blob: 4ac82c7a1e01ea9684a7bd43f7912bcc9691308a [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* 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.android.textclassifier.notification;
import android.app.Notification;
import android.service.notification.NotificationAssistantService;
import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextClassifierEvent;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import java.util.Map;
/** Logs events related to a {@link TextClassifier} result. */
final class SmartSuggestionsLogSession {
private final TextClassificationContext textClassificationContext;
private final String resultId;
private final ImmutableMap<CharSequence, Float> repliesScores;
private final TextClassifier textClassifier;
private boolean isSeenEventLogged;
/**
* Creates a session for logging purpose.
*
* @param resultId the result id from a {@link TextClassifier} result object.
* @param repliesScores a map contains suggested replies and their scores.
* @param textClassifier a text classifier that the log will be sent to. This instance will take
* the ownership of this text classifier, do not further interact with it directly.
* @param textClassificationContext a context where the {@link TextClassifier} API is performed.
*/
SmartSuggestionsLogSession(
String resultId,
Map<CharSequence, Float> repliesScores,
TextClassifier textClassifier,
TextClassificationContext textClassificationContext) {
this.resultId = resultId;
this.repliesScores = ImmutableMap.copyOf(repliesScores);
this.textClassifier = textClassifier;
this.textClassificationContext = textClassificationContext;
}
/**
* Notifies that a notification has been expanded or collapsed.
*
* @param isExpanded true for when a notification is expanded, false for when it is collapsed.
*/
void onNotificationExpansionChanged(boolean isExpanded) {
if (!isExpanded) {
return;
}
// Only report if this is the first time the user sees these suggestions.
if (isSeenEventLogged) {
return;
}
isSeenEventLogged = true;
TextClassifierEvent textClassifierEvent =
createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN, resultId).build();
// TODO(tonymak): If possible, report which replies / actions are actually seen by user.
textClassifier.onTextClassifierEvent(textClassifierEvent);
}
/**
* Notifies that a suggested text reply has been sent.
*
* @param action the action that was just clicked
* @param source the source that provided the reply, e.g. SOURCE_FROM_ASSISTANT
*/
void onActionClicked(Notification.Action action, int source) {
if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
return;
}
String actionType = action.getExtras().getString(SmartSuggestionsHelper.KEY_ACTION_TYPE);
if (actionType == null) {
return;
}
TextClassifierEvent textClassifierEvent =
createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
.setEntityTypes(actionType)
.build();
textClassifier.onTextClassifierEvent(textClassifierEvent);
}
/**
* Notifies that a suggested reply has been sent.
*
* @param reply the reply that is just sent
* @param source the source that provided the reply, e.g. SOURCE_FROM_ASSISTANT
*/
void onSuggestedReplySent(CharSequence reply, int source) {
if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
return;
}
TextClassifierEvent textClassifierEvent =
createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
.setEntityTypes(ConversationAction.TYPE_TEXT_REPLY)
.setScores(repliesScores.getOrDefault(reply, 0f))
.build();
textClassifier.onTextClassifierEvent(textClassifierEvent);
}
/** Notifies that a direct reply has been sent from a notification. */
void onDirectReplied() {
TextClassifierEvent textClassifierEvent =
createTextClassifierEventBuilder(TextClassifierEvent.TYPE_MANUAL_REPLY, resultId).build();
textClassifier.onTextClassifierEvent(textClassifierEvent);
}
/** Notifies that some suggestions have been generated. */
void onSuggestionsGenerated(List<ConversationAction> generatedActions) {
TextClassifierEvent textClassifierEvent =
createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_GENERATED, resultId)
.setEntityTypes(
generatedActions.stream().map(ConversationAction::getType).toArray(String[]::new))
.build();
textClassifier.onTextClassifierEvent(textClassifierEvent);
}
/** Destroys this session. Do not call any method in this class after this is called. */
void destroy() {
textClassifier.destroy();
}
private TextClassifierEvent.ConversationActionsEvent.Builder createTextClassifierEventBuilder(
int eventType, String resultId) {
return new TextClassifierEvent.ConversationActionsEvent.Builder(eventType)
.setEventContext(this.textClassificationContext)
.setResultId(resultId);
}
}