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 17 package com.android.textclassifier.common.logging; 18 19 import android.content.Context; 20 import android.text.TextUtils; 21 import com.android.textclassifier.common.base.LocaleCompat; 22 import com.google.common.base.Joiner; 23 import com.google.common.base.Objects; 24 import com.google.common.base.Optional; 25 import com.google.common.base.Preconditions; 26 import com.google.common.base.Splitter; 27 import com.google.common.collect.ImmutableList; 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Locale; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 import javax.annotation.Nullable; 34 35 /** Provide utils to generate and parse the result id. */ 36 public final class ResultIdUtils { 37 private static final String CLASSIFIER_ID = "androidtc"; 38 private static final String SEPARATOR_MODEL_NAME = ";"; 39 private static final String SEPARATOR_LOCALES = ","; 40 private static final Pattern EXTRACT_MODEL_NAME_FROM_RESULT_ID = 41 Pattern.compile("^[^|]*\\|([^|]*)\\|[^|]*$"); 42 43 /** Creates a string id that may be used to identify a TextClassifier result. */ createId( Context context, String text, int start, int end, List<Optional<ModelInfo>> modelInfos)44 public static String createId( 45 Context context, String text, int start, int end, List<Optional<ModelInfo>> modelInfos) { 46 Preconditions.checkNotNull(text); 47 Preconditions.checkNotNull(context); 48 Preconditions.checkNotNull(modelInfos); 49 final int hash = Objects.hashCode(text, start, end, context.getPackageName()); 50 return createId(hash, modelInfos); 51 } 52 53 /** Creates a string id that may be used to identify a TextClassifier result. */ createId(int hash, List<Optional<ModelInfo>> modelInfos)54 public static String createId(int hash, List<Optional<ModelInfo>> modelInfos) { 55 Preconditions.checkNotNull(modelInfos); 56 final List<String> modelNames = new ArrayList<>(); 57 for (Optional<ModelInfo> modelInfo : modelInfos) { 58 modelNames.add(modelInfo.transform(ModelInfo::toModelName).or("")); 59 } 60 return String.format( 61 Locale.US, 62 "%s|%s|%d", 63 CLASSIFIER_ID, 64 Joiner.on(SEPARATOR_MODEL_NAME).join(modelNames), 65 hash); 66 } 67 68 /** Returns if the result id was generated from the default text classifier. */ isFromDefaultTextClassifier(String resultId)69 public static boolean isFromDefaultTextClassifier(String resultId) { 70 return resultId.startsWith(CLASSIFIER_ID + '|'); 71 } 72 73 /** Returns all the model names encoded in the signature. */ getModelNames(@ullable String signature)74 public static ImmutableList<String> getModelNames(@Nullable String signature) { 75 if (TextUtils.isEmpty(signature)) { 76 return ImmutableList.of(); 77 } 78 Matcher matcher = EXTRACT_MODEL_NAME_FROM_RESULT_ID.matcher(signature); 79 if (!matcher.find()) { 80 return ImmutableList.of(); 81 } 82 return ImmutableList.copyOf(Splitter.on(SEPARATOR_MODEL_NAME).splitToList(matcher.group(1))); 83 } 84 ResultIdUtils()85 private ResultIdUtils() {} 86 87 /** Model information of a model file. */ 88 public static class ModelInfo { 89 private final String modelName; 90 ModelInfo(int version, List<Locale> locales)91 public ModelInfo(int version, List<Locale> locales) { 92 this(version, createSupportedLanguageTagsString(locales)); 93 } 94 95 /** 96 * Creates a {@link ModelInfo} object. 97 * 98 * @param version model version 99 * @param supportedLanguageTags a comma-separated string of bcp47 language tags of supported 100 * languages 101 */ ModelInfo(int version, String supportedLanguageTags)102 public ModelInfo(int version, String supportedLanguageTags) { 103 this.modelName = createModelName(version, supportedLanguageTags); 104 } 105 createSupportedLanguageTagsString(List<Locale> locales)106 private static String createSupportedLanguageTagsString(List<Locale> locales) { 107 List<String> languageTags = new ArrayList<>(); 108 for (Locale locale : locales) { 109 languageTags.add(LocaleCompat.toLanguageTag(locale)); 110 } 111 return Joiner.on(SEPARATOR_LOCALES).join(languageTags); 112 } 113 createModelName(int version, String supportedLanguageTags)114 private static String createModelName(int version, String supportedLanguageTags) { 115 return String.format(Locale.US, "%s_v%d", supportedLanguageTags, version); 116 } 117 118 /** Returns a string representation of the model info. */ toModelName()119 public String toModelName() { 120 return modelName; 121 } 122 } 123 } 124