Commit f14e31f8 authored by Tommy Martino's avatar Tommy Martino Committed by Commit Bot

Store last cryptid render in pref

This CL replaces the default hardcoded value for last render timestamp
with one tied to an Android preference.

(see go/probabilistic-cryptid-renderer for design; sorry, Googlers only)

Bug: 1061949
Change-Id: I5a975fbb96ea5bf24c4201f576928a3b0af33f4f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2118810Reviewed-by: default avatarsebsg <sebsg@chromium.org>
Commit-Queue: Tommy Martino <tmartino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#753213}
parent 945ff967
...@@ -7,6 +7,8 @@ package org.chromium.chrome.browser.cryptids; ...@@ -7,6 +7,8 @@ package org.chromium.chrome.browser.cryptids;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
/** /**
* Allows for cryptids to be displayed on the New Tab Page under certain probabilistic conditions. * Allows for cryptids to be displayed on the New Tab Page under certain probabilistic conditions.
...@@ -25,15 +27,28 @@ public class ProbabilisticCryptidRenderer { ...@@ -25,15 +27,28 @@ public class ProbabilisticCryptidRenderer {
*/ */
public boolean shouldUseCryptidRendering() { public boolean shouldUseCryptidRendering() {
// TODO: This should be disabled unless enabled by variations. // TODO: This should be disabled unless enabled by variations.
return getRandom() < calculateProbability(getLastRenderTimestampMillis(), return getRandom() < calculateProbability();
System.currentTimeMillis(), getRenderingMoratoriumLengthMillis(), }
getRampUpLengthMillis(), getMaxProbability());
/**
* Records the current timestamp as the last render time in the appropriate pref.
*/
public void recordRenderEvent() {
recordRenderEvent(System.currentTimeMillis());
} }
// Protected for testing // Protected for testing
protected long getLastRenderTimestampMillis() { protected long getLastRenderTimestampMillis() {
// TODO: Store last instance timestamp in a pref and return it. long lastRenderTimestamp = SharedPreferencesManager.getInstance().readLong(
return 0; ChromePreferenceKeys.CRYPTID_LAST_RENDER_TIMESTAMP,
/* defaultValue = */ 0);
if (lastRenderTimestamp == 0) {
// If no render has ever been recorded, set the timestamp such that the current time is
// the end of the moratorium period.
lastRenderTimestamp = System.currentTimeMillis() - getRenderingMoratoriumLengthMillis();
recordRenderEvent(lastRenderTimestamp);
}
return lastRenderTimestamp;
} }
protected long getRenderingMoratoriumLengthMillis() { protected long getRenderingMoratoriumLengthMillis() {
...@@ -55,6 +70,12 @@ public class ProbabilisticCryptidRenderer { ...@@ -55,6 +70,12 @@ public class ProbabilisticCryptidRenderer {
return (int) (Math.random() * DENOMINATOR); return (int) (Math.random() * DENOMINATOR);
} }
@VisibleForTesting
void recordRenderEvent(long timestamp) {
SharedPreferencesManager.getInstance().writeLong(
ChromePreferenceKeys.CRYPTID_LAST_RENDER_TIMESTAMP, timestamp);
}
/** /**
* Calculates the probability of display at a particular moment, based on various timestamp/ * Calculates the probability of display at a particular moment, based on various timestamp/
* length factors. Roughly speaking, the probability starts at 0 after a rendering event, * length factors. Roughly speaking, the probability starts at 0 after a rendering event,
...@@ -90,4 +111,13 @@ public class ProbabilisticCryptidRenderer { ...@@ -90,4 +111,13 @@ public class ProbabilisticCryptidRenderer {
float fractionOfRampUp = (float) (currentTimestamp - windowStartTimestamp) / rampUpLength; float fractionOfRampUp = (float) (currentTimestamp - windowStartTimestamp) / rampUpLength;
return (int) Math.round(fractionOfRampUp * maxProbability); return (int) Math.round(fractionOfRampUp * maxProbability);
} }
/**
* Convenience method calling the static method above using the appropriate values.
*/
@VisibleForTesting
int calculateProbability() {
return calculateProbability(getLastRenderTimestampMillis(), System.currentTimeMillis(),
getRenderingMoratoriumLengthMillis(), getRampUpLengthMillis(), getMaxProbability());
}
} }
...@@ -68,10 +68,40 @@ public class ProbabilisticCryptidRendererUnitTest { ...@@ -68,10 +68,40 @@ public class ProbabilisticCryptidRendererUnitTest {
Assert.assertEquals(MAX_PROBABILITY, probPostRampup); Assert.assertEquals(MAX_PROBABILITY, probPostRampup);
} }
@Test
@SmallTest
public void testPrefStorageDefaultValue() {
ProbabilisticCryptidRenderer render = new ProbabilisticCryptidRenderer();
long defaultRenderTimestamp = render.getLastRenderTimestampMillis();
long howLongSinceDefaultTime = System.currentTimeMillis() - defaultRenderTimestamp;
// We expect |howLongSinceDefaultTime| to be one moratorium length, because the default
// case should be rigged up to start users at the end of the moratorium.
long delta = howLongSinceDefaultTime - render.getRenderingMoratoriumLengthMillis();
Assert.assertTrue(String.format("Delta %d was larger than 10 seconds (10000)", delta),
delta < 10000); // Allow a 10 second grace period in case the test is slow.
}
@Test
@SmallTest
public void testPrefStorage() {
ProbabilisticCryptidRenderer render = new ProbabilisticCryptidRenderer();
// Set the last render event to be a crazy long time ago, ensuring max probability.
render.recordRenderEvent(1);
Assert.assertEquals(render.getMaxProbability(), render.calculateProbability());
// Immediately after an event, the probability should have dropped to 0.
render.recordRenderEvent();
Assert.assertEquals(0, render.calculateProbability());
}
// Aggregator tests: these tests run |NUM_RUNS| invocations of shouldUseCryptidRendering to // Aggregator tests: these tests run |NUM_RUNS| invocations of shouldUseCryptidRendering to
// verify that the number of trues returned is consistent with our assumptions about how often // verify that the number of trues returned is consistent with our assumptions about how often
// this should happen, within |TOLERANCE|. // this should happen, within |TOLERANCE|.
/**
* This fake bypasses any calls to pref logic, and also uses a seeded RNG.
*/
private static class FakeProbabilisticCrpytidRenderer extends ProbabilisticCryptidRenderer { private static class FakeProbabilisticCrpytidRenderer extends ProbabilisticCryptidRenderer {
public FakeProbabilisticCrpytidRenderer(long lastRenderDeltaFromNow) { public FakeProbabilisticCrpytidRenderer(long lastRenderDeltaFromNow) {
mLastRenderTimestamp = System.currentTimeMillis() + lastRenderDeltaFromNow; mLastRenderTimestamp = System.currentTimeMillis() + lastRenderDeltaFromNow;
......
...@@ -190,6 +190,8 @@ public final class ChromePreferenceKeys { ...@@ -190,6 +190,8 @@ public final class ChromePreferenceKeys {
public static final String CRASH_UPLOAD_SUCCESS_OTHER = "other_crash_success_upload"; public static final String CRASH_UPLOAD_SUCCESS_OTHER = "other_crash_success_upload";
public static final String CRASH_UPLOAD_SUCCESS_RENDERER = "renderer_crash_success_upload"; public static final String CRASH_UPLOAD_SUCCESS_RENDERER = "renderer_crash_success_upload";
public static final String CRYPTID_LAST_RENDER_TIMESTAMP = "Chrome.Cryptid.LastRenderTimestamp";
public static final KeyPrefix CUSTOM_TABS_DEX_LAST_UPDATE_TIME_PREF_PREFIX = public static final KeyPrefix CUSTOM_TABS_DEX_LAST_UPDATE_TIME_PREF_PREFIX =
new KeyPrefix("pref_local_custom_tabs_module_dex_last_update_time_*"); new KeyPrefix("pref_local_custom_tabs_module_dex_last_update_time_*");
public static final String CUSTOM_TABS_LAST_URL = "pref_last_custom_tab_url"; public static final String CUSTOM_TABS_LAST_URL = "pref_last_custom_tab_url";
...@@ -674,6 +676,7 @@ public final class ChromePreferenceKeys { ...@@ -674,6 +676,7 @@ public final class ChromePreferenceKeys {
CONTEXT_MENU_OPEN_IMAGE_IN_EPHEMERAL_TAB_CLICKED, CONTEXT_MENU_OPEN_IMAGE_IN_EPHEMERAL_TAB_CLICKED,
CONTEXT_MENU_OPEN_IN_EPHEMERAL_TAB_CLICKED, CONTEXT_MENU_OPEN_IN_EPHEMERAL_TAB_CLICKED,
CONTEXT_MENU_SEARCH_WITH_GOOGLE_LENS_CLICKED, CONTEXT_MENU_SEARCH_WITH_GOOGLE_LENS_CLICKED,
CRYPTID_LAST_RENDER_TIMESTAMP,
EXPLORE_OFFLINE_CONTENT_AVAILABILITY_STATUS, EXPLORE_OFFLINE_CONTENT_AVAILABILITY_STATUS,
FLAGS_CACHED.pattern(), FLAGS_CACHED.pattern(),
FLAGS_CACHED_DUET_TABSTRIP_INTEGRATION_ANDROID_ENABLED, FLAGS_CACHED_DUET_TABSTRIP_INTEGRATION_ANDROID_ENABLED,
......
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