1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.view.textclassifier; 17 18 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL; 19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE; 20 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SCORE; 21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE; 22 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SESSION_ID; 23 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE; 24 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_TYPE; 25 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_WIDGET_VERSION; 26 27 import android.metrics.LogMaker; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.logging.MetricsLogger; 31 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 32 import com.android.internal.util.Preconditions; 33 34 35 /** 36 * Log {@link TextClassifierEvent} by using Tron, only support language detection and 37 * conversation actions. 38 * 39 * @hide 40 */ 41 public final class TextClassifierEventTronLogger { 42 43 private static final String TAG = "TCEventTronLogger"; 44 45 private final MetricsLogger mMetricsLogger; 46 TextClassifierEventTronLogger()47 public TextClassifierEventTronLogger() { 48 this(new MetricsLogger()); 49 } 50 51 @VisibleForTesting TextClassifierEventTronLogger(MetricsLogger metricsLogger)52 public TextClassifierEventTronLogger(MetricsLogger metricsLogger) { 53 mMetricsLogger = Preconditions.checkNotNull(metricsLogger); 54 } 55 56 /** Emits a text classifier event to the logs. */ writeEvent(TextClassifierEvent event)57 public void writeEvent(TextClassifierEvent event) { 58 Preconditions.checkNotNull(event); 59 60 int category = getCategory(event); 61 if (category == -1) { 62 Log.w(TAG, "Unknown category: " + event.getEventCategory()); 63 return; 64 } 65 final LogMaker log = new LogMaker(category) 66 .setSubtype(getLogType(event)) 67 .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId()) 68 .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)); 69 if (event.getScores().length >= 1) { 70 log.addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScores()[0]); 71 } 72 String[] entityTypes = event.getEntityTypes(); 73 // The old logger does not support a field of list type, and thus workaround by store them 74 // in three separate fields. This is not an issue with the new logger. 75 if (entityTypes.length >= 1) { 76 log.addTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE, entityTypes[0]); 77 } 78 if (entityTypes.length >= 2) { 79 log.addTaggedData(FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE, entityTypes[1]); 80 } 81 if (entityTypes.length >= 3) { 82 log.addTaggedData(FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE, entityTypes[2]); 83 } 84 TextClassificationContext eventContext = event.getEventContext(); 85 if (eventContext != null) { 86 log.addTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE, eventContext.getWidgetType()); 87 log.addTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_VERSION, 88 eventContext.getWidgetVersion()); 89 log.setPackageName(eventContext.getPackageName()); 90 } 91 mMetricsLogger.write(log); 92 debugLog(log); 93 } 94 getModelName(TextClassifierEvent event)95 private static String getModelName(TextClassifierEvent event) { 96 if (event.getModelName() != null) { 97 return event.getModelName(); 98 } 99 return SelectionSessionLogger.SignatureParser.getModelName(event.getResultId()); 100 } 101 getCategory(TextClassifierEvent event)102 private static int getCategory(TextClassifierEvent event) { 103 switch (event.getEventCategory()) { 104 case TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS: 105 return MetricsEvent.CONVERSATION_ACTIONS; 106 case TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION: 107 return MetricsEvent.LANGUAGE_DETECTION; 108 } 109 return -1; 110 } 111 getLogType(TextClassifierEvent event)112 private static int getLogType(TextClassifierEvent event) { 113 switch (event.getEventType()) { 114 case TextClassifierEvent.TYPE_SMART_ACTION: 115 return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE; 116 case TextClassifierEvent.TYPE_ACTIONS_SHOWN: 117 return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN; 118 case TextClassifierEvent.TYPE_MANUAL_REPLY: 119 return MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY; 120 case TextClassifierEvent.TYPE_ACTIONS_GENERATED: 121 return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED; 122 default: 123 return MetricsEvent.VIEW_UNKNOWN; 124 } 125 } 126 toCategoryName(int category)127 private String toCategoryName(int category) { 128 switch (category) { 129 case MetricsEvent.CONVERSATION_ACTIONS: 130 return "conversation_actions"; 131 case MetricsEvent.LANGUAGE_DETECTION: 132 return "language_detection"; 133 } 134 return "unknown"; 135 } 136 toEventName(int logType)137 private String toEventName(int logType) { 138 switch (logType) { 139 case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE: 140 return "smart_share"; 141 case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN: 142 return "actions_shown"; 143 case MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY: 144 return "manual_reply"; 145 case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED: 146 return "actions_generated"; 147 } 148 return "unknown"; 149 } 150 debugLog(LogMaker log)151 private void debugLog(LogMaker log) { 152 if (!Log.ENABLE_FULL_LOGGING) { 153 return; 154 } 155 final String id = String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID)); 156 final String categoryName = toCategoryName(log.getCategory()); 157 final String eventName = toEventName(log.getSubtype()); 158 final String widgetType = 159 String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE)); 160 final String widgetVersion = 161 String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_VERSION)); 162 final String model = String.valueOf(log.getTaggedData(FIELD_TEXTCLASSIFIER_MODEL)); 163 final String firstEntityType = 164 String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE)); 165 final String secondEntityType = 166 String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE)); 167 final String thirdEntityType = 168 String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_THIRD_ENTITY_TYPE)); 169 final String score = 170 String.valueOf(log.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE)); 171 172 StringBuilder builder = new StringBuilder(); 173 builder.append("writeEvent: "); 174 builder.append("id=").append(id); 175 builder.append(", category=").append(categoryName); 176 builder.append(", eventName=").append(eventName); 177 builder.append(", widgetType=").append(widgetType); 178 builder.append(", widgetVersion=").append(widgetVersion); 179 builder.append(", model=").append(model); 180 builder.append(", firstEntityType=").append(firstEntityType); 181 builder.append(", secondEntityType=").append(secondEntityType); 182 builder.append(", thirdEntityType=").append(thirdEntityType); 183 builder.append(", score=").append(score); 184 185 Log.v(TAG, builder.toString()); 186 } 187 } 188