1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
|
/*
* Copyright (C) 2019 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 android.annotation.Nullable;
import android.app.RemoteAction;
import android.content.Intent;
import android.icu.util.ULocale;
import android.os.Bundle;
import com.android.internal.util.ArrayUtils;
import com.google.android.textclassifier.AnnotatorModel;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for inserting and retrieving data in TextClassifier request/response extras.
* @hide
*/
// TODO: Make this a TestApi for CTS testing.
public final class ExtrasUtils {
// Keys for response objects.
private static final String SERIALIZED_ENTITIES_DATA = "serialized-entities-data";
private static final String ENTITIES_EXTRAS = "entities-extras";
private static final String ACTION_INTENT = "action-intent";
private static final String ACTIONS_INTENTS = "actions-intents";
private static final String FOREIGN_LANGUAGE = "foreign-language";
private static final String ENTITY_TYPE = "entity-type";
private static final String SCORE = "score";
private static final String MODEL_VERSION = "model-version";
private static final String MODEL_NAME = "model-name";
private static final String TEXT_LANGUAGES = "text-languages";
private static final String ENTITIES = "entities";
// Keys for request objects.
private static final String IS_SERIALIZED_ENTITY_DATA_ENABLED =
"is-serialized-entity-data-enabled";
private ExtrasUtils() {}
/**
* Bundles and returns foreign language detection information for TextClassifier responses.
*/
static Bundle createForeignLanguageExtra(
String language, float score, int modelVersion) {
final Bundle bundle = new Bundle();
bundle.putString(ENTITY_TYPE, language);
bundle.putFloat(SCORE, score);
bundle.putInt(MODEL_VERSION, modelVersion);
bundle.putString(MODEL_NAME, "langId_v" + modelVersion);
return bundle;
}
/**
* Stores {@code extra} as foreign language information in TextClassifier response object's
* extras {@code container}.
*
* @see #getForeignLanguageExtra(TextClassification)
*/
static void putForeignLanguageExtra(Bundle container, Bundle extra) {
container.putParcelable(FOREIGN_LANGUAGE, extra);
}
/**
* Returns foreign language detection information contained in the TextClassification object.
* responses.
*
* @see #putForeignLanguageExtra(Bundle, Bundle)
*/
@Nullable
public static Bundle getForeignLanguageExtra(@Nullable TextClassification classification) {
if (classification == null) {
return null;
}
return classification.getExtras().getBundle(FOREIGN_LANGUAGE);
}
/**
* @see #getTopLanguage(Intent)
*/
static void putTopLanguageScores(Bundle container, EntityConfidence languageScores) {
final int maxSize = Math.min(3, languageScores.getEntities().size());
final String[] languages = languageScores.getEntities().subList(0, maxSize)
.toArray(new String[0]);
final float[] scores = new float[languages.length];
for (int i = 0; i < languages.length; i++) {
scores[i] = languageScores.getConfidenceScore(languages[i]);
}
container.putStringArray(ENTITY_TYPE, languages);
container.putFloatArray(SCORE, scores);
}
/**
* @see #putTopLanguageScores(Bundle, EntityConfidence)
*/
@Nullable
public static ULocale getTopLanguage(@Nullable Intent intent) {
if (intent == null) {
return null;
}
final Bundle tcBundle = intent.getBundleExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER);
if (tcBundle == null) {
return null;
}
final Bundle textLanguagesExtra = tcBundle.getBundle(TEXT_LANGUAGES);
if (textLanguagesExtra == null) {
return null;
}
final String[] languages = textLanguagesExtra.getStringArray(ENTITY_TYPE);
final float[] scores = textLanguagesExtra.getFloatArray(SCORE);
if (languages == null || scores == null
|| languages.length == 0 || languages.length != scores.length) {
return null;
}
int highestScoringIndex = 0;
for (int i = 1; i < languages.length; i++) {
if (scores[highestScoringIndex] < scores[i]) {
highestScoringIndex = i;
}
}
return ULocale.forLanguageTag(languages[highestScoringIndex]);
}
public static void putTextLanguagesExtra(Bundle container, Bundle extra) {
container.putBundle(TEXT_LANGUAGES, extra);
}
/**
* Stores {@code actionIntents} information in TextClassifier response object's extras
* {@code container}.
*/
static void putActionsIntents(Bundle container, ArrayList<Intent> actionsIntents) {
container.putParcelableArrayList(ACTIONS_INTENTS, actionsIntents);
}
/**
* Stores {@code actionIntents} information in TextClassifier response object's extras
* {@code container}.
*/
public static void putActionIntent(Bundle container, @Nullable Intent actionIntent) {
container.putParcelable(ACTION_INTENT, actionIntent);
}
/**
* Returns {@code actionIntent} information contained in a TextClassifier response object.
*/
@Nullable
public static Intent getActionIntent(Bundle container) {
return container.getParcelable(ACTION_INTENT);
}
/**
* Stores serialized entity data information in TextClassifier response object's extras
* {@code container}.
*/
public static void putSerializedEntityData(
Bundle container, @Nullable byte[] serializedEntityData) {
container.putByteArray(SERIALIZED_ENTITIES_DATA, serializedEntityData);
}
/**
* Returns serialized entity data information contained in a TextClassifier response
* object.
*/
@Nullable
public static byte[] getSerializedEntityData(Bundle container) {
return container.getByteArray(SERIALIZED_ENTITIES_DATA);
}
/**
* Stores {@code entities} information in TextClassifier response object's extras
* {@code container}.
*
* @see {@link #getCopyText(Bundle)}
*/
public static void putEntitiesExtras(Bundle container, @Nullable Bundle entitiesExtras) {
container.putParcelable(ENTITIES_EXTRAS, entitiesExtras);
}
/**
* Returns {@code entities} information contained in a TextClassifier response object.
*
* @see {@link #putEntitiesExtras(Bundle, Bundle)}
*/
@Nullable
public static String getCopyText(Bundle container) {
Bundle entitiesExtras = container.getParcelable(ENTITIES_EXTRAS);
if (entitiesExtras == null) {
return null;
}
return entitiesExtras.getString("text");
}
/**
* Returns {@code actionIntents} information contained in the TextClassification object.
*/
@Nullable
public static ArrayList<Intent> getActionsIntents(@Nullable TextClassification classification) {
if (classification == null) {
return null;
}
return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS);
}
/**
* Returns the first action found in the {@code classification} object with an intent
* action string, {@code intentAction}.
*/
@Nullable
public static RemoteAction findAction(
@Nullable TextClassification classification, @Nullable String intentAction) {
if (classification == null || intentAction == null) {
return null;
}
final ArrayList<Intent> actionIntents = getActionsIntents(classification);
if (actionIntents != null) {
final int size = actionIntents.size();
for (int i = 0; i < size; i++) {
final Intent intent = actionIntents.get(i);
if (intent != null && intentAction.equals(intent.getAction())) {
return classification.getActions().get(i);
}
}
}
return null;
}
/**
* Returns the first "translate" action found in the {@code classification} object.
*/
@Nullable
public static RemoteAction findTranslateAction(@Nullable TextClassification classification) {
return findAction(classification, Intent.ACTION_TRANSLATE);
}
/**
* Returns the entity type contained in the {@code extra}.
*/
@Nullable
public static String getEntityType(@Nullable Bundle extra) {
if (extra == null) {
return null;
}
return extra.getString(ENTITY_TYPE);
}
/**
* Returns the score contained in the {@code extra}.
*/
@Nullable
public static float getScore(Bundle extra) {
final int defaultValue = -1;
if (extra == null) {
return defaultValue;
}
return extra.getFloat(SCORE, defaultValue);
}
/**
* Returns the model name contained in the {@code extra}.
*/
@Nullable
public static String getModelName(@Nullable Bundle extra) {
if (extra == null) {
return null;
}
return extra.getString(MODEL_NAME);
}
/**
* Stores the entities from {@link AnnotatorModel.ClassificationResult} in {@code container}.
*/
public static void putEntities(
Bundle container,
@Nullable AnnotatorModel.ClassificationResult[] classifications) {
if (ArrayUtils.isEmpty(classifications)) {
return;
}
ArrayList<Bundle> entitiesBundle = new ArrayList<>();
for (AnnotatorModel.ClassificationResult classification : classifications) {
if (classification == null) {
continue;
}
Bundle entityBundle = new Bundle();
entityBundle.putString(ENTITY_TYPE, classification.getCollection());
entityBundle.putByteArray(
SERIALIZED_ENTITIES_DATA,
classification.getSerializedEntityData());
entitiesBundle.add(entityBundle);
}
if (!entitiesBundle.isEmpty()) {
container.putParcelableArrayList(ENTITIES, entitiesBundle);
}
}
/**
* Returns a list of entities contained in the {@code extra}.
*/
@Nullable
public static List<Bundle> getEntities(Bundle container) {
return container.getParcelableArrayList(ENTITIES);
}
/**
* Whether the annotator should populate serialized entity data into the result object.
*/
public static boolean isSerializedEntityDataEnabled(TextLinks.Request request) {
return request.getExtras().getBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED);
}
/**
* To indicate whether the annotator should populate serialized entity data in the result
* object.
*/
public static void putIsSerializedEntityDataEnabled(Bundle bundle, boolean isEnabled) {
bundle.putBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED, isEnabled);
}
}
|