blob: a9d609c4f25c9c3902dfbf2a62ee9cee46b9b474 [file] [log] [blame]
// Copyright 2018 The Feed Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.android.libraries.feed.sharedstream.logging;
import com.google.android.libraries.feed.api.host.logging.BasicLoggingApi;
import com.google.android.libraries.feed.api.host.logging.SessionEvent;
import com.google.android.libraries.feed.api.internal.modelprovider.ModelError;
import com.google.android.libraries.feed.api.internal.modelprovider.ModelProvider;
import com.google.android.libraries.feed.api.internal.modelprovider.ModelProviderObserver;
import com.google.android.libraries.feed.common.logging.Logger;
import com.google.android.libraries.feed.common.time.Clock;
import com.google.search.now.feed.client.StreamDataProto.UiContext;
/** Logs the initial event after sessions have been requested by the UI. */
public class UiSessionRequestLogger implements ModelProviderObserver {
private static final String TAG = "UiSessionRequestLogger";
private final Clock clock;
private final BasicLoggingApi basicLoggingApi;
private int sessionCount = 0;
/*@Nullable*/ private SessionRequestState sessionRequestState;
public UiSessionRequestLogger(Clock clock, BasicLoggingApi basicLoggingApi) {
this.clock = clock;
this.basicLoggingApi = basicLoggingApi;
}
/** Should be called whenever the UI requests a new session from the {@link ModelProvider}. */
public void onSessionRequested(ModelProvider modelProvider) {
if (sessionRequestState != null) {
sessionRequestState.modelProvider.unregisterObserver(this);
}
this.sessionRequestState = new SessionRequestState(modelProvider, clock);
modelProvider.registerObserver(this);
}
@Override
public void onSessionStart(UiContext uiContext) {
if (sessionRequestState == null) {
Logger.wtf(TAG, "onSessionStart() called without SessionRequestState.");
return;
}
SessionRequestState localSessionRequestState = sessionRequestState;
basicLoggingApi.onInitialSessionEvent(
SessionEvent.STARTED, localSessionRequestState.getElapsedTime(), ++sessionCount);
localSessionRequestState.getModelProvider().unregisterObserver(this);
sessionRequestState = null;
}
@Override
public void onSessionFinished(UiContext uiContext) {
if (sessionRequestState == null) {
Logger.wtf(TAG, "onSessionFinished() called without SessionRequestState.");
return;
}
SessionRequestState localSessionRequestState = sessionRequestState;
basicLoggingApi.onInitialSessionEvent(
SessionEvent.FINISHED_IMMEDIATELY,
localSessionRequestState.getElapsedTime(),
++sessionCount);
localSessionRequestState.getModelProvider().unregisterObserver(this);
sessionRequestState = null;
}
@Override
public void onError(ModelError modelError) {
if (sessionRequestState == null) {
Logger.wtf(TAG, "onError() called without SessionRequestState.");
return;
}
SessionRequestState localSessionRequestState = sessionRequestState;
basicLoggingApi.onInitialSessionEvent(
SessionEvent.ERROR, localSessionRequestState.getElapsedTime(), ++sessionCount);
localSessionRequestState.getModelProvider().unregisterObserver(this);
sessionRequestState = null;
}
/** Should be called whenever the UI is destroyed, and will log the event if necessary. */
public void onDestroy() {
if (sessionRequestState == null) {
// We don't wtf here as to allow onDestroy() to be called regardless of the internal state.
return;
}
SessionRequestState localSessionRequestState = sessionRequestState;
basicLoggingApi.onInitialSessionEvent(
SessionEvent.USER_ABANDONED, localSessionRequestState.getElapsedTime(), ++sessionCount);
localSessionRequestState.getModelProvider().unregisterObserver(this);
sessionRequestState = null;
}
/** Encapsulates the state of whether a session has been requested and when it was requested. */
private static class SessionRequestState {
private final long sessionRequestTime;
private final ModelProvider modelProvider;
private final Clock clock;
private SessionRequestState(ModelProvider modelProvider, Clock clock) {
this.sessionRequestTime = clock.elapsedRealtime();
this.modelProvider = modelProvider;
this.clock = clock;
}
int getElapsedTime() {
return (int) (clock.elapsedRealtime() - sessionRequestTime);
}
ModelProvider getModelProvider() {
return modelProvider;
}
}
}