blob: 1f14f19b6472d1886085d3d4a5239645b80ee357 [file] [log] [blame]
// Copyright 2019 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.contextualsearch;
import androidx.annotation.Nullable;
import org.chromium.chrome.browser.contextualsearch.ContextualSearchInteractionRecorder.Feature;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import java.util.Map;
/**
* Implements persisting an interaction event and outcomes to local storage.
* Call {@link #persistInteractions} to persist a pair of values given ID and outcomes.
* Call the static getAndResetPersistedInteractionOutcomes to get the previous persisted pair
* and reset the storage (so we can't get the same value twice).
* A pair with an Event ID of {@link ContextualSearchInteractionPersister#NO_EVENT_ID} represents no
* persisted value.
*/
class ContextualSearchInteractionPersisterImpl implements ContextualSearchInteractionPersister {
private static final @Nullable Integer getOutcomeBitMask(@Feature int feature) {
switch (feature) {
case Feature.OUTCOME_WAS_PANEL_OPENED:
return 1 << 0;
case Feature.OUTCOME_WAS_QUICK_ACTION_CLICKED:
return 1 << 1;
case Feature.OUTCOME_WAS_QUICK_ANSWER_SEEN:
return 1 << 2;
case Feature.OUTCOME_WAS_CARDS_DATA_SHOWN:
return 1 << 3;
}
return null;
}
@Override
public PersistedInteraction getAndClearPersistedInteraction() {
long previousEventId = readEventIdFromPersistantStorage();
if (previousEventId == NO_EVENT_ID) return new PersistedInteractionImpl();
int encodedInteractionOutcomes = readOutcomesFromPersistantStorage();
long timestamp = readTimestampFromPersistantStorage();
assert timestamp != 0;
ContextualSearchUma.logOutcomesTimestamp(System.currentTimeMillis() - timestamp);
writeEventIDToPersistantStorage(NO_EVENT_ID);
writeOutcomesToPersistantStorage(NO_INTERACTION);
writeTimestampToPersistantStorage(0);
return new PersistedInteractionImpl(previousEventId, encodedInteractionOutcomes, timestamp);
}
@Override
public void persistInteractions(long eventId, Map<Integer, Object> outcomesMap) {
assert eventId != NO_EVENT_ID;
assert outcomesMap != null;
int encodedInteractionResults = NO_INTERACTION;
// Only the outcomes will be present, since we logged inference features at
// inference time.
for (Map.Entry<Integer, Object> entry : outcomesMap.entrySet()) {
// Bit-wise encode into an int with all the boolean outcomes.
if ((boolean) entry.getValue()) {
encodedInteractionResults |= getOutcomeBitMask(entry.getKey());
}
}
writeOutcomesToPersistantStorage(encodedInteractionResults);
writeEventIDToPersistantStorage(eventId);
writeTimestampToPersistantStorage(System.currentTimeMillis());
}
/** @param eventId An event ID to write to local storage. */
private void writeEventIDToPersistantStorage(long eventId) {
SharedPreferencesManager.getInstance().writeLong(
ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID, eventId);
}
/** @return The event ID from local storage. */
private long readEventIdFromPersistantStorage() {
return SharedPreferencesManager.getInstance().readLong(
ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID, NO_EVENT_ID);
}
/** @param bitEncodedValue An encoded outcome to write to local storage. */
private void writeOutcomesToPersistantStorage(int bitEncodedValue) {
SharedPreferencesManager.getInstance().writeInt(
ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES,
bitEncodedValue);
}
/** @return The encoded outcome from local storage. */
private int readOutcomesFromPersistantStorage() {
return SharedPreferencesManager.getInstance().readInt(
ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES);
}
/** Writes the current time stamp to local storage. */
private void writeTimestampToPersistantStorage(long timestamp) {
SharedPreferencesManager.getInstance().writeLong(
ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP, timestamp);
}
/** @return The time stamp when we wrote the outcome to local storage. */
private long readTimestampFromPersistantStorage() {
return SharedPreferencesManager.getInstance().readLong(
ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP, 0);
}
/**
* Provides a read-only encapsulation of a persisted user interaction and the ID from the
* server used to identify it, and a timestamp.
*/
static class PersistedInteractionImpl implements PersistedInteraction {
/**
* The identifier from the server for this interaction outcome, or
* {@link ContextualSearchInteractionPersister#NO_EVENT_ID} if none.
*/
private final long mEventId;
/**
* The encoded results of the user interaction, often
* {@link ContextualSearchInteractionPersister#NO_INTERACTION} meaning no interaction.
*/
private final int mEncodedUserInteractions;
/**
* The time stamp of the user interaction, in milliseconds, or 0 if not known.
*/
private final long mTimestampMs;
/** Creates an empty interaction. */
PersistedInteractionImpl() {
this(NO_EVENT_ID, NO_INTERACTION, 0);
}
/** Creates an interaction with the given EventID and encoded user interactions. */
PersistedInteractionImpl(long eventId, int encodedUserInteractions, long timestamp) {
mEventId = eventId;
mEncodedUserInteractions = encodedUserInteractions;
mTimestampMs = timestamp;
}
@Override
public long getEventId() {
return mEventId;
}
@Override
public int getEncodedUserInteractions() {
return mEncodedUserInteractions;
}
@Override
public long getTimestampMs() {
return mTimestampMs;
}
}
}