Commit 2971d024 authored by Michael Thiessen's avatar Michael Thiessen Committed by Chromium LUCI CQ

Implement Intent-less LaunchCauseMetrics

Implements LaunchCauseMetrics for launch types that don't involve
intents - Recents, Back, and Power button.

It's not possible to distinguish between Back and Recents in all cases.
However, when the Activity is killed in the background, and then
restored from Recents, Android adds a flag to the intent we can look
at. Also, when Chrome does not receive a UserLeaveHint when going to
the background, we can be sure that the Back button will not return
the user to that Chrome Activity.

We can detect resume by power button by looking at whether the
screen is off when Chrome is paused. (If Chrome happens to be killed
while the screen is off, the launcher is shown on screen on)

These changes range from extremely difficult to impossible to
integration test as you would need control of multiple apps for some,
and the ability to manipulate the Recents screen in others. I've opted
for unit testing here, and have manually tested every situation I could
think of in both CTA and CCT.

Bug: 1163961
Change-Id: I86a00dcf7333a22da724a1b26be2c5bcf5236cc3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2625909
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843898}
parent f85849d7
...@@ -1684,7 +1684,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent ...@@ -1684,7 +1684,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
@Override @Override
protected LaunchCauseMetrics createLaunchCauseMetrics() { protected LaunchCauseMetrics createLaunchCauseMetrics() {
return new TabbedActivityLaunchCauseMetrics(); return new TabbedActivityLaunchCauseMetrics(this);
} }
@Override @Override
......
...@@ -466,9 +466,14 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -466,9 +466,14 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
super.performPostInflationStartup(); super.performPostInflationStartup();
Intent intent = getIntent(); Intent intent = getIntent();
if (intent != null && getSavedInstanceState() == null) { if (getSavedInstanceState() == null) {
VrModuleProvider.getDelegate().maybeHandleVrIntentPreNative(this, intent); VrModuleProvider.getDelegate().maybeHandleVrIntentPreNative(this, intent);
} }
if (0 != (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) {
getLaunchCauseMetrics().onLaunchFromRecents();
} else {
getLaunchCauseMetrics().onReceivedIntent();
}
BottomContainer bottomContainer = (BottomContainer) findViewById(R.id.bottom_container); BottomContainer bottomContainer = (BottomContainer) findViewById(R.id.bottom_container);
...@@ -979,6 +984,8 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -979,6 +984,8 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
protected void onUserLeaveHint() { protected void onUserLeaveHint() {
super.onUserLeaveHint(); super.onUserLeaveHint();
getLaunchCauseMetrics().onUserLeaveHint();
// Can be in finishing state. No need to attempt PIP. // Can be in finishing state. No need to attempt PIP.
if (isActivityFinishingOrDestroyed()) return; if (isActivityFinishingOrDestroyed()) return;
...@@ -1035,6 +1042,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> ...@@ -1035,6 +1042,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
} }
super.onNewIntentWithNative(intent); super.onNewIntentWithNative(intent);
getLaunchCauseMetrics().onReceivedIntent();
if (mIntentHandler.shouldIgnoreIntent(intent, /*startedActivity=*/false)) return; if (mIntentHandler.shouldIgnoreIntent(intent, /*startedActivity=*/false)) return;
// We send this intent so that we can enter WebVr presentation mode if needed. This // We send this intent so that we can enter WebVr presentation mode if needed. This
......
...@@ -14,6 +14,7 @@ public class CustomTabLaunchCauseMetrics extends LaunchCauseMetrics { ...@@ -14,6 +14,7 @@ public class CustomTabLaunchCauseMetrics extends LaunchCauseMetrics {
private final CustomTabActivity mActivity; private final CustomTabActivity mActivity;
public CustomTabLaunchCauseMetrics(CustomTabActivity activity) { public CustomTabLaunchCauseMetrics(CustomTabActivity activity) {
super(activity);
mActivity = activity; mActivity = activity;
} }
......
...@@ -4,14 +4,21 @@ ...@@ -4,14 +4,21 @@
package org.chromium.chrome.browser.metrics; package org.chromium.chrome.browser.metrics;
import android.app.Activity;
import android.view.Display;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationState; import org.chromium.base.ApplicationState;
import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CheckDiscard;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.ui.display.DisplayAndroidManager;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
...@@ -19,7 +26,10 @@ import java.lang.annotation.RetentionPolicy; ...@@ -19,7 +26,10 @@ import java.lang.annotation.RetentionPolicy;
/** /**
* Computes and records metrics for what caused Chrome to be launched. * Computes and records metrics for what caused Chrome to be launched.
*/ */
public abstract class LaunchCauseMetrics { public abstract class LaunchCauseMetrics implements ApplicationStatus.ApplicationStateListener {
private static final boolean DEBUG = false;
private static final String TAG = "LaunchCauseMetrics";
// Static to avoid recording launch metrics when transitioning between Activities without // Static to avoid recording launch metrics when transitioning between Activities without
// Chrome leaving the foreground. // Chrome leaving the foreground.
private static boolean sRecordedLaunchCause; private static boolean sRecordedLaunchCause;
...@@ -27,31 +37,71 @@ public abstract class LaunchCauseMetrics { ...@@ -27,31 +37,71 @@ public abstract class LaunchCauseMetrics {
@VisibleForTesting @VisibleForTesting
public static final String LAUNCH_CAUSE_HISTOGRAM = "MobileStartup.Experimental.LaunchCause"; public static final String LAUNCH_CAUSE_HISTOGRAM = "MobileStartup.Experimental.LaunchCause";
private PerLaunchState mPerLaunchState = new PerLaunchState();
private BetweenLaunchState mBetweenLaunchState = new BetweenLaunchState();
// State pertaining to the current launch, reset when Chrome is backgrounded.
private static class PerLaunchState {
boolean mReceivedIntent;
boolean mLaunchedFromRecents;
}
// State that persists through Chrome being backgrounded (but not destroyed), reset after
// computing LaunchCause.
private static class BetweenLaunchState {
boolean mReceivedLeaveHint;
boolean mScreenOffWhenPaused;
}
// 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}) @IntDef({LaunchCause.OTHER, LaunchCause.CUSTOM_TAB, LaunchCause.TWA, LaunchCause.RECENTS,
LaunchCause.RECENTS_OR_BACK, LaunchCause.FOREGROUND_WHEN_LOCKED})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface LaunchCause { public @interface LaunchCause {
int OTHER = 0; int OTHER = 0;
int CUSTOM_TAB = 1; int CUSTOM_TAB = 1;
int TWA = 2; int TWA = 2;
int RECENTS = 3;
int RECENTS_OR_BACK = 4;
int FOREGROUND_WHEN_LOCKED = 5;
int NUM_ENTRIES = 3; int NUM_ENTRIES = 6;
}
/**
* @param activity The Activity context to compute LaunchCause for, used for getting the correct
* Display, etc.
*/
public LaunchCauseMetrics(final Activity activity) {
ApplicationStatus.registerApplicationStateListener(this);
ApplicationStatus.registerStateListenerForActivity((a, newState) -> {
if (newState == ActivityState.PAUSED) {
mBetweenLaunchState.mScreenOffWhenPaused = isDisplayOff(a);
}
if (newState == ActivityState.DESTROYED) {
ApplicationStatus.unregisterApplicationStateListener(this);
}
}, activity);
} }
public LaunchCauseMetrics() { @Override
ApplicationStatus.registerApplicationStateListener(newState -> { public void onApplicationStateChange(@ApplicationState int newState) {
if (newState == ApplicationState.HAS_STOPPED_ACTIVITIES) { if (newState == ApplicationState.HAS_STOPPED_ACTIVITIES) {
reset(); resetPerLaunchState();
} }
});
} }
/** /**
* Resets state used to compute launch cause when Chrome is backgrounded. * Resets state used to compute launch cause when Chrome is backgrounded.
*/ */
@CallSuper @CallSuper
protected void reset() { protected void resetPerLaunchState() {
sRecordedLaunchCause = false; sRecordedLaunchCause = false;
mPerLaunchState = new PerLaunchState();
}
private void resetBetweenLaunchState() {
mBetweenLaunchState = new BetweenLaunchState();
} }
/** /**
...@@ -66,18 +116,107 @@ public abstract class LaunchCauseMetrics { ...@@ -66,18 +116,107 @@ public abstract class LaunchCauseMetrics {
* Records UMA metrics for what caused Chrome to launch. * Records UMA metrics for what caused Chrome to launch.
*/ */
public void recordLaunchCause() { public void recordLaunchCause() {
if (sRecordedLaunchCause) return; if (!sRecordedLaunchCause) {
sRecordedLaunchCause = true; sRecordedLaunchCause = true;
@LaunchCause @LaunchCause
int cause = computeLaunchCause(); int cause = LaunchCause.OTHER;
if (mPerLaunchState.mReceivedIntent) {
cause = computeLaunchCause();
} else {
cause = computeNonIntentLaunchCause();
}
if (DEBUG) logLaunchCause(cause);
RecordHistogram.recordEnumeratedHistogram( RecordHistogram.recordEnumeratedHistogram(
LAUNCH_CAUSE_HISTOGRAM, cause, LaunchCause.NUM_ENTRIES); LAUNCH_CAUSE_HISTOGRAM, cause, LaunchCause.NUM_ENTRIES);
} }
resetBetweenLaunchState();
}
// If Chrome wasn't launched via an intent, it was either launched from Recents, Back button,
// or through Screen ON.
//
// For posterity: If you're testing this by switching between the Android Settings app, and
// Chrome, with Chrome set as the debug app, it won't work because Android clears app state and
// resuming through Recents will instead send a MAIN intent.
private @LaunchCause int computeNonIntentLaunchCause() {
if (mPerLaunchState.mLaunchedFromRecents) {
return LaunchCause.RECENTS;
}
if (mBetweenLaunchState.mScreenOffWhenPaused) {
// It's possible we got here through Recents, if the user tapped a non-Chrome
// notification after locking their screen with Chrome in the foreground, then
// returned to Chrome through Recents, and there's no reliable way to detect this.
// The most likely explanation for arriving here is Chrome was resumed through
// unlocking their phone.
return LaunchCause.FOREGROUND_WHEN_LOCKED;
}
// If we don't get a UserLeaveHint when leaving Chrome, then back can't return us to Chrome.
if (!mBetweenLaunchState.mReceivedLeaveHint) {
return LaunchCause.RECENTS;
}
// There's no way to distinguish between Recents and Back when we've received a
// UserLeaveHint.
return LaunchCause.RECENTS_OR_BACK;
}
/**
* Called when Chrome receives a new Intent (including both when Chrome is launched, or
* resumed, through an intent). The Intent may be any Intent, including MAIN, VIEW, and
* arbitrary explicit intents targeting Chrome.
*/
public void onReceivedIntent() {
mPerLaunchState.mReceivedIntent = true;
}
/** See {@link Activity#onUserLeaveHint()} */
public void onUserLeaveHint() {
mBetweenLaunchState.mReceivedLeaveHint = true;
}
/** Called when the Activity is launched from Android Recets (aka App Overview) */
public void onLaunchFromRecents() {
mPerLaunchState.mLaunchedFromRecents = true;
}
@VisibleForTesting
protected boolean isDisplayOff(Activity activity) {
final Display display = DisplayAndroidManager.getDefaultDisplayForContext(activity);
return display.getState() != Display.STATE_ON;
}
@VisibleForTesting @VisibleForTesting
public static void resetForTests() { public static void resetForTests() {
ThreadUtils.assertOnUiThread(); ThreadUtils.assertOnUiThread();
sRecordedLaunchCause = false; sRecordedLaunchCause = false;
} }
@CheckDiscard("")
private static void logLaunchCause(@LaunchCause int cause) {
String launchCause = "";
switch (cause) {
case LaunchCause.OTHER:
launchCause = "OTHER";
break;
case LaunchCause.CUSTOM_TAB:
launchCause = "CUSTOM_TAB";
break;
case LaunchCause.TWA:
launchCause = "TWA";
break;
case LaunchCause.RECENTS:
launchCause = "RECENTS";
break;
case LaunchCause.RECENTS_OR_BACK:
launchCause = "RECENTS_OR_BACK";
break;
case LaunchCause.FOREGROUND_WHEN_LOCKED:
launchCause = "FOREGROUND_WHEN_LOCKED";
break;
}
Log.d(TAG, "Launch Cause: " + launchCause);
}
} }
...@@ -4,10 +4,16 @@ ...@@ -4,10 +4,16 @@
package org.chromium.chrome.browser.metrics; package org.chromium.chrome.browser.metrics;
import android.app.Activity;
/** /**
* LaunchCauseMetrics for ChromeTabbedActivity. * LaunchCauseMetrics for ChromeTabbedActivity.
*/ */
public class TabbedActivityLaunchCauseMetrics extends LaunchCauseMetrics { public class TabbedActivityLaunchCauseMetrics extends LaunchCauseMetrics {
public TabbedActivityLaunchCauseMetrics(Activity activity) {
super(activity);
}
@Override @Override
public @LaunchCause int computeLaunchCause() { public @LaunchCause int computeLaunchCause() {
// TODO(https://crbug.com/1163961): Implement ChromeTabbedActivity launch cause metrics. // TODO(https://crbug.com/1163961): Implement ChromeTabbedActivity launch cause metrics.
......
...@@ -91,6 +91,6 @@ public class WebappActivity extends BaseCustomTabActivity { ...@@ -91,6 +91,6 @@ public class WebappActivity extends BaseCustomTabActivity {
@Override @Override
protected LaunchCauseMetrics createLaunchCauseMetrics() { protected LaunchCauseMetrics createLaunchCauseMetrics() {
return new WebappLaunchCauseMetrics(); return new WebappLaunchCauseMetrics(this);
} }
} }
...@@ -4,12 +4,18 @@ ...@@ -4,12 +4,18 @@
package org.chromium.chrome.browser.webapps; package org.chromium.chrome.browser.webapps;
import android.app.Activity;
import org.chromium.chrome.browser.metrics.LaunchCauseMetrics; import org.chromium.chrome.browser.metrics.LaunchCauseMetrics;
/** /**
* LaunchCauseMetrics for WebappActivity. * LaunchCauseMetrics for WebappActivity.
*/ */
public class WebappLaunchCauseMetrics extends LaunchCauseMetrics { public class WebappLaunchCauseMetrics extends LaunchCauseMetrics {
public WebappLaunchCauseMetrics(Activity activity) {
super(activity);
}
@Override @Override
public @LaunchCause int computeLaunchCause() { public @LaunchCause int computeLaunchCause() {
// TODO(https://crbug.com/1163961): Implement Webapp launch cause metrics. // TODO(https://crbug.com/1163961): Implement Webapp launch cause metrics.
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.customtabs; package org.chromium.chrome.browser.customtabs;
import android.app.Activity;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import org.junit.After; import org.junit.After;
...@@ -12,6 +14,8 @@ import org.junit.Before; ...@@ -12,6 +14,8 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.BaseJUnit4ClassRunner;
...@@ -30,11 +34,15 @@ public final class CustomTabLaunchCauseMetricsTest { ...@@ -30,11 +34,15 @@ public final class CustomTabLaunchCauseMetricsTest {
@Before @Before
public void setUp() { public void setUp() {
NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
if (!ApplicationStatus.isInitialized()) {
ApplicationStatus.initialize(BaseJUnit4ClassRunner.getApplication());
}
} }
@After @After
public void tearDown() { public void tearDown() {
ThreadUtils.runOnUiThreadBlocking(() -> LaunchCauseMetrics.resetForTests()); ThreadUtils.runOnUiThreadBlocking(() -> LaunchCauseMetrics.resetForTests());
ApplicationStatus.destroyForJUnitTests();
} }
private static int histogramCountForValue(int value) { private static int histogramCountForValue(int value) {
...@@ -42,25 +50,32 @@ public final class CustomTabLaunchCauseMetricsTest { ...@@ -42,25 +50,32 @@ public final class CustomTabLaunchCauseMetricsTest {
LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM, value); LaunchCauseMetrics.LAUNCH_CAUSE_HISTOGRAM, value);
} }
// CustomTabActivity can't be mocked, because Mockito can't handle @ApiLevel annotations, and so private CustomTabLaunchCauseMetrics makeLaunchCauseMetrics(boolean twa) {
// can't mock classes that use them because classes can't be found on older API levels. // CustomTabActivity can't be mocked, because Mockito can't handle @ApiLevel annotations,
private CustomTabActivity makeActivity(boolean twa) { // and so can't mock classes that use them because classes can't be found on older API
return new CustomTabActivity() { // levels.
CustomTabActivity activity = new CustomTabActivity() {
@Override @Override
public int getActivityType() { public int getActivityType() {
return twa ? ActivityType.TRUSTED_WEB_ACTIVITY : ActivityType.CUSTOM_TAB; return twa ? ActivityType.TRUSTED_WEB_ACTIVITY : ActivityType.CUSTOM_TAB;
} }
}; };
ApplicationStatus.onStateChangeForTesting(activity, ActivityState.CREATED);
return new CustomTabLaunchCauseMetrics(activity) {
@Override
protected boolean isDisplayOff(Activity context) {
return false;
}
};
} }
@Test @Test
@SmallTest @SmallTest
@UiThreadTest @UiThreadTest
public void testCCTLaunch() throws Throwable { public void testCCTLaunch() throws Throwable {
CustomTabActivity activity = makeActivity(false);
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.CUSTOM_TAB); int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.CUSTOM_TAB);
CustomTabLaunchCauseMetrics metrics = makeLaunchCauseMetrics(false);
CustomTabLaunchCauseMetrics metrics = new CustomTabLaunchCauseMetrics(activity); metrics.onReceivedIntent();
metrics.recordLaunchCause(); metrics.recordLaunchCause();
count++; count++;
Assert.assertEquals( Assert.assertEquals(
...@@ -71,12 +86,22 @@ public final class CustomTabLaunchCauseMetricsTest { ...@@ -71,12 +86,22 @@ public final class CustomTabLaunchCauseMetricsTest {
@SmallTest @SmallTest
@UiThreadTest @UiThreadTest
public void testTWALaunch() throws Throwable { public void testTWALaunch() throws Throwable {
CustomTabActivity activity = makeActivity(true);
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.TWA); int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.TWA);
CustomTabLaunchCauseMetrics metrics = makeLaunchCauseMetrics(true);
CustomTabLaunchCauseMetrics metrics = new CustomTabLaunchCauseMetrics(activity); metrics.onReceivedIntent();
metrics.recordLaunchCause(); metrics.recordLaunchCause();
count++; count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.TWA)); Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.TWA));
} }
@Test
@SmallTest
@UiThreadTest
public void testNoIntent() throws Throwable {
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS);
CustomTabLaunchCauseMetrics metrics = makeLaunchCauseMetrics(true);
metrics.recordLaunchCause();
count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS));
}
} }
...@@ -42,6 +42,12 @@ public final class LaunchCauseMetricsTest { ...@@ -42,6 +42,12 @@ public final class LaunchCauseMetricsTest {
@Before @Before
public void setUp() { public void setUp() {
ThreadUtils.runOnUiThreadBlocking(() -> {
if (!ApplicationStatus.isInitialized()) {
ApplicationStatus.initialize(BaseJUnit4ClassRunner.getApplication());
}
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED);
});
NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
} }
...@@ -57,10 +63,25 @@ public final class LaunchCauseMetricsTest { ...@@ -57,10 +63,25 @@ public final class LaunchCauseMetricsTest {
} }
private static class TestLaunchCauseMetrics extends LaunchCauseMetrics { private static class TestLaunchCauseMetrics extends LaunchCauseMetrics {
private boolean mDisplayOff;
public TestLaunchCauseMetrics(Activity activity) {
super(activity);
}
@Override @Override
protected @LaunchCause int computeLaunchCause() { protected @LaunchCause int computeLaunchCause() {
return LaunchCause.OTHER; return LaunchCause.OTHER;
} }
@Override
protected boolean isDisplayOff(Activity activity) {
return mDisplayOff;
}
public void setDisplayOff(boolean off) {
mDisplayOff = off;
}
} }
@Test @Test
...@@ -68,12 +89,12 @@ public final class LaunchCauseMetricsTest { ...@@ -68,12 +89,12 @@ public final class LaunchCauseMetricsTest {
@UiThreadTest @UiThreadTest
public void testRecordsOncePerLaunch() throws Throwable { public void testRecordsOncePerLaunch() throws Throwable {
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER); int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER);
TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(); TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(mActivity);
metrics.onReceivedIntent();
metrics.recordLaunchCause(); metrics.recordLaunchCause();
count++; count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER)); Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER));
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
metrics.recordLaunchCause(); metrics.recordLaunchCause();
...@@ -84,6 +105,7 @@ public final class LaunchCauseMetricsTest { ...@@ -84,6 +105,7 @@ public final class LaunchCauseMetricsTest {
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER)); Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER));
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED); ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED);
metrics.onReceivedIntent();
metrics.recordLaunchCause(); metrics.recordLaunchCause();
count++; count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER)); Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER));
...@@ -94,11 +116,83 @@ public final class LaunchCauseMetricsTest { ...@@ -94,11 +116,83 @@ public final class LaunchCauseMetricsTest {
@UiThreadTest @UiThreadTest
public void testRecordsOnceWithMultipleInstances() throws Throwable { public void testRecordsOnceWithMultipleInstances() throws Throwable {
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER); int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER);
TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(); TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(mActivity);
metrics.onReceivedIntent();
metrics.recordLaunchCause(); metrics.recordLaunchCause();
count++; count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER)); Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER));
new TestLaunchCauseMetrics().recordLaunchCause(); new TestLaunchCauseMetrics(mActivity).recordLaunchCause();
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER)); Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.OTHER));
} }
@Test
@SmallTest
@UiThreadTest
public void testLaunchedFromRecents() throws Throwable {
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS);
TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(mActivity);
metrics.onLaunchFromRecents();
metrics.recordLaunchCause();
count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS));
LaunchCauseMetrics.resetForTests();
metrics.onLaunchFromRecents();
metrics.onUserLeaveHint();
metrics.recordLaunchCause();
count++;
Assert.assertEquals(count, histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS));
}
@Test
@SmallTest
@UiThreadTest
public void testResumedFromRecents() throws Throwable {
int recentsCount = histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS);
int backCount = histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS_OR_BACK);
TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(mActivity);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
metrics.recordLaunchCause();
recentsCount++;
Assert.assertEquals(
recentsCount, histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS));
metrics.onUserLeaveHint();
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED);
metrics.recordLaunchCause();
backCount++;
Assert.assertEquals(
backCount, histogramCountForValue(LaunchCauseMetrics.LaunchCause.RECENTS_OR_BACK));
}
@Test
@SmallTest
@UiThreadTest
public void testResumedFromScreenOn() throws Throwable {
int count = histogramCountForValue(LaunchCauseMetrics.LaunchCause.FOREGROUND_WHEN_LOCKED);
TestLaunchCauseMetrics metrics = new TestLaunchCauseMetrics(mActivity);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
metrics.setDisplayOff(true);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
metrics.recordLaunchCause();
count++;
Assert.assertEquals(count,
histogramCountForValue(LaunchCauseMetrics.LaunchCause.FOREGROUND_WHEN_LOCKED));
metrics.setDisplayOff(false);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED);
ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED);
metrics.recordLaunchCause();
Assert.assertEquals(count,
histogramCountForValue(LaunchCauseMetrics.LaunchCause.FOREGROUND_WHEN_LOCKED));
}
} }
...@@ -41247,6 +41247,9 @@ Called by update_gpu_driver_bug_workaround_entries.py.--> ...@@ -41247,6 +41247,9 @@ Called by update_gpu_driver_bug_workaround_entries.py.-->
<int value="0" label="Other"/> <int value="0" label="Other"/>
<int value="1" label="Chrome Custom Tab"/> <int value="1" label="Chrome Custom Tab"/>
<int value="2" label="Trusted Web Activity"/> <int value="2" label="Trusted Web Activity"/>
<int value="3" label="Recents (aka App Overview)"/>
<int value="4" label="Recents or Back"/>
<int value="5" label="Foreground when Locked (Power Button)"/>
</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