| /* |
| * 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 android.view.textclassifier; |
| |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SCORE; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SESSION_ID; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_TYPE; |
| import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_VERSION; |
| |
| import android.metrics.LogMaker; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.logging.MetricsLogger; |
| import com.android.internal.logging.nano.MetricsProto.MetricsEvent; |
| import java.util.Objects; |
| |
| |
| /** |
| * Log {@link TextClassifierEvent} by using Tron, only support language detection and |
| * conversation actions. |
| * |
| * @hide |
| */ |
| public final class TextClassifierEventTronLogger { |
| |
| private static final String TAG = "TCEventTronLogger"; |
| |
| private final MetricsLogger mMetricsLogger; |
| |
| public TextClassifierEventTronLogger() { |
| this(new MetricsLogger()); |
| } |
| |
| @VisibleForTesting |
| public TextClassifierEventTronLogger(MetricsLogger metricsLogger) { |
| mMetricsLogger = Objects.requireNonNull(metricsLogger); |
| } |
| |
| /** Emits a text classifier event to the logs. */ |
| public void writeEvent(TextClassifierEvent event) { |
| Objects.requireNonNull(event); |
| |
| int category = getCategory(event); |
| if (category == -1) { |
| Log.w(TAG, "Unknown category: " + event.getEventCategory()); |
| return; |
| } |
| final LogMaker log = new LogMaker(category) |
| .setSubtype(getLogType(event)) |
| .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId()) |
| .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)); |
| if (event.getScores().length >= 1) { |
| log.addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScores()[0]); |
| } |
| String[] entityTypes = event.getEntityTypes(); |
| // The old logger does not support a field of list type, and thus workaround by store them |
| // in three separate fields. This is not an issue with the new logger. |
| if (entityTypes.length >= 1) { |
| log.addTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE, entityTypes[0]); |
| } |
| if (entityTypes.length >= 2) { |
| log.addTaggedData(FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE, entityTypes[1]); |
| } |
| if (entityTypes.length >= 3) { |
| log.addTaggedData(FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE, entityTypes[2]); |
| } |
| TextClassificationContext eventContext = event.getEventContext(); |
| if (eventContext != null) { |
| log.addTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE, eventContext.getWidgetType()); |
| log.addTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_VERSION, |
| eventContext.getWidgetVersion()); |
| log.setPackageName(eventContext.getPackageName()); |
| } |
| mMetricsLogger.write(log); |
| debugLog(log); |
| } |
| |
| private static String getModelName(TextClassifierEvent event) { |
| if (event.getModelName() != null) { |
| return event.getModelName(); |
| } |
| return SelectionSessionLogger.SignatureParser.getModelName(event.getResultId()); |
| } |
| |
| private static int getCategory(TextClassifierEvent event) { |
| switch (event.getEventCategory()) { |
| case TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS: |
| return MetricsEvent.CONVERSATION_ACTIONS; |
| case TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION: |
| return MetricsEvent.LANGUAGE_DETECTION; |
| } |
| return -1; |
| } |
| |
| private static int getLogType(TextClassifierEvent event) { |
| switch (event.getEventType()) { |
| case TextClassifierEvent.TYPE_SMART_ACTION: |
| return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE; |
| case TextClassifierEvent.TYPE_ACTIONS_SHOWN: |
| return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN; |
| case TextClassifierEvent.TYPE_MANUAL_REPLY: |
| return MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY; |
| case TextClassifierEvent.TYPE_ACTIONS_GENERATED: |
| return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED; |
| default: |
| return MetricsEvent.VIEW_UNKNOWN; |
| } |
| } |
| |
| private String toCategoryName(int category) { |
| switch (category) { |
| case MetricsEvent.CONVERSATION_ACTIONS: |
| return "conversation_actions"; |
| case MetricsEvent.LANGUAGE_DETECTION: |
| return "language_detection"; |
| } |
| return "unknown"; |
| } |
| |
| private String toEventName(int logType) { |
| switch (logType) { |
| case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE: |
| return "smart_share"; |
| case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN: |
| return "actions_shown"; |
| case MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY: |
| return "manual_reply"; |
| case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED: |
| return "actions_generated"; |
| } |
| return "unknown"; |
| } |
| |
| private void debugLog(LogMaker log) { |
| if (!Log.ENABLE_FULL_LOGGING) { |
| return; |
| } |
| final String id = String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID)); |
| final String categoryName = toCategoryName(log.getCategory()); |
| final String eventName = toEventName(log.getSubtype()); |
| final String widgetType = |
| String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE)); |
| final String widgetVersion = |
| String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_VERSION)); |
| final String model = String.valueOf(log.getTaggedData(FIELD_TEXTCLASSIFIER_MODEL)); |
| final String firstEntityType = |
| String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE)); |
| final String secondEntityType = |
| String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE)); |
| final String thirdEntityType = |
| String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE)); |
| final String score = |
| String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE)); |
| |
| StringBuilder builder = new StringBuilder(); |
| builder.append("writeEvent: "); |
| builder.append("id=").append(id); |
| builder.append(", category=").append(categoryName); |
| builder.append(", eventName=").append(eventName); |
| builder.append(", widgetType=").append(widgetType); |
| builder.append(", widgetVersion=").append(widgetVersion); |
| builder.append(", model=").append(model); |
| builder.append(", firstEntityType=").append(firstEntityType); |
| builder.append(", secondEntityType=").append(secondEntityType); |
| builder.append(", thirdEntityType=").append(thirdEntityType); |
| builder.append(", score=").append(score); |
| |
| Log.v(TAG, builder.toString()); |
| } |
| } |