Merge "Move Scoped Storage compat flags definition to frameworks/base" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 8adf48d..da5d624 100644
--- a/Android.bp
+++ b/Android.bp
@@ -791,10 +791,6 @@
"libphonenumber-platform",
"tagsoup",
"rappor",
- "libtextclassifier-java",
- ],
- required: [
- "libtextclassifier",
],
dxflags: ["--core-library"],
}
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
index f61ea85..46250d7 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassificationManagerPerfTest.java
@@ -77,7 +77,6 @@
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
textClassificationManager.getTextClassifier();
- textClassificationManager.invalidateForTesting();
}
}
@@ -90,7 +89,6 @@
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
textClassificationManager.getTextClassifier();
- textClassificationManager.invalidateForTesting();
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 32e0f73..5b8ee71 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11995,7 +11995,8 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with
* @param timeoutMillis Maximum time the profile is allowed to be off in milliseconds or 0 if
- * not limited.
+ * not limited. The minimum non-zero value corresponds to 72 hours. If an admin sets a
+ * smaller non-zero vaulue, 72 hours will be set instead.
* @throws IllegalStateException if the profile owner doesn't have an activity that handles
* {@link #ACTION_CHECK_POLICY_COMPLIANCE}
* @see #setPersonalAppsSuspended
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 1b6c1ee..7e4d68d 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -20,6 +20,7 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -71,6 +72,7 @@
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
+import android.view.WindowInsets.Side;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.view.autofill.AutofillId;
@@ -1246,7 +1248,8 @@
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
- mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars());
+ mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
+ mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
// IME layout should always be inset by navigation bar, no matter its current visibility,
// unless automotive requests it, since automotive may hide the navigation bar.
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 3ff6f54..9dfbc28 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -41,7 +41,6 @@
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassificationSessionId;
@@ -405,27 +404,19 @@
*/
@NonNull
public static TextClassifier getDefaultTextClassifierImplementation(@NonNull Context context) {
- final TextClassificationManager tcm =
- context.getSystemService(TextClassificationManager.class);
- if (tcm == null) {
+ final String defaultTextClassifierPackageName =
+ context.getPackageManager().getDefaultTextClassifierPackageName();
+ if (TextUtils.isEmpty(defaultTextClassifierPackageName)) {
return TextClassifier.NO_OP;
}
- TextClassificationConstants settings = new TextClassificationConstants();
- if (settings.getUseDefaultTextClassifierAsDefaultImplementation()) {
- final String defaultTextClassifierPackageName =
- context.getPackageManager().getDefaultTextClassifierPackageName();
- if (TextUtils.isEmpty(defaultTextClassifierPackageName)) {
- return TextClassifier.NO_OP;
- }
- if (defaultTextClassifierPackageName.equals(context.getPackageName())) {
- throw new RuntimeException(
- "The default text classifier itself should not call the"
- + "getDefaultTextClassifierImplementation() method.");
- }
- return tcm.getTextClassifier(TextClassifier.DEFAULT_SERVICE);
- } else {
- return tcm.getTextClassifier(TextClassifier.LOCAL);
+ if (defaultTextClassifierPackageName.equals(context.getPackageName())) {
+ throw new RuntimeException(
+ "The default text classifier itself should not call the"
+ + "getDefaultTextClassifierImplementation() method.");
}
+ final TextClassificationManager tcm =
+ context.getSystemService(TextClassificationManager.class);
+ return tcm.getTextClassifier(TextClassifier.DEFAULT_SYSTEM);
}
/** @hide **/
diff --git a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
deleted file mode 100644
index 3164567..0000000
--- a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.KeyValueListParser;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-
-import java.lang.ref.WeakReference;
-import java.util.Objects;
-import java.util.function.Supplier;
-
-/**
- * Parses the {@link Settings.Global#TEXT_CLASSIFIER_ACTION_MODEL_PARAMS} flag.
- *
- * @hide
- */
-public final class ActionsModelParamsSupplier implements
- Supplier<ActionsModelParamsSupplier.ActionsModelParams> {
- private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
-
- @VisibleForTesting
- static final String KEY_REQUIRED_MODEL_VERSION = "required_model_version";
- @VisibleForTesting
- static final String KEY_REQUIRED_LOCALES = "required_locales";
- @VisibleForTesting
- static final String KEY_SERIALIZED_PRECONDITIONS = "serialized_preconditions";
-
- private final Context mAppContext;
- private final SettingsObserver mSettingsObserver;
-
- private final Object mLock = new Object();
- private final Runnable mOnChangedListener;
- @Nullable
- @GuardedBy("mLock")
- private ActionsModelParams mActionsModelParams;
- @GuardedBy("mLock")
- private boolean mParsed = true;
-
- public ActionsModelParamsSupplier(Context context, @Nullable Runnable onChangedListener) {
- final Context appContext = Preconditions.checkNotNull(context).getApplicationContext();
- // Some contexts don't have an app context.
- mAppContext = appContext != null ? appContext : context;
- mOnChangedListener = onChangedListener == null ? () -> {} : onChangedListener;
- mSettingsObserver = new SettingsObserver(mAppContext, () -> {
- synchronized (mLock) {
- Log.v(TAG, "Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS is updated");
- mParsed = true;
- mOnChangedListener.run();
- }
- });
- }
-
- /**
- * Returns the parsed actions params or {@link ActionsModelParams#INVALID} if the value is
- * invalid.
- */
- @Override
- public ActionsModelParams get() {
- synchronized (mLock) {
- if (mParsed) {
- mActionsModelParams = parse(mAppContext.getContentResolver());
- mParsed = false;
- }
- }
- return mActionsModelParams;
- }
-
- private ActionsModelParams parse(ContentResolver contentResolver) {
- String settingStr = Settings.Global.getString(contentResolver,
- Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS);
- if (TextUtils.isEmpty(settingStr)) {
- return ActionsModelParams.INVALID;
- }
- try {
- KeyValueListParser keyValueListParser = new KeyValueListParser(',');
- keyValueListParser.setString(settingStr);
- int version = keyValueListParser.getInt(KEY_REQUIRED_MODEL_VERSION, -1);
- if (version == -1) {
- Log.w(TAG, "ActionsModelParams.Parse, invalid model version");
- return ActionsModelParams.INVALID;
- }
- String locales = keyValueListParser.getString(KEY_REQUIRED_LOCALES, null);
- if (locales == null) {
- Log.w(TAG, "ActionsModelParams.Parse, invalid locales");
- return ActionsModelParams.INVALID;
- }
- String serializedPreconditionsStr =
- keyValueListParser.getString(KEY_SERIALIZED_PRECONDITIONS, null);
- if (serializedPreconditionsStr == null) {
- Log.w(TAG, "ActionsModelParams.Parse, invalid preconditions");
- return ActionsModelParams.INVALID;
- }
- byte[] serializedPreconditions =
- Base64.decode(serializedPreconditionsStr, Base64.NO_WRAP);
- return new ActionsModelParams(version, locales, serializedPreconditions);
- } catch (Throwable t) {
- Log.e(TAG, "Invalid TEXT_CLASSIFIER_ACTION_MODEL_PARAMS, ignore", t);
- }
- return ActionsModelParams.INVALID;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- mAppContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
- } finally {
- super.finalize();
- }
- }
-
- /**
- * Represents the parsed result.
- */
- public static final class ActionsModelParams {
-
- public static final ActionsModelParams INVALID =
- new ActionsModelParams(-1, "", new byte[0]);
-
- /**
- * The required model version to apply {@code mSerializedPreconditions}.
- */
- private final int mRequiredModelVersion;
-
- /**
- * The required model locales to apply {@code mSerializedPreconditions}.
- */
- private final String mRequiredModelLocales;
-
- /**
- * The serialized params that will be applied to the model file, if all requirements are
- * met. Do not modify.
- */
- private final byte[] mSerializedPreconditions;
-
- public ActionsModelParams(int requiredModelVersion, String requiredModelLocales,
- byte[] serializedPreconditions) {
- mRequiredModelVersion = requiredModelVersion;
- mRequiredModelLocales = Preconditions.checkNotNull(requiredModelLocales);
- mSerializedPreconditions = Preconditions.checkNotNull(serializedPreconditions);
- }
-
- /**
- * Returns the serialized preconditions. Returns {@code null} if the the model in use does
- * not meet all the requirements listed in the {@code ActionsModelParams} or the params
- * are invalid.
- */
- @Nullable
- public byte[] getSerializedPreconditions(ModelFileManager.ModelFile modelInUse) {
- if (this == INVALID) {
- return null;
- }
- if (modelInUse.getVersion() != mRequiredModelVersion) {
- Log.w(TAG, String.format(
- "Not applying mSerializedPreconditions, required version=%d, actual=%d",
- mRequiredModelVersion, modelInUse.getVersion()));
- return null;
- }
- if (!Objects.equals(modelInUse.getSupportedLocalesStr(), mRequiredModelLocales)) {
- Log.w(TAG, String.format(
- "Not applying mSerializedPreconditions, required locales=%s, actual=%s",
- mRequiredModelLocales, modelInUse.getSupportedLocalesStr()));
- return null;
- }
- return mSerializedPreconditions;
- }
- }
-
- private static final class SettingsObserver extends ContentObserver {
-
- private final WeakReference<Runnable> mOnChangedListener;
-
- SettingsObserver(Context appContext, Runnable listener) {
- super(null);
- mOnChangedListener = new WeakReference<>(listener);
- appContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_ACTION_MODEL_PARAMS),
- false /* notifyForDescendants */,
- this);
- }
-
- public void onChange(boolean selfChange) {
- if (mOnChangedListener.get() != null) {
- mOnChangedListener.get().run();
- }
- }
- }
-}
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
deleted file mode 100644
index 3ed48f6..0000000
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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 android.annotation.Nullable;
-import android.app.Person;
-import android.app.RemoteAction;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Pair;
-import android.view.textclassifier.intent.LabeledIntent;
-import android.view.textclassifier.intent.TemplateIntentFactory;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.textclassifier.ActionsSuggestionsModel;
-import com.google.android.textclassifier.RemoteActionTemplate;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.StringJoiner;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-/**
- * Helper class for action suggestions.
- *
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class ActionsSuggestionsHelper {
- private static final String TAG = "ActionsSuggestions";
- private static final int USER_LOCAL = 0;
- private static final int FIRST_NON_LOCAL_USER = 1;
-
- private ActionsSuggestionsHelper() {}
-
- /**
- * Converts the messages to a list of native messages object that the model can understand.
- * <p>
- * User id encoding - local user is represented as 0, Other users are numbered according to
- * how far before they spoke last time in the conversation. For example, considering this
- * conversation:
- * <ul>
- * <li> User A: xxx
- * <li> Local user: yyy
- * <li> User B: zzz
- * </ul>
- * User A will be encoded as 2, user B will be encoded as 1 and local user will be encoded as 0.
- */
- public static ActionsSuggestionsModel.ConversationMessage[] toNativeMessages(
- List<ConversationActions.Message> messages,
- Function<CharSequence, String> languageDetector) {
- List<ConversationActions.Message> messagesWithText =
- messages.stream()
- .filter(message -> !TextUtils.isEmpty(message.getText()))
- .collect(Collectors.toCollection(ArrayList::new));
- if (messagesWithText.isEmpty()) {
- return new ActionsSuggestionsModel.ConversationMessage[0];
- }
- Deque<ActionsSuggestionsModel.ConversationMessage> nativeMessages = new ArrayDeque<>();
- PersonEncoder personEncoder = new PersonEncoder();
- int size = messagesWithText.size();
- for (int i = size - 1; i >= 0; i--) {
- ConversationActions.Message message = messagesWithText.get(i);
- long referenceTime = message.getReferenceTime() == null
- ? 0
- : message.getReferenceTime().toInstant().toEpochMilli();
- String timeZone = message.getReferenceTime() == null
- ? null
- : message.getReferenceTime().getZone().getId();
- nativeMessages.push(new ActionsSuggestionsModel.ConversationMessage(
- personEncoder.encode(message.getAuthor()),
- message.getText().toString(), referenceTime, timeZone,
- languageDetector.apply(message.getText())));
- }
- return nativeMessages.toArray(
- new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]);
- }
-
- /**
- * Returns the result id for logging.
- */
- public static String createResultId(
- Context context,
- List<ConversationActions.Message> messages,
- int modelVersion,
- List<Locale> modelLocales) {
- final StringJoiner localesJoiner = new StringJoiner(",");
- for (Locale locale : modelLocales) {
- localesJoiner.add(locale.toLanguageTag());
- }
- final String modelName = String.format(
- Locale.US, "%s_v%d", localesJoiner.toString(), modelVersion);
- final int hash = Objects.hash(
- messages.stream().mapToInt(ActionsSuggestionsHelper::hashMessage),
- context.getPackageName(),
- System.currentTimeMillis());
- return SelectionSessionLogger.SignatureParser.createSignature(
- SelectionSessionLogger.CLASSIFIER_ID, modelName, hash);
- }
-
- /**
- * Generated labeled intent from an action suggestion and return the resolved result.
- */
- @Nullable
- public static LabeledIntent.Result createLabeledIntentResult(
- Context context,
- TemplateIntentFactory templateIntentFactory,
- ActionsSuggestionsModel.ActionSuggestion nativeSuggestion) {
- RemoteActionTemplate[] remoteActionTemplates =
- nativeSuggestion.getRemoteActionTemplates();
- if (remoteActionTemplates == null) {
- Log.w(TAG, "createRemoteAction: Missing template for type "
- + nativeSuggestion.getActionType());
- return null;
- }
- List<LabeledIntent> labeledIntents = templateIntentFactory.create(remoteActionTemplates);
- if (labeledIntents.isEmpty()) {
- return null;
- }
- // Given that we only support implicit intent here, we should expect there is just one
- // intent for each action type.
- LabeledIntent.TitleChooser titleChooser =
- ActionsSuggestionsHelper.createTitleChooser(nativeSuggestion.getActionType());
- return labeledIntents.get(0).resolve(context, titleChooser, null);
- }
-
- /**
- * Returns a {@link LabeledIntent.TitleChooser} for conversation actions use case.
- */
- @Nullable
- public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
- if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) {
- return (labeledIntent, resolveInfo) -> {
- if (resolveInfo.handleAllWebDataURI) {
- return labeledIntent.titleWithEntity;
- }
- if ("android".equals(resolveInfo.activityInfo.packageName)) {
- return labeledIntent.titleWithEntity;
- }
- return labeledIntent.titleWithoutEntity;
- };
- }
- return null;
- }
-
- /**
- * Returns a list of {@link ConversationAction}s that have 0 duplicates. Two actions are
- * duplicates if they may look the same to users. This function assumes every
- * ConversationActions with a non-null RemoteAction also have a non-null intent in the extras.
- */
- public static List<ConversationAction> removeActionsWithDuplicates(
- List<ConversationAction> conversationActions) {
- // Ideally, we should compare title and icon here, but comparing icon is expensive and thus
- // we use the component name of the target handler as the heuristic.
- Map<Pair<String, String>, Integer> counter = new ArrayMap<>();
- for (ConversationAction conversationAction : conversationActions) {
- Pair<String, String> representation = getRepresentation(conversationAction);
- if (representation == null) {
- continue;
- }
- Integer existingCount = counter.getOrDefault(representation, 0);
- counter.put(representation, existingCount + 1);
- }
- List<ConversationAction> result = new ArrayList<>();
- for (ConversationAction conversationAction : conversationActions) {
- Pair<String, String> representation = getRepresentation(conversationAction);
- if (representation == null || counter.getOrDefault(representation, 0) == 1) {
- result.add(conversationAction);
- }
- }
- return result;
- }
-
- @Nullable
- private static Pair<String, String> getRepresentation(
- ConversationAction conversationAction) {
- RemoteAction remoteAction = conversationAction.getAction();
- if (remoteAction == null) {
- return null;
- }
- Intent actionIntent = ExtrasUtils.getActionIntent(conversationAction.getExtras());
- ComponentName componentName = actionIntent.getComponent();
- // Action without a component name will be considered as from the same app.
- String packageName = componentName == null ? null : componentName.getPackageName();
- return new Pair<>(
- conversationAction.getAction().getTitle().toString(), packageName);
- }
-
- private static final class PersonEncoder {
- private final Map<Person, Integer> mMapping = new ArrayMap<>();
- private int mNextUserId = FIRST_NON_LOCAL_USER;
-
- private int encode(Person person) {
- if (ConversationActions.Message.PERSON_USER_SELF.equals(person)) {
- return USER_LOCAL;
- }
- Integer result = mMapping.get(person);
- if (result == null) {
- mMapping.put(person, mNextUserId);
- result = mNextUserId;
- mNextUserId++;
- }
- return result;
- }
- }
-
- private static int hashMessage(ConversationActions.Message message) {
- return Objects.hash(message.getAuthor(), message.getText(), message.getReferenceTime());
- }
-}
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 11e0e2c..9e2b642 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -19,15 +19,9 @@
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.
@@ -37,52 +31,19 @@
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);
+ private ExtrasUtils() {
}
/**
* Returns foreign language detection information contained in the TextClassification object.
* responses.
- *
- * @see #putForeignLanguageExtra(Bundle, Bundle)
*/
@Nullable
public static Bundle getForeignLanguageExtra(@Nullable TextClassification classification) {
@@ -93,72 +54,6 @@
}
/**
- * @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
@@ -167,48 +62,6 @@
}
/**
- * 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
@@ -224,7 +77,7 @@
* action string, {@code intentAction}.
*/
@Nullable
- public static RemoteAction findAction(
+ private static RemoteAction findAction(
@Nullable TextClassification classification, @Nullable String intentAction) {
if (classification == null || intentAction == null) {
return null;
@@ -283,53 +136,4 @@
}
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);
- }
-}
+}
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
deleted file mode 100644
index 17ec73a..0000000
--- a/core/java/android/view/textclassifier/GenerateLinksLogger.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2017 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.metrics.LogMaker;
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Random;
-import java.util.UUID;
-
-/**
- * A helper for logging calls to generateLinks.
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class GenerateLinksLogger {
-
- private static final String LOG_TAG = "GenerateLinksLogger";
- private static final String ZERO = "0";
-
- private final MetricsLogger mMetricsLogger;
- private final Random mRng;
- private final int mSampleRate;
-
- /**
- * @param sampleRate the rate at which log events are written. (e.g. 100 means there is a 0.01
- * chance that a call to logGenerateLinks results in an event being written).
- * To write all events, pass 1.
- */
- public GenerateLinksLogger(int sampleRate) {
- mSampleRate = sampleRate;
- mRng = new Random(System.nanoTime());
- mMetricsLogger = new MetricsLogger();
- }
-
- @VisibleForTesting
- public GenerateLinksLogger(int sampleRate, MetricsLogger metricsLogger) {
- mSampleRate = sampleRate;
- mRng = new Random(System.nanoTime());
- mMetricsLogger = metricsLogger;
- }
-
- /** Logs statistics about a call to generateLinks. */
- public void logGenerateLinks(CharSequence text, TextLinks links, String callingPackageName,
- long latencyMs) {
- Objects.requireNonNull(text);
- Objects.requireNonNull(links);
- Objects.requireNonNull(callingPackageName);
- if (!shouldLog()) {
- return;
- }
-
- // Always populate the total stats, and per-entity stats for each entity type detected.
- final LinkifyStats totalStats = new LinkifyStats();
- final Map<String, LinkifyStats> perEntityTypeStats = new ArrayMap<>();
- for (TextLinks.TextLink link : links.getLinks()) {
- if (link.getEntityCount() == 0) continue;
- final String entityType = link.getEntity(0);
- if (entityType == null
- || TextClassifier.TYPE_OTHER.equals(entityType)
- || TextClassifier.TYPE_UNKNOWN.equals(entityType)) {
- continue;
- }
- totalStats.countLink(link);
- perEntityTypeStats.computeIfAbsent(entityType, k -> new LinkifyStats()).countLink(link);
- }
-
- final String callId = UUID.randomUUID().toString();
- writeStats(callId, callingPackageName, null, totalStats, text, latencyMs);
- for (Map.Entry<String, LinkifyStats> entry : perEntityTypeStats.entrySet()) {
- writeStats(callId, callingPackageName, entry.getKey(), entry.getValue(), text,
- latencyMs);
- }
- }
-
- /**
- * Returns whether this particular event should be logged.
- *
- * Sampling is used to reduce the amount of logging data generated.
- **/
- private boolean shouldLog() {
- if (mSampleRate <= 1) {
- return true;
- } else {
- return mRng.nextInt(mSampleRate) == 0;
- }
- }
-
- /** Writes a log event for the given stats. */
- private void writeStats(String callId, String callingPackageName, @Nullable String entityType,
- LinkifyStats stats, CharSequence text, long latencyMs) {
- final LogMaker log = new LogMaker(MetricsEvent.TEXT_CLASSIFIER_GENERATE_LINKS)
- .setPackageName(callingPackageName)
- .addTaggedData(MetricsEvent.FIELD_LINKIFY_CALL_ID, callId)
- .addTaggedData(MetricsEvent.FIELD_LINKIFY_NUM_LINKS, stats.mNumLinks)
- .addTaggedData(MetricsEvent.FIELD_LINKIFY_LINK_LENGTH, stats.mNumLinksTextLength)
- .addTaggedData(MetricsEvent.FIELD_LINKIFY_TEXT_LENGTH, text.length())
- .addTaggedData(MetricsEvent.FIELD_LINKIFY_LATENCY, latencyMs);
- if (entityType != null) {
- log.addTaggedData(MetricsEvent.FIELD_LINKIFY_ENTITY_TYPE, entityType);
- }
- mMetricsLogger.write(log);
- debugLog(log);
- }
-
- private static void debugLog(LogMaker log) {
- if (!Log.ENABLE_FULL_LOGGING) {
- return;
- }
- final String callId = Objects.toString(
- log.getTaggedData(MetricsEvent.FIELD_LINKIFY_CALL_ID), "");
- final String entityType = Objects.toString(
- log.getTaggedData(MetricsEvent.FIELD_LINKIFY_ENTITY_TYPE), "ANY_ENTITY");
- final int numLinks = Integer.parseInt(
- Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_NUM_LINKS), ZERO));
- final int linkLength = Integer.parseInt(
- Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_LINK_LENGTH), ZERO));
- final int textLength = Integer.parseInt(
- Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_TEXT_LENGTH), ZERO));
- final int latencyMs = Integer.parseInt(
- Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_LATENCY), ZERO));
-
- Log.v(LOG_TAG,
- String.format(Locale.US, "%s:%s %d links (%d/%d chars) %dms %s", callId, entityType,
- numLinks, linkLength, textLength, latencyMs, log.getPackageName()));
- }
-
- /** Helper class for storing per-entity type statistics. */
- private static final class LinkifyStats {
- int mNumLinks;
- int mNumLinksTextLength;
-
- void countLink(TextLinks.TextLink link) {
- mNumLinks += 1;
- mNumLinksTextLength += link.getEnd() - link.getStart();
- }
- }
-}
diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java
index 03ed496..98ee09c 100644
--- a/core/java/android/view/textclassifier/Log.java
+++ b/core/java/android/view/textclassifier/Log.java
@@ -32,7 +32,7 @@
* false: Limits logging to debug level.
*/
static final boolean ENABLE_FULL_LOGGING =
- android.util.Log.isLoggable(TextClassifier.DEFAULT_LOG_TAG, android.util.Log.VERBOSE);
+ android.util.Log.isLoggable(TextClassifier.LOG_TAG, android.util.Log.VERBOSE);
private Log() {
}
diff --git a/core/java/android/view/textclassifier/ModelFileManager.java b/core/java/android/view/textclassifier/ModelFileManager.java
deleted file mode 100644
index 0a4ff5d..0000000
--- a/core/java/android/view/textclassifier/ModelFileManager.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * 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 android.view.textclassifier.TextClassifier.DEFAULT_LOG_TAG;
-
-import android.annotation.Nullable;
-import android.os.LocaleList;
-import android.os.ParcelFileDescriptor;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.StringJoiner;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Manages model files that are listed by the model files supplier.
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class ModelFileManager {
- private final Object mLock = new Object();
- private final Supplier<List<ModelFile>> mModelFileSupplier;
-
- private List<ModelFile> mModelFiles;
-
- public ModelFileManager(Supplier<List<ModelFile>> modelFileSupplier) {
- mModelFileSupplier = Objects.requireNonNull(modelFileSupplier);
- }
-
- /**
- * Returns an unmodifiable list of model files listed by the given model files supplier.
- * <p>
- * The result is cached.
- */
- public List<ModelFile> listModelFiles() {
- synchronized (mLock) {
- if (mModelFiles == null) {
- mModelFiles = Collections.unmodifiableList(mModelFileSupplier.get());
- }
- return mModelFiles;
- }
- }
-
- /**
- * Returns the best model file for the given localelist, {@code null} if nothing is found.
- *
- * @param localeList the required locales, use {@code null} if there is no preference.
- */
- public ModelFile findBestModelFile(@Nullable LocaleList localeList) {
- final String languages = localeList == null || localeList.isEmpty()
- ? LocaleList.getDefault().toLanguageTags()
- : localeList.toLanguageTags();
- final List<Locale.LanguageRange> languageRangeList = Locale.LanguageRange.parse(languages);
-
- ModelFile bestModel = null;
- for (ModelFile model : listModelFiles()) {
- if (model.isAnyLanguageSupported(languageRangeList)) {
- if (model.isPreferredTo(bestModel)) {
- bestModel = model;
- }
- }
- }
- return bestModel;
- }
-
- /**
- * Default implementation of the model file supplier.
- */
- public static final class ModelFileSupplierImpl implements Supplier<List<ModelFile>> {
- private final File mUpdatedModelFile;
- private final File mFactoryModelDir;
- private final Pattern mModelFilenamePattern;
- private final Function<Integer, Integer> mVersionSupplier;
- private final Function<Integer, String> mSupportedLocalesSupplier;
-
- public ModelFileSupplierImpl(
- File factoryModelDir,
- String factoryModelFileNameRegex,
- File updatedModelFile,
- Function<Integer, Integer> versionSupplier,
- Function<Integer, String> supportedLocalesSupplier) {
- mUpdatedModelFile = Objects.requireNonNull(updatedModelFile);
- mFactoryModelDir = Objects.requireNonNull(factoryModelDir);
- mModelFilenamePattern = Pattern.compile(
- Objects.requireNonNull(factoryModelFileNameRegex));
- mVersionSupplier = Objects.requireNonNull(versionSupplier);
- mSupportedLocalesSupplier = Objects.requireNonNull(supportedLocalesSupplier);
- }
-
- @Override
- public List<ModelFile> get() {
- final List<ModelFile> modelFiles = new ArrayList<>();
- // The update model has the highest precedence.
- if (mUpdatedModelFile.exists()) {
- final ModelFile updatedModel = createModelFile(mUpdatedModelFile);
- if (updatedModel != null) {
- modelFiles.add(updatedModel);
- }
- }
- // Factory models should never have overlapping locales, so the order doesn't matter.
- if (mFactoryModelDir.exists() && mFactoryModelDir.isDirectory()) {
- final File[] files = mFactoryModelDir.listFiles();
- for (File file : files) {
- final Matcher matcher = mModelFilenamePattern.matcher(file.getName());
- if (matcher.matches() && file.isFile()) {
- final ModelFile model = createModelFile(file);
- if (model != null) {
- modelFiles.add(model);
- }
- }
- }
- }
- return modelFiles;
- }
-
- /** Returns null if the path did not point to a compatible model. */
- @Nullable
- private ModelFile createModelFile(File file) {
- if (!file.exists()) {
- return null;
- }
- ParcelFileDescriptor modelFd = null;
- try {
- modelFd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
- if (modelFd == null) {
- return null;
- }
- final int modelFdInt = modelFd.getFd();
- final int version = mVersionSupplier.apply(modelFdInt);
- final String supportedLocalesStr = mSupportedLocalesSupplier.apply(modelFdInt);
- if (supportedLocalesStr.isEmpty()) {
- Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
- return null;
- }
- final List<Locale> supportedLocales = new ArrayList<>();
- for (String langTag : supportedLocalesStr.split(",")) {
- supportedLocales.add(Locale.forLanguageTag(langTag));
- }
- return new ModelFile(
- file,
- version,
- supportedLocales,
- supportedLocalesStr,
- ModelFile.LANGUAGE_INDEPENDENT.equals(supportedLocalesStr));
- } catch (FileNotFoundException e) {
- Log.e(DEFAULT_LOG_TAG, "Failed to find " + file.getAbsolutePath(), e);
- return null;
- } finally {
- maybeCloseAndLogError(modelFd);
- }
- }
-
- /**
- * Closes the ParcelFileDescriptor, if non-null, and logs any errors that occur.
- */
- private static void maybeCloseAndLogError(@Nullable ParcelFileDescriptor fd) {
- if (fd == null) {
- return;
- }
- try {
- fd.close();
- } catch (IOException e) {
- Log.e(DEFAULT_LOG_TAG, "Error closing file.", e);
- }
- }
-
- }
-
- /**
- * Describes TextClassifier model files on disk.
- */
- public static final class ModelFile {
- public static final String LANGUAGE_INDEPENDENT = "*";
-
- private final File mFile;
- private final int mVersion;
- private final List<Locale> mSupportedLocales;
- private final String mSupportedLocalesStr;
- private final boolean mLanguageIndependent;
-
- public ModelFile(File file, int version, List<Locale> supportedLocales,
- String supportedLocalesStr,
- boolean languageIndependent) {
- mFile = Objects.requireNonNull(file);
- mVersion = version;
- mSupportedLocales = Objects.requireNonNull(supportedLocales);
- mSupportedLocalesStr = Objects.requireNonNull(supportedLocalesStr);
- mLanguageIndependent = languageIndependent;
- }
-
- /** Returns the absolute path to the model file. */
- public String getPath() {
- return mFile.getAbsolutePath();
- }
-
- /** Returns a name to use for id generation, effectively the name of the model file. */
- public String getName() {
- return mFile.getName();
- }
-
- /** Returns the version tag in the model's metadata. */
- public int getVersion() {
- return mVersion;
- }
-
- /** Returns whether the language supports any language in the given ranges. */
- public boolean isAnyLanguageSupported(List<Locale.LanguageRange> languageRanges) {
- Objects.requireNonNull(languageRanges);
- return mLanguageIndependent || Locale.lookup(languageRanges, mSupportedLocales) != null;
- }
-
- /** Returns an immutable lists of supported locales. */
- public List<Locale> getSupportedLocales() {
- return Collections.unmodifiableList(mSupportedLocales);
- }
-
- /** Returns the original supported locals string read from the model file. */
- public String getSupportedLocalesStr() {
- return mSupportedLocalesStr;
- }
-
- /**
- * Returns if this model file is preferred to the given one.
- */
- public boolean isPreferredTo(@Nullable ModelFile model) {
- // A model is preferred to no model.
- if (model == null) {
- return true;
- }
-
- // A language-specific model is preferred to a language independent
- // model.
- if (!mLanguageIndependent && model.mLanguageIndependent) {
- return true;
- }
- if (mLanguageIndependent && !model.mLanguageIndependent) {
- return false;
- }
-
- // A higher-version model is preferred.
- if (mVersion > model.getVersion()) {
- return true;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getPath());
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (other instanceof ModelFile) {
- final ModelFile otherModel = (ModelFile) other;
- return TextUtils.equals(getPath(), otherModel.getPath());
- }
- return false;
- }
-
- @Override
- public String toString() {
- final StringJoiner localesJoiner = new StringJoiner(",");
- for (Locale locale : mSupportedLocales) {
- localesJoiner.add(locale.toLanguageTag());
- }
- return String.format(Locale.US,
- "ModelFile { path=%s name=%s version=%d locales=%s }",
- getPath(), getName(), mVersion, localesJoiner.toString());
- }
- }
-}
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 9a54544..6f9556b 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -158,7 +158,6 @@
mEventType = in.readInt();
mEntityType = in.readString();
mWidgetVersion = in.readInt() > 0 ? in.readString() : null;
- // TODO: remove mPackageName once aiai does not need it
mPackageName = in.readString();
mWidgetType = in.readString();
mInvocationMethod = in.readInt();
@@ -186,7 +185,6 @@
if (mWidgetVersion != null) {
dest.writeString(mWidgetVersion);
}
- // TODO: remove mPackageName once aiai does not need it
dest.writeString(mPackageName);
dest.writeString(mWidgetType);
dest.writeInt(mInvocationMethod);
@@ -406,7 +404,7 @@
*/
@NonNull
public String getPackageName() {
- return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : "";
+ return mPackageName;
}
/**
diff --git a/core/java/android/view/textclassifier/SelectionSessionLogger.java b/core/java/android/view/textclassifier/SelectionSessionLogger.java
index ae9f65b..e7d896e 100644
--- a/core/java/android/view/textclassifier/SelectionSessionLogger.java
+++ b/core/java/android/view/textclassifier/SelectionSessionLogger.java
@@ -16,251 +16,24 @@
package android.view.textclassifier;
-import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.Context;
-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.text.BreakIterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.StringJoiner;
/**
* A helper for logging selection session events.
+ *
* @hide
*/
public final class SelectionSessionLogger {
-
- private static final String LOG_TAG = "SelectionSessionLogger";
- static final String CLASSIFIER_ID = "androidtc";
-
- private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
- private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
- private static final int INDEX = MetricsEvent.FIELD_SELECTION_SESSION_INDEX;
- private static final int WIDGET_TYPE = MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
- private static final int WIDGET_VERSION = MetricsEvent.FIELD_SELECTION_WIDGET_VERSION;
- private static final int MODEL_NAME = MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
- private static final int ENTITY_TYPE = MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
- private static final int SMART_START = MetricsEvent.FIELD_SELECTION_SMART_RANGE_START;
- private static final int SMART_END = MetricsEvent.FIELD_SELECTION_SMART_RANGE_END;
- private static final int EVENT_START = MetricsEvent.FIELD_SELECTION_RANGE_START;
- private static final int EVENT_END = MetricsEvent.FIELD_SELECTION_RANGE_END;
- private static final int SESSION_ID = MetricsEvent.FIELD_SELECTION_SESSION_ID;
-
- private static final String ZERO = "0";
- private static final String UNKNOWN = "unknown";
-
- private final MetricsLogger mMetricsLogger;
-
- public SelectionSessionLogger() {
- mMetricsLogger = new MetricsLogger();
- }
-
- @VisibleForTesting
- public SelectionSessionLogger(@NonNull MetricsLogger metricsLogger) {
- mMetricsLogger = Objects.requireNonNull(metricsLogger);
- }
-
- /** Emits a selection event to the logs. */
- public void writeEvent(@NonNull SelectionEvent event) {
- Objects.requireNonNull(event);
- final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
- .setType(getLogType(event))
- .setSubtype(getLogSubType(event))
- .setPackageName(event.getPackageName())
- .addTaggedData(START_EVENT_DELTA, event.getDurationSinceSessionStart())
- .addTaggedData(PREV_EVENT_DELTA, event.getDurationSincePreviousEvent())
- .addTaggedData(INDEX, event.getEventIndex())
- .addTaggedData(WIDGET_TYPE, event.getWidgetType())
- .addTaggedData(WIDGET_VERSION, event.getWidgetVersion())
- .addTaggedData(ENTITY_TYPE, event.getEntityType())
- .addTaggedData(EVENT_START, event.getStart())
- .addTaggedData(EVENT_END, event.getEnd());
- if (isPlatformLocalTextClassifierSmartSelection(event.getResultId())) {
- // Ensure result id and smart indices are only set for events with smart selection from
- // the platform's textclassifier.
- log.addTaggedData(MODEL_NAME, SignatureParser.getModelName(event.getResultId()))
- .addTaggedData(SMART_START, event.getSmartStart())
- .addTaggedData(SMART_END, event.getSmartEnd());
- }
- if (event.getSessionId() != null) {
- log.addTaggedData(SESSION_ID, event.getSessionId().getValue());
- }
- mMetricsLogger.write(log);
- debugLog(log);
- }
-
- private static int getLogType(SelectionEvent event) {
- switch (event.getEventType()) {
- case SelectionEvent.ACTION_OVERTYPE:
- return MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE;
- case SelectionEvent.ACTION_COPY:
- return MetricsEvent.ACTION_TEXT_SELECTION_COPY;
- case SelectionEvent.ACTION_PASTE:
- return MetricsEvent.ACTION_TEXT_SELECTION_PASTE;
- case SelectionEvent.ACTION_CUT:
- return MetricsEvent.ACTION_TEXT_SELECTION_CUT;
- case SelectionEvent.ACTION_SHARE:
- return MetricsEvent.ACTION_TEXT_SELECTION_SHARE;
- case SelectionEvent.ACTION_SMART_SHARE:
- return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
- case SelectionEvent.ACTION_DRAG:
- return MetricsEvent.ACTION_TEXT_SELECTION_DRAG;
- case SelectionEvent.ACTION_ABANDON:
- return MetricsEvent.ACTION_TEXT_SELECTION_ABANDON;
- case SelectionEvent.ACTION_OTHER:
- return MetricsEvent.ACTION_TEXT_SELECTION_OTHER;
- case SelectionEvent.ACTION_SELECT_ALL:
- return MetricsEvent.ACTION_TEXT_SELECTION_SELECT_ALL;
- case SelectionEvent.ACTION_RESET:
- return MetricsEvent.ACTION_TEXT_SELECTION_RESET;
- case SelectionEvent.EVENT_SELECTION_STARTED:
- return MetricsEvent.ACTION_TEXT_SELECTION_START;
- case SelectionEvent.EVENT_SELECTION_MODIFIED:
- return MetricsEvent.ACTION_TEXT_SELECTION_MODIFY;
- case SelectionEvent.EVENT_SMART_SELECTION_SINGLE:
- return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SINGLE;
- case SelectionEvent.EVENT_SMART_SELECTION_MULTI:
- return MetricsEvent.ACTION_TEXT_SELECTION_SMART_MULTI;
- case SelectionEvent.EVENT_AUTO_SELECTION:
- return MetricsEvent.ACTION_TEXT_SELECTION_AUTO;
- default:
- return MetricsEvent.VIEW_UNKNOWN;
- }
- }
-
- private static int getLogSubType(SelectionEvent event) {
- switch (event.getInvocationMethod()) {
- case SelectionEvent.INVOCATION_MANUAL:
- return MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL;
- case SelectionEvent.INVOCATION_LINK:
- return MetricsEvent.TEXT_SELECTION_INVOCATION_LINK;
- default:
- return MetricsEvent.TEXT_SELECTION_INVOCATION_UNKNOWN;
- }
- }
-
- private static String getLogTypeString(int logType) {
- switch (logType) {
- case MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE:
- return "OVERTYPE";
- case MetricsEvent.ACTION_TEXT_SELECTION_COPY:
- return "COPY";
- case MetricsEvent.ACTION_TEXT_SELECTION_PASTE:
- return "PASTE";
- case MetricsEvent.ACTION_TEXT_SELECTION_CUT:
- return "CUT";
- case MetricsEvent.ACTION_TEXT_SELECTION_SHARE:
- return "SHARE";
- case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE:
- return "SMART_SHARE";
- case MetricsEvent.ACTION_TEXT_SELECTION_DRAG:
- return "DRAG";
- case MetricsEvent.ACTION_TEXT_SELECTION_ABANDON:
- return "ABANDON";
- case MetricsEvent.ACTION_TEXT_SELECTION_OTHER:
- return "OTHER";
- case MetricsEvent.ACTION_TEXT_SELECTION_SELECT_ALL:
- return "SELECT_ALL";
- case MetricsEvent.ACTION_TEXT_SELECTION_RESET:
- return "RESET";
- case MetricsEvent.ACTION_TEXT_SELECTION_START:
- return "SELECTION_STARTED";
- case MetricsEvent.ACTION_TEXT_SELECTION_MODIFY:
- return "SELECTION_MODIFIED";
- case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SINGLE:
- return "SMART_SELECTION_SINGLE";
- case MetricsEvent.ACTION_TEXT_SELECTION_SMART_MULTI:
- return "SMART_SELECTION_MULTI";
- case MetricsEvent.ACTION_TEXT_SELECTION_AUTO:
- return "AUTO_SELECTION";
- default:
- return UNKNOWN;
- }
- }
-
- private static String getLogSubTypeString(int logSubType) {
- switch (logSubType) {
- case MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL:
- return "MANUAL";
- case MetricsEvent.TEXT_SELECTION_INVOCATION_LINK:
- return "LINK";
- default:
- return UNKNOWN;
- }
- }
+ // Keep this in sync with the ResultIdUtils in libtextclassifier.
+ private static final String CLASSIFIER_ID = "androidtc";
static boolean isPlatformLocalTextClassifierSmartSelection(String signature) {
return SelectionSessionLogger.CLASSIFIER_ID.equals(
SelectionSessionLogger.SignatureParser.getClassifierId(signature));
}
- private static void debugLog(LogMaker log) {
- if (!Log.ENABLE_FULL_LOGGING) {
- return;
- }
- final String widgetType = Objects.toString(log.getTaggedData(WIDGET_TYPE), UNKNOWN);
- final String widgetVersion = Objects.toString(log.getTaggedData(WIDGET_VERSION), "");
- final String widget = widgetVersion.isEmpty()
- ? widgetType : widgetType + "-" + widgetVersion;
- final int index = Integer.parseInt(Objects.toString(log.getTaggedData(INDEX), ZERO));
- if (log.getType() == MetricsEvent.ACTION_TEXT_SELECTION_START) {
- String sessionId = Objects.toString(log.getTaggedData(SESSION_ID), "");
- sessionId = sessionId.substring(sessionId.lastIndexOf("-") + 1);
- Log.d(LOG_TAG, String.format("New selection session: %s (%s)", widget, sessionId));
- }
-
- final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
- final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
- final String type = getLogTypeString(log.getType());
- final String subType = getLogSubTypeString(log.getSubtype());
- final int smartStart = Integer.parseInt(
- Objects.toString(log.getTaggedData(SMART_START), ZERO));
- final int smartEnd = Integer.parseInt(
- Objects.toString(log.getTaggedData(SMART_END), ZERO));
- final int eventStart = Integer.parseInt(
- Objects.toString(log.getTaggedData(EVENT_START), ZERO));
- final int eventEnd = Integer.parseInt(
- Objects.toString(log.getTaggedData(EVENT_END), ZERO));
-
- Log.v(LOG_TAG,
- String.format(Locale.US, "%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
- index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd,
- widget, model));
- }
-
- /**
- * Returns a token iterator for tokenizing text for logging purposes.
- */
- public static BreakIterator getTokenIterator(@NonNull Locale locale) {
- return BreakIterator.getWordInstance(Objects.requireNonNull(locale));
- }
-
- /**
- * Creates a string id that may be used to identify a TextClassifier result.
- */
- public static String createId(
- String text, int start, int end, Context context, int modelVersion,
- List<Locale> locales) {
- Objects.requireNonNull(text);
- Objects.requireNonNull(context);
- Objects.requireNonNull(locales);
- final StringJoiner localesJoiner = new StringJoiner(",");
- for (Locale locale : locales) {
- localesJoiner.add(locale.toLanguageTag());
- }
- final String modelName = String.format(Locale.US, "%s_v%d", localesJoiner.toString(),
- modelVersion);
- final int hash = Objects.hash(text, start, end, context.getPackageName());
- return SignatureParser.createSignature(CLASSIFIER_ID, modelName, hash);
- }
-
/**
* Helper for creating and parsing string ids for
* {@link android.view.textclassifier.TextClassifierImpl}.
@@ -268,10 +41,6 @@
@VisibleForTesting
public static final class SignatureParser {
- static String createSignature(String classifierId, String modelName, int hash) {
- return String.format(Locale.US, "%s|%s|%d", classifierId, modelName, hash);
- }
-
static String getClassifierId(@Nullable String signature) {
if (signature == null) {
return "";
@@ -282,29 +51,5 @@
}
return "";
}
-
- static String getModelName(@Nullable String signature) {
- if (signature == null) {
- return "";
- }
- final int start = signature.indexOf("|") + 1;
- final int end = signature.indexOf("|", start);
- if (start >= 1 && end >= start) {
- return signature.substring(start, end);
- }
- return "";
- }
-
- static int getHash(@Nullable String signature) {
- if (signature == null) {
- return 0;
- }
- final int index1 = signature.indexOf("|");
- final int index2 = signature.indexOf("|", index1);
- if (index2 > 0) {
- return Integer.parseInt(signature.substring(index2));
- }
- return 0;
- }
}
}
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 86ef4e1..8eac1c1 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -45,7 +45,7 @@
@VisibleForTesting(visibility = Visibility.PACKAGE)
public final class SystemTextClassifier implements TextClassifier {
- private static final String LOG_TAG = "SystemTextClassifier";
+ private static final String LOG_TAG = TextClassifier.LOG_TAG;
private final ITextClassifierService mManagerService;
private final TextClassificationConstants mSettings;
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 8b9d129..3aed32a 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -44,8 +44,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import com.google.android.textclassifier.AnnotatorModel;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.ZonedDateTime;
@@ -327,9 +325,6 @@
@NonNull private List<RemoteAction> mActions = new ArrayList<>();
@NonNull private final Map<String, Float> mTypeScoreMap = new ArrayMap<>();
- @NonNull
- private final Map<String, AnnotatorModel.ClassificationResult> mClassificationResults =
- new ArrayMap<>();
@Nullable private String mText;
@Nullable private Drawable mLegacyIcon;
@Nullable private String mLegacyLabel;
@@ -362,36 +357,7 @@
public Builder setEntityType(
@NonNull @EntityType String type,
@FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
- setEntityType(type, confidenceScore, null);
- return this;
- }
-
- /**
- * @see #setEntityType(String, float)
- *
- * @hide
- */
- @NonNull
- public Builder setEntityType(AnnotatorModel.ClassificationResult classificationResult) {
- setEntityType(
- classificationResult.getCollection(),
- classificationResult.getScore(),
- classificationResult);
- return this;
- }
-
- /**
- * @see #setEntityType(String, float)
- *
- * @hide
- */
- @NonNull
- private Builder setEntityType(
- @NonNull @EntityType String type,
- @FloatRange(from = 0.0, to = 1.0) float confidenceScore,
- @Nullable AnnotatorModel.ClassificationResult classificationResult) {
mTypeScoreMap.put(type, confidenceScore);
- mClassificationResults.put(type, classificationResult);
return this;
}
@@ -517,25 +483,7 @@
EntityConfidence entityConfidence = new EntityConfidence(mTypeScoreMap);
return new TextClassification(mText, mLegacyIcon, mLegacyLabel, mLegacyIntent,
mLegacyOnClickListener, mActions, entityConfidence, mId,
- buildExtras(entityConfidence));
- }
-
- private Bundle buildExtras(EntityConfidence entityConfidence) {
- final Bundle extras = mExtras == null ? new Bundle() : mExtras;
- if (mActionIntents.stream().anyMatch(Objects::nonNull)) {
- ExtrasUtils.putActionsIntents(extras, mActionIntents);
- }
- if (mForeignLanguageExtra != null) {
- ExtrasUtils.putForeignLanguageExtra(extras, mForeignLanguageExtra);
- }
- List<String> sortedTypes = entityConfidence.getEntities();
- ArrayList<AnnotatorModel.ClassificationResult> sortedEntities = new ArrayList<>();
- for (String type : sortedTypes) {
- sortedEntities.add(mClassificationResults.get(type));
- }
- ExtrasUtils.putEntities(
- extras, sortedEntities.toArray(new AnnotatorModel.ClassificationResult[0]));
- return extras.isEmpty() ? Bundle.EMPTY : extras;
+ mExtras == null ? Bundle.EMPTY : mExtras);
}
}
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 3d5ac58..adb6fea 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -17,16 +17,11 @@
package android.view.textclassifier;
import android.annotation.Nullable;
-import android.content.Context;
import android.provider.DeviceConfig;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
/**
* TextClassifier specific settings.
*
@@ -41,8 +36,6 @@
*/
// TODO: Rename to TextClassifierSettings.
public final class TextClassificationConstants {
- private static final String DELIMITER = ":";
-
/**
* Whether the smart linkify feature is enabled.
*/
@@ -60,7 +53,6 @@
* Enable smart selection without a visible UI changes.
*/
private static final String MODEL_DARK_LAUNCH_ENABLED = "model_dark_launch_enabled";
-
/**
* Whether the smart selection feature is enabled.
*/
@@ -75,88 +67,10 @@
private static final String SMART_SELECT_ANIMATION_ENABLED =
"smart_select_animation_enabled";
/**
- * Max length of text that suggestSelection can accept.
- */
- @VisibleForTesting
- static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
- "suggest_selection_max_range_length";
- /**
- * Max length of text that classifyText can accept.
- */
- private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH = "classify_text_max_range_length";
- /**
* Max length of text that generateLinks can accept.
*/
- private static final String GENERATE_LINKS_MAX_TEXT_LENGTH = "generate_links_max_text_length";
- /**
- * Sampling rate for generateLinks logging.
- */
- private static final String GENERATE_LINKS_LOG_SAMPLE_RATE =
- "generate_links_log_sample_rate";
- /**
- * A colon(:) separated string that specifies the default entities types for
- * generateLinks when hint is not given.
- */
@VisibleForTesting
- static final String ENTITY_LIST_DEFAULT = "entity_list_default";
- /**
- * A colon(:) separated string that specifies the default entities types for
- * generateLinks when the text is in a not editable UI widget.
- */
- private static final String ENTITY_LIST_NOT_EDITABLE = "entity_list_not_editable";
- /**
- * A colon(:) separated string that specifies the default entities types for
- * generateLinks when the text is in an editable UI widget.
- */
- private static final String ENTITY_LIST_EDITABLE = "entity_list_editable";
- /**
- * A colon(:) separated string that specifies the default action types for
- * suggestConversationActions when the suggestions are used in an app.
- */
- private static final String IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT =
- "in_app_conversation_action_types_default";
- /**
- * A colon(:) separated string that specifies the default action types for
- * suggestConversationActions when the suggestions are used in a notification.
- */
- private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT =
- "notification_conversation_action_types_default";
- /**
- * Threshold to accept a suggested language from LangID model.
- */
- @VisibleForTesting
- static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override";
- /**
- * Whether to enable {@link android.view.textclassifier.TemplateIntentFactory}.
- */
- private static final String TEMPLATE_INTENT_FACTORY_ENABLED = "template_intent_factory_enabled";
- /**
- * Whether to enable "translate" action in classifyText.
- */
- private static final String TRANSLATE_IN_CLASSIFICATION_ENABLED =
- "translate_in_classification_enabled";
- /**
- * Whether to detect the languages of the text in request by using langId for the native
- * model.
- */
- private static final String DETECT_LANGUAGES_FROM_TEXT_ENABLED =
- "detect_languages_from_text_enabled";
- /**
- * A colon(:) separated string that specifies the configuration to use when including
- * surrounding context text in language detection queries.
- * <p>
- * Format= minimumTextSize<int>:penalizeRatio<float>:textScoreRatio<float>
- * <p>
- * e.g. 20:1.0:0.4
- * <p>
- * Accept all text lengths with minimumTextSize=0
- * <p>
- * Reject all text less than minimumTextSize with penalizeRatio=0
- * @see {@code TextClassifierImpl#detectLanguages(String, int, int)} for reference.
- */
- @VisibleForTesting
- static final String LANG_ID_CONTEXT_SETTINGS = "lang_id_context_settings";
-
+ static final String GENERATE_LINKS_MAX_TEXT_LENGTH = "generate_links_max_text_length";
/**
* The TextClassifierService which would like to use. Example of setting the package:
* <pre>
@@ -168,16 +82,6 @@
static final String TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE =
"textclassifier_service_package_override";
- /**
- * Whether to use the default system text classifier as the default text classifier
- * implementation. The local text classifier is used if it is {@code false}.
- *
- * @see android.service.textclassifier.TextClassifierService#getDefaultTextClassifierImplementation(Context)
- */
- // TODO: Once the system health experiment is done, remove this together with local TC.
- private static final String USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL =
- "use_default_system_text_classifier_as_default_impl";
-
private static final String DEFAULT_TEXT_CLASSIFIER_SERVICE_PACKAGE_OVERRIDE = null;
private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -186,42 +90,7 @@
private static final boolean SMART_TEXT_SHARE_ENABLED_DEFAULT = true;
private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
private static final boolean SMART_SELECT_ANIMATION_ENABLED_DEFAULT = true;
- private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
- private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
- private static final int GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT = 100;
- private static final List<String> ENTITY_LIST_DEFAULT_VALUE = Arrays.asList(
- TextClassifier.TYPE_ADDRESS,
- TextClassifier.TYPE_EMAIL,
- TextClassifier.TYPE_PHONE,
- TextClassifier.TYPE_URL,
- TextClassifier.TYPE_DATE,
- TextClassifier.TYPE_DATE_TIME,
- TextClassifier.TYPE_FLIGHT_NUMBER);
- private static final List<String> CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES = Arrays.asList(
- ConversationAction.TYPE_TEXT_REPLY,
- ConversationAction.TYPE_CREATE_REMINDER,
- ConversationAction.TYPE_CALL_PHONE,
- ConversationAction.TYPE_OPEN_URL,
- ConversationAction.TYPE_SEND_EMAIL,
- ConversationAction.TYPE_SEND_SMS,
- ConversationAction.TYPE_TRACK_FLIGHT,
- ConversationAction.TYPE_VIEW_CALENDAR,
- ConversationAction.TYPE_VIEW_MAP,
- ConversationAction.TYPE_ADD_CONTACT,
- ConversationAction.TYPE_COPY);
- /**
- * < 0 : Not set. Use value from LangId model.
- * 0 - 1: Override value in LangId model.
- *
- * @see EntityConfidence
- */
- private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f;
- private static final boolean TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT = true;
- private static final boolean TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT = true;
- private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
- private static final float[] LANG_ID_CONTEXT_SETTINGS_DEFAULT = new float[]{20f, 1.0f, 0.4f};
- private static final boolean USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL_DEFAULT = true;
@Nullable
public String getTextClassifierServicePackageOverride() {
@@ -266,119 +135,20 @@
SMART_SELECT_ANIMATION_ENABLED, SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
}
- public int getSuggestSelectionMaxRangeLength() {
- return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- SUGGEST_SELECTION_MAX_RANGE_LENGTH, SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
- }
-
- public int getClassifyTextMaxRangeLength() {
- return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- CLASSIFY_TEXT_MAX_RANGE_LENGTH, CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
- }
-
public int getGenerateLinksMaxTextLength() {
return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
GENERATE_LINKS_MAX_TEXT_LENGTH, GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
}
- public int getGenerateLinksLogSampleRate() {
- return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- GENERATE_LINKS_LOG_SAMPLE_RATE, GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
- }
-
- public List<String> getEntityListDefault() {
- return getDeviceConfigStringList(ENTITY_LIST_DEFAULT, ENTITY_LIST_DEFAULT_VALUE);
- }
-
- public List<String> getEntityListNotEditable() {
- return getDeviceConfigStringList(ENTITY_LIST_NOT_EDITABLE, ENTITY_LIST_DEFAULT_VALUE);
- }
-
- public List<String> getEntityListEditable() {
- return getDeviceConfigStringList(ENTITY_LIST_EDITABLE, ENTITY_LIST_DEFAULT_VALUE);
- }
-
- public List<String> getInAppConversationActionTypes() {
- return getDeviceConfigStringList(
- IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
- CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
- }
-
- public List<String> getNotificationConversationActionTypes() {
- return getDeviceConfigStringList(
- NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
- CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES);
- }
-
- public float getLangIdThresholdOverride() {
- return DeviceConfig.getFloat(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- LANG_ID_THRESHOLD_OVERRIDE,
- LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
- }
-
- public boolean isTemplateIntentFactoryEnabled() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- TEMPLATE_INTENT_FACTORY_ENABLED,
- TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
- }
-
- public boolean isTranslateInClassificationEnabled() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- TRANSLATE_IN_CLASSIFICATION_ENABLED,
- TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
- }
-
- public boolean isDetectLanguagesFromTextEnabled() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- DETECT_LANGUAGES_FROM_TEXT_ENABLED,
- DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
- }
-
- public float[] getLangIdContextSettings() {
- return getDeviceConfigFloatArray(
- LANG_ID_CONTEXT_SETTINGS, LANG_ID_CONTEXT_SETTINGS_DEFAULT);
- }
-
- public boolean getUseDefaultTextClassifierAsDefaultImplementation() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL,
- USE_DEFAULT_SYSTEM_TEXT_CLASSIFIER_AS_DEFAULT_IMPL_DEFAULT);
- }
-
void dump(IndentingPrintWriter pw) {
pw.println("TextClassificationConstants:");
pw.increaseIndent();
- pw.printPair("classify_text_max_range_length", getClassifyTextMaxRangeLength())
- .println();
- pw.printPair("detect_languages_from_text_enabled", isDetectLanguagesFromTextEnabled())
- .println();
- pw.printPair("entity_list_default", getEntityListDefault())
- .println();
- pw.printPair("entity_list_editable", getEntityListEditable())
- .println();
- pw.printPair("entity_list_not_editable", getEntityListNotEditable())
- .println();
- pw.printPair("generate_links_log_sample_rate", getGenerateLinksLogSampleRate())
- .println();
pw.printPair("generate_links_max_text_length", getGenerateLinksMaxTextLength())
.println();
- pw.printPair("in_app_conversation_action_types_default", getInAppConversationActionTypes())
- .println();
- pw.printPair("lang_id_context_settings", Arrays.toString(getLangIdContextSettings()))
- .println();
- pw.printPair("lang_id_threshold_override", getLangIdThresholdOverride())
- .println();
pw.printPair("local_textclassifier_enabled", isLocalTextClassifierEnabled())
.println();
pw.printPair("model_dark_launch_enabled", isModelDarkLaunchEnabled())
.println();
- pw.printPair("notification_conversation_action_types_default",
- getNotificationConversationActionTypes()).println();
pw.printPair("smart_linkify_enabled", isSmartLinkifyEnabled())
.println();
pw.printPair("smart_select_animation_enabled", isSmartSelectionAnimationEnabled())
@@ -387,57 +157,10 @@
.println();
pw.printPair("smart_text_share_enabled", isSmartTextShareEnabled())
.println();
- pw.printPair("suggest_selection_max_range_length", getSuggestSelectionMaxRangeLength())
- .println();
pw.printPair("system_textclassifier_enabled", isSystemTextClassifierEnabled())
.println();
- pw.printPair("template_intent_factory_enabled", isTemplateIntentFactoryEnabled())
- .println();
- pw.printPair("translate_in_classification_enabled", isTranslateInClassificationEnabled())
- .println();
pw.printPair("textclassifier_service_package_override",
getTextClassifierServicePackageOverride()).println();
- pw.printPair("use_default_system_text_classifier_as_default_impl",
- getUseDefaultTextClassifierAsDefaultImplementation()).println();
pw.decreaseIndent();
}
-
- private static List<String> getDeviceConfigStringList(String key, List<String> defaultValue) {
- return parse(
- DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
- defaultValue);
- }
-
- private static float[] getDeviceConfigFloatArray(String key, float[] defaultValue) {
- return parse(
- DeviceConfig.getString(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key, null),
- defaultValue);
- }
-
- private static List<String> parse(@Nullable String listStr, List<String> defaultValue) {
- if (listStr != null) {
- return Collections.unmodifiableList(Arrays.asList(listStr.split(DELIMITER)));
- }
- return defaultValue;
- }
-
- private static float[] parse(@Nullable String arrayStr, float[] defaultValue) {
- if (arrayStr != null) {
- final String[] split = arrayStr.split(DELIMITER);
- if (split.length != defaultValue.length) {
- return defaultValue;
- }
- final float[] result = new float[split.length];
- for (int i = 0; i < split.length; i++) {
- try {
- result[i] = Float.parseFloat(split[i]);
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
- return result;
- } else {
- return defaultValue;
- }
- }
}
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index dfbec9b..fa4f7d6 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -19,21 +19,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
-import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.ServiceManager;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
import android.view.textclassifier.TextClassifier.TextClassifierType;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
-import java.lang.ref.WeakReference;
import java.util.Objects;
-import java.util.Set;
/**
* Interface to the text classification service.
@@ -41,7 +35,7 @@
@SystemService(Context.TEXT_CLASSIFICATION_SERVICE)
public final class TextClassificationManager {
- private static final String LOG_TAG = "TextClassificationManager";
+ private static final String LOG_TAG = TextClassifier.LOG_TAG;
private static final TextClassificationConstants sDefaultSettings =
new TextClassificationConstants();
@@ -52,15 +46,11 @@
classificationContext, getTextClassifier());
private final Context mContext;
- private final SettingsObserver mSettingsObserver;
@GuardedBy("mLock")
@Nullable
private TextClassifier mCustomTextClassifier;
@GuardedBy("mLock")
- @Nullable
- private TextClassifier mLocalTextClassifier;
- @GuardedBy("mLock")
private TextClassificationSessionFactory mSessionFactory;
@GuardedBy("mLock")
private TextClassificationConstants mSettings;
@@ -69,7 +59,6 @@
public TextClassificationManager(Context context) {
mContext = Objects.requireNonNull(context);
mSessionFactory = mDefaultSessionFactory;
- mSettingsObserver = new SettingsObserver(this);
}
/**
@@ -112,7 +101,7 @@
*
* @see TextClassifier#LOCAL
* @see TextClassifier#SYSTEM
- * @see TextClassifier#DEFAULT_SERVICE
+ * @see TextClassifier#DEFAULT_SYSTEM
* @hide
*/
@UnsupportedAppUsage
@@ -189,28 +178,17 @@
}
}
- @Override
- protected void finalize() throws Throwable {
- try {
- // Note that fields could be null if the constructor threw.
- if (mSettingsObserver != null) {
- DeviceConfig.removeOnPropertiesChangedListener(mSettingsObserver);
- }
- } finally {
- super.finalize();
- }
- }
-
/** @hide */
private TextClassifier getSystemTextClassifier(@TextClassifierType int type) {
synchronized (mLock) {
if (getSettings().isSystemTextClassifierEnabled()) {
try {
- Log.d(LOG_TAG, "Initializing SystemTextClassifier, type = " + type);
+ Log.d(LOG_TAG, "Initializing SystemTextClassifier, type = "
+ + TextClassifier.typeToString(type));
return new SystemTextClassifier(
mContext,
getSettings(),
- /* useDefault= */ type == TextClassifier.DEFAULT_SERVICE);
+ /* useDefault= */ type == TextClassifier.DEFAULT_SYSTEM);
} catch (ServiceManager.ServiceNotFoundException e) {
Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e);
}
@@ -224,49 +202,13 @@
*/
@NonNull
private TextClassifier getLocalTextClassifier() {
- synchronized (mLock) {
- if (mLocalTextClassifier == null) {
- if (getSettings().isLocalTextClassifierEnabled()) {
- mLocalTextClassifier =
- new TextClassifierImpl(mContext, getSettings(), TextClassifier.NO_OP);
- } else {
- Log.d(LOG_TAG, "Local TextClassifier disabled");
- mLocalTextClassifier = TextClassifier.NO_OP;
- }
- }
- return mLocalTextClassifier;
- }
- }
-
- /** @hide */
- @VisibleForTesting
- public void invalidateForTesting() {
- invalidate();
- }
-
- private void invalidate() {
- synchronized (mLock) {
- mSettings = null;
- invalidateTextClassifiers();
- }
- }
-
- private void invalidateTextClassifiers() {
- synchronized (mLock) {
- mLocalTextClassifier = null;
- }
- }
-
- Context getApplicationContext() {
- return mContext.getApplicationContext() != null
- ? mContext.getApplicationContext()
- : mContext;
+ Log.d(LOG_TAG, "Local text-classifier not supported. Returning a no-op text-classifier.");
+ return TextClassifier.NO_OP;
}
/** @hide **/
public void dump(IndentingPrintWriter pw) {
- getLocalTextClassifier().dump(pw);
- getSystemTextClassifier(TextClassifier.DEFAULT_SERVICE).dump(pw);
+ getSystemTextClassifier(TextClassifier.DEFAULT_SYSTEM).dump(pw);
getSystemTextClassifier(TextClassifier.SYSTEM).dump(pw);
getSettings().dump(pw);
}
@@ -283,31 +225,4 @@
return sDefaultSettings;
}
}
-
- private static final class SettingsObserver implements
- DeviceConfig.OnPropertiesChangedListener {
-
- private final WeakReference<TextClassificationManager> mTcm;
-
- SettingsObserver(TextClassificationManager tcm) {
- mTcm = new WeakReference<>(tcm);
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- ActivityThread.currentApplication().getMainExecutor(),
- this);
- }
-
- @Override
- public void onPropertiesChanged(Properties properties) {
- final TextClassificationManager tcm = mTcm.get();
- if (tcm != null) {
- final Set<String> keys = properties.getKeyset();
- if (keys.contains(TextClassificationConstants.SYSTEM_TEXT_CLASSIFIER_ENABLED)
- || keys.contains(
- TextClassificationConstants.LOCAL_TEXT_CLASSIFIER_ENABLED)) {
- tcm.invalidateTextClassifiers();
- }
- }
- }
- }
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 2cc226d..6d5077a 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -61,19 +61,32 @@
public interface TextClassifier {
/** @hide */
- String DEFAULT_LOG_TAG = "androidtc";
+ String LOG_TAG = "androidtc";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {LOCAL, SYSTEM, DEFAULT_SERVICE})
+ @IntDef(value = {LOCAL, SYSTEM, DEFAULT_SYSTEM})
@interface TextClassifierType {} // TODO: Expose as system APIs.
/** Specifies a TextClassifier that runs locally in the app's process. @hide */
int LOCAL = 0;
/** Specifies a TextClassifier that runs in the system process and serves all apps. @hide */
int SYSTEM = 1;
/** Specifies the default TextClassifier that runs in the system process. @hide */
- int DEFAULT_SERVICE = 2;
+ int DEFAULT_SYSTEM = 2;
+
+ /** @hide */
+ static String typeToString(@TextClassifierType int type) {
+ switch (type) {
+ case LOCAL:
+ return "Local";
+ case SYSTEM:
+ return "System";
+ case DEFAULT_SYSTEM:
+ return "Default system";
+ }
+ return "Unknown";
+ }
/** The TextClassifier failed to run. */
String TYPE_UNKNOWN = "";
@@ -776,7 +789,7 @@
static void checkMainThread() {
if (Looper.myLooper() == Looper.getMainLooper()) {
- Log.w(DEFAULT_LOG_TAG, "TextClassifier called on main thread");
+ Log.w(LOG_TAG, "TextClassifier called on main thread");
}
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
deleted file mode 100644
index 8162699..0000000
--- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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());
- }
-}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
deleted file mode 100644
index d7149ee..0000000
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * Copyright (C) 2017 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.NonNull;
-import android.annotation.Nullable;
-import android.annotation.WorkerThread;
-import android.app.RemoteAction;
-import android.content.Context;
-import android.content.Intent;
-import android.icu.util.ULocale;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.os.ParcelFileDescriptor;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.view.textclassifier.ActionsModelParamsSupplier.ActionsModelParams;
-import android.view.textclassifier.intent.ClassificationIntentFactory;
-import android.view.textclassifier.intent.LabeledIntent;
-import android.view.textclassifier.intent.LegacyClassificationIntentFactory;
-import android.view.textclassifier.intent.TemplateClassificationIntentFactory;
-import android.view.textclassifier.intent.TemplateIntentFactory;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
-
-import com.google.android.textclassifier.ActionsSuggestionsModel;
-import com.google.android.textclassifier.AnnotatorModel;
-import com.google.android.textclassifier.LangIdModel;
-import com.google.android.textclassifier.LangIdModel.LanguageResult;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.time.Instant;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.Supplier;
-
-/**
- * Default implementation of the {@link TextClassifier} interface.
- *
- * <p>This class uses machine learning to recognize entities in text.
- * Unless otherwise stated, methods of this class are blocking operations and should most
- * likely not be called on the UI thread.
- *
- * @hide
- */
-public final class TextClassifierImpl implements TextClassifier {
-
- private static final String LOG_TAG = DEFAULT_LOG_TAG;
-
- private static final boolean DEBUG = false;
-
- private static final File FACTORY_MODEL_DIR = new File("/etc/textclassifier/");
- // Annotator
- private static final String ANNOTATOR_FACTORY_MODEL_FILENAME_REGEX =
- "textclassifier\\.(.*)\\.model";
- private static final File ANNOTATOR_UPDATED_MODEL_FILE =
- new File("/data/misc/textclassifier/textclassifier.model");
-
- // LangID
- private static final String LANG_ID_FACTORY_MODEL_FILENAME_REGEX = "lang_id.model";
- private static final File UPDATED_LANG_ID_MODEL_FILE =
- new File("/data/misc/textclassifier/lang_id.model");
-
- // Actions
- private static final String ACTIONS_FACTORY_MODEL_FILENAME_REGEX =
- "actions_suggestions\\.(.*)\\.model";
- private static final File UPDATED_ACTIONS_MODEL =
- new File("/data/misc/textclassifier/actions_suggestions.model");
-
- private final Context mContext;
- private final TextClassifier mFallback;
- private final GenerateLinksLogger mGenerateLinksLogger;
-
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private ModelFileManager.ModelFile mAnnotatorModelInUse;
- @GuardedBy("mLock")
- private AnnotatorModel mAnnotatorImpl;
-
- @GuardedBy("mLock")
- private ModelFileManager.ModelFile mLangIdModelInUse;
- @GuardedBy("mLock")
- private LangIdModel mLangIdImpl;
-
- @GuardedBy("mLock")
- private ModelFileManager.ModelFile mActionModelInUse;
- @GuardedBy("mLock")
- private ActionsSuggestionsModel mActionsImpl;
-
- private final SelectionSessionLogger mSessionLogger = new SelectionSessionLogger();
- private final TextClassifierEventTronLogger mTextClassifierEventTronLogger =
- new TextClassifierEventTronLogger();
-
- private final TextClassificationConstants mSettings;
-
- private final ModelFileManager mAnnotatorModelFileManager;
- private final ModelFileManager mLangIdModelFileManager;
- private final ModelFileManager mActionsModelFileManager;
-
- private final ClassificationIntentFactory mClassificationIntentFactory;
- private final TemplateIntentFactory mTemplateIntentFactory;
- private final Supplier<ActionsModelParams> mActionsModelParamsSupplier;
-
- public TextClassifierImpl(
- Context context, TextClassificationConstants settings, TextClassifier fallback) {
- mContext = Objects.requireNonNull(context);
- mFallback = Objects.requireNonNull(fallback);
- mSettings = Objects.requireNonNull(settings);
- mGenerateLinksLogger = new GenerateLinksLogger(mSettings.getGenerateLinksLogSampleRate());
- mAnnotatorModelFileManager = new ModelFileManager(
- new ModelFileManager.ModelFileSupplierImpl(
- FACTORY_MODEL_DIR,
- ANNOTATOR_FACTORY_MODEL_FILENAME_REGEX,
- ANNOTATOR_UPDATED_MODEL_FILE,
- AnnotatorModel::getVersion,
- AnnotatorModel::getLocales));
- mLangIdModelFileManager = new ModelFileManager(
- new ModelFileManager.ModelFileSupplierImpl(
- FACTORY_MODEL_DIR,
- LANG_ID_FACTORY_MODEL_FILENAME_REGEX,
- UPDATED_LANG_ID_MODEL_FILE,
- LangIdModel::getVersion,
- fd -> ModelFileManager.ModelFile.LANGUAGE_INDEPENDENT));
- mActionsModelFileManager = new ModelFileManager(
- new ModelFileManager.ModelFileSupplierImpl(
- FACTORY_MODEL_DIR,
- ACTIONS_FACTORY_MODEL_FILENAME_REGEX,
- UPDATED_ACTIONS_MODEL,
- ActionsSuggestionsModel::getVersion,
- ActionsSuggestionsModel::getLocales));
-
- mTemplateIntentFactory = new TemplateIntentFactory();
- mClassificationIntentFactory = mSettings.isTemplateIntentFactoryEnabled()
- ? new TemplateClassificationIntentFactory(
- mTemplateIntentFactory, new LegacyClassificationIntentFactory())
- : new LegacyClassificationIntentFactory();
- mActionsModelParamsSupplier = new ActionsModelParamsSupplier(mContext,
- () -> {
- synchronized (mLock) {
- // Clear mActionsImpl here, so that we will create a new
- // ActionsSuggestionsModel object with the new flag in the next request.
- mActionsImpl = null;
- mActionModelInUse = null;
- }
- });
- }
-
- public TextClassifierImpl(Context context, TextClassificationConstants settings) {
- this(context, settings, TextClassifier.NO_OP);
- }
-
- /** @inheritDoc */
- @Override
- @WorkerThread
- public TextSelection suggestSelection(TextSelection.Request request) {
- Objects.requireNonNull(request);
- Utils.checkMainThread();
- try {
- final int rangeLength = request.getEndIndex() - request.getStartIndex();
- final String string = request.getText().toString();
- if (string.length() > 0
- && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
- final String localesString = concatenateLocales(request.getDefaultLocales());
- final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
- final ZonedDateTime refTime = ZonedDateTime.now();
- final AnnotatorModel annotatorImpl = getAnnotatorImpl(request.getDefaultLocales());
- final int start;
- final int end;
- if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
- start = request.getStartIndex();
- end = request.getEndIndex();
- } else {
- final int[] startEnd = annotatorImpl.suggestSelection(
- string, request.getStartIndex(), request.getEndIndex(),
- new AnnotatorModel.SelectionOptions(localesString, detectLanguageTags));
- start = startEnd[0];
- end = startEnd[1];
- }
- if (start < end
- && start >= 0 && end <= string.length()
- && start <= request.getStartIndex() && end >= request.getEndIndex()) {
- final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
- final AnnotatorModel.ClassificationResult[] results =
- annotatorImpl.classifyText(
- string, start, end,
- new AnnotatorModel.ClassificationOptions(
- refTime.toInstant().toEpochMilli(),
- refTime.getZone().getId(),
- localesString,
- detectLanguageTags),
- // Passing null here to suppress intent generation
- // TODO: Use an explicit flag to suppress it.
- /* appContext */ null,
- /* deviceLocales */null);
- final int size = results.length;
- for (int i = 0; i < size; i++) {
- tsBuilder.setEntityType(results[i].getCollection(), results[i].getScore());
- }
- return tsBuilder.setId(createId(
- string, request.getStartIndex(), request.getEndIndex()))
- .build();
- } else {
- // We can not trust the result. Log the issue and ignore the result.
- Log.d(LOG_TAG, "Got bad indices for input text. Ignoring result.");
- }
- }
- } catch (Throwable t) {
- // Avoid throwing from this method. Log the error.
- Log.e(LOG_TAG,
- "Error suggesting selection for text. No changes to selection suggested.",
- t);
- }
- // Getting here means something went wrong, return a NO_OP result.
- return mFallback.suggestSelection(request);
- }
-
- /** @inheritDoc */
- @Override
- @WorkerThread
- public TextClassification classifyText(TextClassification.Request request) {
- Objects.requireNonNull(request);
- Utils.checkMainThread();
- try {
- final int rangeLength = request.getEndIndex() - request.getStartIndex();
- final String string = request.getText().toString();
- if (string.length() > 0 && rangeLength <= mSettings.getClassifyTextMaxRangeLength()) {
- final String localesString = concatenateLocales(request.getDefaultLocales());
- final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
- final ZonedDateTime refTime = request.getReferenceTime() != null
- ? request.getReferenceTime() : ZonedDateTime.now();
- final AnnotatorModel.ClassificationResult[] results =
- getAnnotatorImpl(request.getDefaultLocales())
- .classifyText(
- string, request.getStartIndex(), request.getEndIndex(),
- new AnnotatorModel.ClassificationOptions(
- refTime.toInstant().toEpochMilli(),
- refTime.getZone().getId(),
- localesString,
- detectLanguageTags),
- mContext,
- getResourceLocalesString()
- );
- if (results.length > 0) {
- return createClassificationResult(
- results, string,
- request.getStartIndex(), request.getEndIndex(), refTime.toInstant());
- }
- }
- } catch (Throwable t) {
- // Avoid throwing from this method. Log the error.
- Log.e(LOG_TAG, "Error getting text classification info.", t);
- }
- // Getting here means something went wrong, return a NO_OP result.
- return mFallback.classifyText(request);
- }
-
- /** @inheritDoc */
- @Override
- @WorkerThread
- public TextLinks generateLinks(@NonNull TextLinks.Request request) {
- Objects.requireNonNull(request);
- Utils.checkMainThread();
- if (!Utils.checkTextLength(request.getText(), getMaxGenerateLinksTextLength())) {
- return mFallback.generateLinks(request);
- }
-
- if (!mSettings.isSmartLinkifyEnabled() && request.isLegacyFallback()) {
- return Utils.generateLegacyLinks(request);
- }
-
- final String textString = request.getText().toString();
- final TextLinks.Builder builder = new TextLinks.Builder(textString);
-
- try {
- final long startTimeMs = System.currentTimeMillis();
- final ZonedDateTime refTime = ZonedDateTime.now();
- final Collection<String> entitiesToIdentify = request.getEntityConfig() != null
- ? request.getEntityConfig().resolveEntityListModifications(
- getEntitiesForHints(request.getEntityConfig().getHints()))
- : mSettings.getEntityListDefault();
- final String localesString = concatenateLocales(request.getDefaultLocales());
- final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
- final AnnotatorModel annotatorImpl =
- getAnnotatorImpl(request.getDefaultLocales());
- final boolean isSerializedEntityDataEnabled =
- ExtrasUtils.isSerializedEntityDataEnabled(request);
- final AnnotatorModel.AnnotatedSpan[] annotations =
- annotatorImpl.annotate(
- textString,
- new AnnotatorModel.AnnotationOptions(
- refTime.toInstant().toEpochMilli(),
- refTime.getZone().getId(),
- localesString,
- detectLanguageTags,
- entitiesToIdentify,
- AnnotatorModel.AnnotationUsecase.SMART.getValue(),
- isSerializedEntityDataEnabled));
- for (AnnotatorModel.AnnotatedSpan span : annotations) {
- final AnnotatorModel.ClassificationResult[] results =
- span.getClassification();
- if (results.length == 0
- || !entitiesToIdentify.contains(results[0].getCollection())) {
- continue;
- }
- final Map<String, Float> entityScores = new ArrayMap<>();
- for (int i = 0; i < results.length; i++) {
- entityScores.put(results[i].getCollection(), results[i].getScore());
- }
- Bundle extras = new Bundle();
- if (isSerializedEntityDataEnabled) {
- ExtrasUtils.putEntities(extras, results);
- }
- builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores, extras);
- }
- final TextLinks links = builder.build();
- final long endTimeMs = System.currentTimeMillis();
- final String callingPackageName = request.getCallingPackageName() == null
- ? mContext.getPackageName() // local (in process) TC.
- : request.getCallingPackageName();
- mGenerateLinksLogger.logGenerateLinks(
- request.getText(), links, callingPackageName, endTimeMs - startTimeMs);
- return links;
- } catch (Throwable t) {
- // Avoid throwing from this method. Log the error.
- Log.e(LOG_TAG, "Error getting links info.", t);
- }
- return mFallback.generateLinks(request);
- }
-
- /** @inheritDoc */
- @Override
- public int getMaxGenerateLinksTextLength() {
- return mSettings.getGenerateLinksMaxTextLength();
- }
-
- private Collection<String> getEntitiesForHints(Collection<String> hints) {
- final boolean editable = hints.contains(HINT_TEXT_IS_EDITABLE);
- final boolean notEditable = hints.contains(HINT_TEXT_IS_NOT_EDITABLE);
-
- // Use the default if there is no hint, or conflicting ones.
- final boolean useDefault = editable == notEditable;
- if (useDefault) {
- return mSettings.getEntityListDefault();
- } else if (editable) {
- return mSettings.getEntityListEditable();
- } else { // notEditable
- return mSettings.getEntityListNotEditable();
- }
- }
-
- /** @inheritDoc */
- @Override
- public void onSelectionEvent(SelectionEvent event) {
- mSessionLogger.writeEvent(event);
- }
-
- @Override
- public void onTextClassifierEvent(TextClassifierEvent event) {
- if (DEBUG) {
- Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]");
- }
- try {
- final SelectionEvent selEvent = event.toSelectionEvent();
- if (selEvent != null) {
- mSessionLogger.writeEvent(selEvent);
- } else {
- mTextClassifierEventTronLogger.writeEvent(event);
- }
- } catch (Exception e) {
- Log.e(LOG_TAG, "Error writing event", e);
- }
- }
-
- /** @inheritDoc */
- @Override
- public TextLanguage detectLanguage(@NonNull TextLanguage.Request request) {
- Objects.requireNonNull(request);
- Utils.checkMainThread();
- try {
- final TextLanguage.Builder builder = new TextLanguage.Builder();
- final LangIdModel.LanguageResult[] langResults =
- getLangIdImpl().detectLanguages(request.getText().toString());
- for (int i = 0; i < langResults.length; i++) {
- builder.putLocale(
- ULocale.forLanguageTag(langResults[i].getLanguage()),
- langResults[i].getScore());
- }
- return builder.build();
- } catch (Throwable t) {
- // Avoid throwing from this method. Log the error.
- Log.e(LOG_TAG, "Error detecting text language.", t);
- }
- return mFallback.detectLanguage(request);
- }
-
- @Override
- public ConversationActions suggestConversationActions(ConversationActions.Request request) {
- Objects.requireNonNull(request);
- Utils.checkMainThread();
- try {
- ActionsSuggestionsModel actionsImpl = getActionsImpl();
- if (actionsImpl == null) {
- // Actions model is optional, fallback if it is not available.
- return mFallback.suggestConversationActions(request);
- }
- ActionsSuggestionsModel.ConversationMessage[] nativeMessages =
- ActionsSuggestionsHelper.toNativeMessages(
- request.getConversation(), this::detectLanguageTagsFromText);
- if (nativeMessages.length == 0) {
- return mFallback.suggestConversationActions(request);
- }
- ActionsSuggestionsModel.Conversation nativeConversation =
- new ActionsSuggestionsModel.Conversation(nativeMessages);
-
- ActionsSuggestionsModel.ActionSuggestion[] nativeSuggestions =
- actionsImpl.suggestActionsWithIntents(
- nativeConversation,
- null,
- mContext,
- getResourceLocalesString(),
- getAnnotatorImpl(LocaleList.getDefault()));
- return createConversationActionResult(request, nativeSuggestions);
- } catch (Throwable t) {
- // Avoid throwing from this method. Log the error.
- Log.e(LOG_TAG, "Error suggesting conversation actions.", t);
- }
- return mFallback.suggestConversationActions(request);
- }
-
- /**
- * Returns the {@link ConversationAction} result, with a non-null extras.
- * <p>
- * Whenever the RemoteAction is non-null, you can expect its corresponding intent
- * with a non-null component name is in the extras.
- */
- private ConversationActions createConversationActionResult(
- ConversationActions.Request request,
- ActionsSuggestionsModel.ActionSuggestion[] nativeSuggestions) {
- Collection<String> expectedTypes = resolveActionTypesFromRequest(request);
- List<ConversationAction> conversationActions = new ArrayList<>();
- for (ActionsSuggestionsModel.ActionSuggestion nativeSuggestion : nativeSuggestions) {
- String actionType = nativeSuggestion.getActionType();
- if (!expectedTypes.contains(actionType)) {
- continue;
- }
- LabeledIntent.Result labeledIntentResult =
- ActionsSuggestionsHelper.createLabeledIntentResult(
- mContext,
- mTemplateIntentFactory,
- nativeSuggestion);
- RemoteAction remoteAction = null;
- Bundle extras = new Bundle();
- if (labeledIntentResult != null) {
- remoteAction = labeledIntentResult.remoteAction;
- ExtrasUtils.putActionIntent(extras, labeledIntentResult.resolvedIntent);
- }
- ExtrasUtils.putSerializedEntityData(extras, nativeSuggestion.getSerializedEntityData());
- ExtrasUtils.putEntitiesExtras(
- extras,
- TemplateIntentFactory.nameVariantsToBundle(nativeSuggestion.getEntityData()));
- conversationActions.add(
- new ConversationAction.Builder(actionType)
- .setConfidenceScore(nativeSuggestion.getScore())
- .setTextReply(nativeSuggestion.getResponseText())
- .setAction(remoteAction)
- .setExtras(extras)
- .build());
- }
- conversationActions =
- ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions);
- if (request.getMaxSuggestions() >= 0
- && conversationActions.size() > request.getMaxSuggestions()) {
- conversationActions = conversationActions.subList(0, request.getMaxSuggestions());
- }
- String resultId = ActionsSuggestionsHelper.createResultId(
- mContext,
- request.getConversation(),
- mActionModelInUse.getVersion(),
- mActionModelInUse.getSupportedLocales());
- return new ConversationActions(conversationActions, resultId);
- }
-
- @Nullable
- private String detectLanguageTagsFromText(CharSequence text) {
- if (!mSettings.isDetectLanguagesFromTextEnabled()) {
- return null;
- }
- final float threshold = getLangIdThreshold();
- if (threshold < 0 || threshold > 1) {
- Log.w(LOG_TAG,
- "[detectLanguageTagsFromText] unexpected threshold is found: " + threshold);
- return null;
- }
- TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
- TextLanguage textLanguage = detectLanguage(request);
- int localeHypothesisCount = textLanguage.getLocaleHypothesisCount();
- List<String> languageTags = new ArrayList<>();
- for (int i = 0; i < localeHypothesisCount; i++) {
- ULocale locale = textLanguage.getLocale(i);
- if (textLanguage.getConfidenceScore(locale) < threshold) {
- break;
- }
- languageTags.add(locale.toLanguageTag());
- }
- if (languageTags.isEmpty()) {
- return null;
- }
- return String.join(",", languageTags);
- }
-
- private Collection<String> resolveActionTypesFromRequest(ConversationActions.Request request) {
- List<String> defaultActionTypes =
- request.getHints().contains(ConversationActions.Request.HINT_FOR_NOTIFICATION)
- ? mSettings.getNotificationConversationActionTypes()
- : mSettings.getInAppConversationActionTypes();
- return request.getTypeConfig().resolveEntityListModifications(defaultActionTypes);
- }
-
- private AnnotatorModel getAnnotatorImpl(LocaleList localeList)
- throws FileNotFoundException {
- synchronized (mLock) {
- localeList = localeList == null ? LocaleList.getDefault() : localeList;
- final ModelFileManager.ModelFile bestModel =
- mAnnotatorModelFileManager.findBestModelFile(localeList);
- if (bestModel == null) {
- throw new FileNotFoundException(
- "No annotator model for " + localeList.toLanguageTags());
- }
- if (mAnnotatorImpl == null || !Objects.equals(mAnnotatorModelInUse, bestModel)) {
- Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
- try {
- if (pfd != null) {
- // The current annotator model may be still used by another thread / model.
- // Do not call close() here, and let the GC to clean it up when no one else
- // is using it.
- mAnnotatorImpl = new AnnotatorModel(pfd.getFd());
- mAnnotatorModelInUse = bestModel;
- }
- } finally {
- maybeCloseAndLogError(pfd);
- }
- }
- return mAnnotatorImpl;
- }
- }
-
- private LangIdModel getLangIdImpl() throws FileNotFoundException {
- synchronized (mLock) {
- final ModelFileManager.ModelFile bestModel =
- mLangIdModelFileManager.findBestModelFile(null);
- if (bestModel == null) {
- throw new FileNotFoundException("No LangID model is found");
- }
- if (mLangIdImpl == null || !Objects.equals(mLangIdModelInUse, bestModel)) {
- Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
- try {
- if (pfd != null) {
- mLangIdImpl = new LangIdModel(pfd.getFd());
- mLangIdModelInUse = bestModel;
- }
- } finally {
- maybeCloseAndLogError(pfd);
- }
- }
- return mLangIdImpl;
- }
- }
-
- @Nullable
- private ActionsSuggestionsModel getActionsImpl() throws FileNotFoundException {
- synchronized (mLock) {
- // TODO: Use LangID to determine the locale we should use here?
- final ModelFileManager.ModelFile bestModel =
- mActionsModelFileManager.findBestModelFile(LocaleList.getDefault());
- if (bestModel == null) {
- return null;
- }
- if (mActionsImpl == null || !Objects.equals(mActionModelInUse, bestModel)) {
- Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
- try {
- if (pfd == null) {
- Log.d(LOG_TAG, "Failed to read the model file: " + bestModel.getPath());
- return null;
- }
- ActionsModelParams params = mActionsModelParamsSupplier.get();
- mActionsImpl = new ActionsSuggestionsModel(
- pfd.getFd(), params.getSerializedPreconditions(bestModel));
- mActionModelInUse = bestModel;
- } finally {
- maybeCloseAndLogError(pfd);
- }
- }
- return mActionsImpl;
- }
- }
-
- private String createId(String text, int start, int end) {
- synchronized (mLock) {
- return SelectionSessionLogger.createId(text, start, end, mContext,
- mAnnotatorModelInUse.getVersion(),
- mAnnotatorModelInUse.getSupportedLocales());
- }
- }
-
- private static String concatenateLocales(@Nullable LocaleList locales) {
- return (locales == null) ? "" : locales.toLanguageTags();
- }
-
- private TextClassification createClassificationResult(
- AnnotatorModel.ClassificationResult[] classifications,
- String text, int start, int end, @Nullable Instant referenceTime) {
- final String classifiedText = text.substring(start, end);
- final TextClassification.Builder builder = new TextClassification.Builder()
- .setText(classifiedText);
-
- final int typeCount = classifications.length;
- AnnotatorModel.ClassificationResult highestScoringResult =
- typeCount > 0 ? classifications[0] : null;
- for (int i = 0; i < typeCount; i++) {
- builder.setEntityType(classifications[i]);
- if (classifications[i].getScore() > highestScoringResult.getScore()) {
- highestScoringResult = classifications[i];
- }
- }
-
- final Pair<Bundle, Bundle> languagesBundles = generateLanguageBundles(text, start, end);
- final Bundle textLanguagesBundle = languagesBundles.first;
- final Bundle foreignLanguageBundle = languagesBundles.second;
- builder.setForeignLanguageExtra(foreignLanguageBundle);
-
- boolean isPrimaryAction = true;
- final List<LabeledIntent> labeledIntents = mClassificationIntentFactory.create(
- mContext,
- classifiedText,
- foreignLanguageBundle != null,
- referenceTime,
- highestScoringResult);
- final LabeledIntent.TitleChooser titleChooser =
- (labeledIntent, resolveInfo) -> labeledIntent.titleWithoutEntity;
-
- for (LabeledIntent labeledIntent : labeledIntents) {
- final LabeledIntent.Result result =
- labeledIntent.resolve(mContext, titleChooser, textLanguagesBundle);
- if (result == null) {
- continue;
- }
-
- final Intent intent = result.resolvedIntent;
- final RemoteAction action = result.remoteAction;
- if (isPrimaryAction) {
- // For O backwards compatibility, the first RemoteAction is also written to the
- // legacy API fields.
- builder.setIcon(action.getIcon().loadDrawable(mContext));
- builder.setLabel(action.getTitle().toString());
- builder.setIntent(intent);
- builder.setOnClickListener(TextClassification.createIntentOnClickListener(
- TextClassification.createPendingIntent(
- mContext, intent, labeledIntent.requestCode)));
- isPrimaryAction = false;
- }
- builder.addAction(action, intent);
- }
- return builder.setId(createId(text, start, end)).build();
- }
-
- /**
- * Returns a bundle pair with language detection information for extras.
- * <p>
- * Pair.first = textLanguagesBundle - A bundle containing information about all detected
- * languages in the text. May be null if language detection fails or is disabled. This is
- * typically expected to be added to a textClassifier generated remote action intent.
- * See {@link ExtrasUtils#putTextLanguagesExtra(Bundle, Bundle)}.
- * See {@link ExtrasUtils#getTopLanguage(Intent)}.
- * <p>
- * Pair.second = foreignLanguageBundle - A bundle with the language and confidence score if the
- * system finds the text to be in a foreign language. Otherwise is null.
- * See {@link TextClassification.Builder#setForeignLanguageExtra(Bundle)}.
- *
- * @param context the context of the text to detect languages for
- * @param start the start index of the text
- * @param end the end index of the text
- */
- // TODO: Revisit this algorithm.
- // TODO: Consider making this public API.
- private Pair<Bundle, Bundle> generateLanguageBundles(String context, int start, int end) {
- if (!mSettings.isTranslateInClassificationEnabled()) {
- return null;
- }
- try {
- final float threshold = getLangIdThreshold();
- if (threshold < 0 || threshold > 1) {
- Log.w(LOG_TAG,
- "[detectForeignLanguage] unexpected threshold is found: " + threshold);
- return Pair.create(null, null);
- }
-
- final EntityConfidence languageScores = detectLanguages(context, start, end);
- if (languageScores.getEntities().isEmpty()) {
- return Pair.create(null, null);
- }
-
- final Bundle textLanguagesBundle = new Bundle();
- ExtrasUtils.putTopLanguageScores(textLanguagesBundle, languageScores);
-
- final String language = languageScores.getEntities().get(0);
- final float score = languageScores.getConfidenceScore(language);
- if (score < threshold) {
- return Pair.create(textLanguagesBundle, null);
- }
-
- Log.v(LOG_TAG, String.format(
- Locale.US, "Language detected: <%s:%.2f>", language, score));
-
- final Locale detected = new Locale(language);
- final LocaleList deviceLocales = LocaleList.getDefault();
- final int size = deviceLocales.size();
- for (int i = 0; i < size; i++) {
- if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) {
- return Pair.create(textLanguagesBundle, null);
- }
- }
- final Bundle foreignLanguageBundle = ExtrasUtils.createForeignLanguageExtra(
- detected.getLanguage(), score, getLangIdImpl().getVersion());
- return Pair.create(textLanguagesBundle, foreignLanguageBundle);
- } catch (Throwable t) {
- Log.e(LOG_TAG, "Error generating language bundles.", t);
- }
- return Pair.create(null, null);
- }
-
- /**
- * Detect the language of a piece of text by taking surrounding text into consideration.
- *
- * @param text text providing context for the text for which its language is to be detected
- * @param start the start index of the text to detect its language
- * @param end the end index of the text to detect its language
- */
- // TODO: Revisit this algorithm.
- private EntityConfidence detectLanguages(String text, int start, int end)
- throws FileNotFoundException {
- Preconditions.checkArgument(start >= 0);
- Preconditions.checkArgument(end <= text.length());
- Preconditions.checkArgument(start <= end);
-
- final float[] langIdContextSettings = mSettings.getLangIdContextSettings();
- // The minimum size of text to prefer for detection.
- final int minimumTextSize = (int) langIdContextSettings[0];
- // For reducing the score when text is less than the preferred size.
- final float penalizeRatio = langIdContextSettings[1];
- // Original detection score to surrounding text detection score ratios.
- final float subjectTextScoreRatio = langIdContextSettings[2];
- final float moreTextScoreRatio = 1f - subjectTextScoreRatio;
- Log.v(LOG_TAG,
- String.format(Locale.US, "LangIdContextSettings: "
- + "minimumTextSize=%d, penalizeRatio=%.2f, "
- + "subjectTextScoreRatio=%.2f, moreTextScoreRatio=%.2f",
- minimumTextSize, penalizeRatio, subjectTextScoreRatio, moreTextScoreRatio));
-
- if (end - start < minimumTextSize && penalizeRatio <= 0) {
- return new EntityConfidence(Collections.emptyMap());
- }
-
- final String subject = text.substring(start, end);
- final EntityConfidence scores = detectLanguages(subject);
-
- if (subject.length() >= minimumTextSize
- || subject.length() == text.length()
- || subjectTextScoreRatio * penalizeRatio >= 1) {
- return scores;
- }
-
- final EntityConfidence moreTextScores;
- if (moreTextScoreRatio >= 0) {
- // Attempt to grow the detection text to be at least minimumTextSize long.
- final String moreText = Utils.getSubString(text, start, end, minimumTextSize);
- moreTextScores = detectLanguages(moreText);
- } else {
- moreTextScores = new EntityConfidence(Collections.emptyMap());
- }
-
- // Combine the original detection scores with the those returned after including more text.
- final Map<String, Float> newScores = new ArrayMap<>();
- final Set<String> languages = new ArraySet<>();
- languages.addAll(scores.getEntities());
- languages.addAll(moreTextScores.getEntities());
- for (String language : languages) {
- final float score = (subjectTextScoreRatio * scores.getConfidenceScore(language)
- + moreTextScoreRatio * moreTextScores.getConfidenceScore(language))
- * penalizeRatio;
- newScores.put(language, score);
- }
- return new EntityConfidence(newScores);
- }
-
- /**
- * Detect languages for the specified text.
- */
- private EntityConfidence detectLanguages(String text) throws FileNotFoundException {
- final LangIdModel langId = getLangIdImpl();
- final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
- final Map<String, Float> languagesMap = new ArrayMap<>();
- for (LanguageResult langResult : langResults) {
- languagesMap.put(langResult.getLanguage(), langResult.getScore());
- }
- return new EntityConfidence(languagesMap);
- }
-
- private float getLangIdThreshold() {
- try {
- return mSettings.getLangIdThresholdOverride() >= 0
- ? mSettings.getLangIdThresholdOverride()
- : getLangIdImpl().getLangIdThreshold();
- } catch (FileNotFoundException e) {
- final float defaultThreshold = 0.5f;
- Log.v(LOG_TAG, "Using default foreign language threshold: " + defaultThreshold);
- return defaultThreshold;
- }
- }
-
- @Override
- public void dump(@NonNull IndentingPrintWriter printWriter) {
- synchronized (mLock) {
- printWriter.println("TextClassifierImpl:");
- printWriter.increaseIndent();
- printWriter.println("Annotator model file(s):");
- printWriter.increaseIndent();
- for (ModelFileManager.ModelFile modelFile :
- mAnnotatorModelFileManager.listModelFiles()) {
- printWriter.println(modelFile.toString());
- }
- printWriter.decreaseIndent();
- printWriter.println("LangID model file(s):");
- printWriter.increaseIndent();
- for (ModelFileManager.ModelFile modelFile :
- mLangIdModelFileManager.listModelFiles()) {
- printWriter.println(modelFile.toString());
- }
- printWriter.decreaseIndent();
- printWriter.println("Actions model file(s):");
- printWriter.increaseIndent();
- for (ModelFileManager.ModelFile modelFile :
- mActionsModelFileManager.listModelFiles()) {
- printWriter.println(modelFile.toString());
- }
- printWriter.decreaseIndent();
- printWriter.printPair("mFallback", mFallback);
- printWriter.decreaseIndent();
- printWriter.println();
- }
- }
-
- /**
- * Closes the ParcelFileDescriptor, if non-null, and logs any errors that occur.
- */
- private static void maybeCloseAndLogError(@Nullable ParcelFileDescriptor fd) {
- if (fd == null) {
- return;
- }
-
- try {
- fd.close();
- } catch (IOException e) {
- Log.e(LOG_TAG, "Error closing file.", e);
- }
- }
-
- /**
- * Returns the locales string for the current resources configuration.
- */
- private String getResourceLocalesString() {
- try {
- return mContext.getResources().getConfiguration().getLocales().toLanguageTags();
- } catch (NullPointerException e) {
- // NPE is unexpected. Erring on the side of caution.
- return LocaleList.getDefault().toLanguageTags();
- }
- }
-}
diff --git a/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java b/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
deleted file mode 100644
index 22e374f2..0000000
--- a/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.intent;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.Intent;
-
-import com.google.android.textclassifier.AnnotatorModel;
-
-import java.time.Instant;
-import java.util.List;
-
-/**
- * @hide
- */
-public interface ClassificationIntentFactory {
-
- /**
- * Return a list of LabeledIntent from the classification result.
- */
- List<LabeledIntent> create(
- Context context,
- String text,
- boolean foreignText,
- @Nullable Instant referenceTime,
- @Nullable AnnotatorModel.ClassificationResult classification);
-
- /**
- * Inserts translate action to the list if it is a foreign text.
- */
- static void insertTranslateAction(
- List<LabeledIntent> actions, Context context, String text) {
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.translate),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.translate_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_TRANSLATE)
- // TODO: Probably better to introduce a "translate" scheme instead of
- // using EXTRA_TEXT.
- .putExtra(Intent.EXTRA_TEXT, text),
- text.hashCode()));
- }
-}
diff --git a/core/java/android/view/textclassifier/intent/LabeledIntent.java b/core/java/android/view/textclassifier/intent/LabeledIntent.java
deleted file mode 100644
index cbd9d1a..0000000
--- a/core/java/android/view/textclassifier/intent/LabeledIntent.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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.intent;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.app.RemoteAction;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.textclassifier.ExtrasUtils;
-import android.view.textclassifier.Log;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassifier;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Objects;
-
-/**
- * Helper class to store the information from which RemoteActions are built.
- *
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class LabeledIntent {
- private static final String TAG = "LabeledIntent";
- public static final int DEFAULT_REQUEST_CODE = 0;
- private static final TitleChooser DEFAULT_TITLE_CHOOSER =
- (labeledIntent, resolveInfo) -> {
- if (!TextUtils.isEmpty(labeledIntent.titleWithEntity)) {
- return labeledIntent.titleWithEntity;
- }
- return labeledIntent.titleWithoutEntity;
- };
-
- @Nullable
- public final String titleWithoutEntity;
- @Nullable
- public final String titleWithEntity;
- public final String description;
- @Nullable
- public final String descriptionWithAppName;
- // Do not update this intent.
- public final Intent intent;
- public final int requestCode;
-
- /**
- * Initializes a LabeledIntent.
- *
- * <p>NOTE: {@code requestCode} is required to not be {@link #DEFAULT_REQUEST_CODE}
- * if distinguishing info (e.g. the classified text) is represented in intent extras only.
- * In such circumstances, the request code should represent the distinguishing info
- * (e.g. by generating a hashcode) so that the generated PendingIntent is (somewhat)
- * unique. To be correct, the PendingIntent should be definitely unique but we try a
- * best effort approach that avoids spamming the system with PendingIntents.
- */
- // TODO: Fix the issue mentioned above so the behaviour is correct.
- public LabeledIntent(
- @Nullable String titleWithoutEntity,
- @Nullable String titleWithEntity,
- String description,
- @Nullable String descriptionWithAppName,
- Intent intent,
- int requestCode) {
- if (TextUtils.isEmpty(titleWithEntity) && TextUtils.isEmpty(titleWithoutEntity)) {
- throw new IllegalArgumentException(
- "titleWithEntity and titleWithoutEntity should not be both null");
- }
- this.titleWithoutEntity = titleWithoutEntity;
- this.titleWithEntity = titleWithEntity;
- this.description = Objects.requireNonNull(description);
- this.descriptionWithAppName = descriptionWithAppName;
- this.intent = Objects.requireNonNull(intent);
- this.requestCode = requestCode;
- }
-
- /**
- * Return the resolved result.
- *
- * @param context the context to resolve the result's intent and action
- * @param titleChooser for choosing an action title
- * @param textLanguagesBundle containing language detection information
- */
- @Nullable
- public Result resolve(
- Context context,
- @Nullable TitleChooser titleChooser,
- @Nullable Bundle textLanguagesBundle) {
- final PackageManager pm = context.getPackageManager();
- final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
-
- if (resolveInfo == null || resolveInfo.activityInfo == null) {
- Log.w(TAG, "resolveInfo or activityInfo is null");
- return null;
- }
- final String packageName = resolveInfo.activityInfo.packageName;
- final String className = resolveInfo.activityInfo.name;
- if (packageName == null || className == null) {
- Log.w(TAG, "packageName or className is null");
- return null;
- }
- Intent resolvedIntent = new Intent(intent);
- resolvedIntent.putExtra(
- TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER,
- getFromTextClassifierExtra(textLanguagesBundle));
- boolean shouldShowIcon = false;
- Icon icon = null;
- if (!"android".equals(packageName)) {
- // We only set the component name when the package name is not resolved to "android"
- // to workaround a bug that explicit intent with component name == ResolverActivity
- // can't be launched on keyguard.
- resolvedIntent.setComponent(new ComponentName(packageName, className));
- if (resolveInfo.activityInfo.getIconResource() != 0) {
- icon = Icon.createWithResource(
- packageName, resolveInfo.activityInfo.getIconResource());
- shouldShowIcon = true;
- }
- }
- if (icon == null) {
- // RemoteAction requires that there be an icon.
- icon = Icon.createWithResource(
- "android", com.android.internal.R.drawable.ic_more_items);
- }
- final PendingIntent pendingIntent =
- TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
- titleChooser = titleChooser == null ? DEFAULT_TITLE_CHOOSER : titleChooser;
- CharSequence title = titleChooser.chooseTitle(this, resolveInfo);
- if (TextUtils.isEmpty(title)) {
- Log.w(TAG, "Custom titleChooser return null, fallback to the default titleChooser");
- title = DEFAULT_TITLE_CHOOSER.chooseTitle(this, resolveInfo);
- }
- final RemoteAction action =
- new RemoteAction(icon, title, resolveDescription(resolveInfo, pm), pendingIntent);
- action.setShouldShowIcon(shouldShowIcon);
- return new Result(resolvedIntent, action);
- }
-
- private String resolveDescription(ResolveInfo resolveInfo, PackageManager packageManager) {
- if (!TextUtils.isEmpty(descriptionWithAppName)) {
- // Example string format of descriptionWithAppName: "Use %1$s to open map".
- String applicationName = getApplicationName(resolveInfo, packageManager);
- if (!TextUtils.isEmpty(applicationName)) {
- return String.format(descriptionWithAppName, applicationName);
- }
- }
- return description;
- }
-
- @Nullable
- private String getApplicationName(
- ResolveInfo resolveInfo, PackageManager packageManager) {
- if (resolveInfo.activityInfo == null) {
- return null;
- }
- if ("android".equals(resolveInfo.activityInfo.packageName)) {
- return null;
- }
- if (resolveInfo.activityInfo.applicationInfo == null) {
- return null;
- }
- return (String) packageManager.getApplicationLabel(
- resolveInfo.activityInfo.applicationInfo);
- }
-
- private Bundle getFromTextClassifierExtra(@Nullable Bundle textLanguagesBundle) {
- if (textLanguagesBundle != null) {
- final Bundle bundle = new Bundle();
- ExtrasUtils.putTextLanguagesExtra(bundle, textLanguagesBundle);
- return bundle;
- } else {
- return Bundle.EMPTY;
- }
- }
-
- /**
- * Data class that holds the result.
- */
- public static final class Result {
- public final Intent resolvedIntent;
- public final RemoteAction remoteAction;
-
- public Result(Intent resolvedIntent, RemoteAction remoteAction) {
- this.resolvedIntent = Objects.requireNonNull(resolvedIntent);
- this.remoteAction = Objects.requireNonNull(remoteAction);
- }
- }
-
- /**
- * An object to choose a title from resolved info. If {@code null} is returned,
- * {@link #titleWithEntity} will be used if it exists, {@link #titleWithoutEntity} otherwise.
- */
- public interface TitleChooser {
- /**
- * Picks a title from a {@link LabeledIntent} by looking into resolved info.
- * {@code resolveInfo} is guaranteed to have a non-null {@code activityInfo}.
- */
- @Nullable
- CharSequence chooseTitle(LabeledIntent labeledIntent, ResolveInfo resolveInfo);
- }
-}
diff --git a/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java b/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
deleted file mode 100644
index 8d60ad8..0000000
--- a/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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.intent;
-
-import static java.time.temporal.ChronoUnit.MILLIS;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.SearchManager;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.UserManager;
-import android.provider.Browser;
-import android.provider.CalendarContract;
-import android.provider.ContactsContract;
-import android.view.textclassifier.Log;
-import android.view.textclassifier.TextClassifier;
-
-import com.google.android.textclassifier.AnnotatorModel;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Creates intents based on the classification type.
- * @hide
- */
-// TODO: Consider to support {@code descriptionWithAppName}.
-public final class LegacyClassificationIntentFactory implements ClassificationIntentFactory {
-
- private static final String TAG = "LegacyClassificationIntentFactory";
- private static final long MIN_EVENT_FUTURE_MILLIS = TimeUnit.MINUTES.toMillis(5);
- private static final long DEFAULT_EVENT_DURATION = TimeUnit.HOURS.toMillis(1);
-
- @NonNull
- @Override
- public List<LabeledIntent> create(Context context, String text, boolean foreignText,
- @Nullable Instant referenceTime,
- AnnotatorModel.ClassificationResult classification) {
- final String type = classification != null
- ? classification.getCollection().trim().toLowerCase(Locale.ENGLISH)
- : "";
- text = text.trim();
- final List<LabeledIntent> actions;
- switch (type) {
- case TextClassifier.TYPE_EMAIL:
- actions = createForEmail(context, text);
- break;
- case TextClassifier.TYPE_PHONE:
- actions = createForPhone(context, text);
- break;
- case TextClassifier.TYPE_ADDRESS:
- actions = createForAddress(context, text);
- break;
- case TextClassifier.TYPE_URL:
- actions = createForUrl(context, text);
- break;
- case TextClassifier.TYPE_DATE: // fall through
- case TextClassifier.TYPE_DATE_TIME:
- if (classification.getDatetimeResult() != null) {
- final Instant parsedTime = Instant.ofEpochMilli(
- classification.getDatetimeResult().getTimeMsUtc());
- actions = createForDatetime(context, type, referenceTime, parsedTime);
- } else {
- actions = new ArrayList<>();
- }
- break;
- case TextClassifier.TYPE_FLIGHT_NUMBER:
- actions = createForFlight(context, text);
- break;
- case TextClassifier.TYPE_DICTIONARY:
- actions = createForDictionary(context, text);
- break;
- default:
- actions = new ArrayList<>();
- break;
- }
- if (foreignText) {
- ClassificationIntentFactory.insertTranslateAction(actions, context, text);
- }
- return actions;
- }
-
- @NonNull
- private static List<LabeledIntent> createForEmail(Context context, String text) {
- final List<LabeledIntent> actions = new ArrayList<>();
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.email),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.email_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("mailto:%s", text))),
- LabeledIntent.DEFAULT_REQUEST_CODE));
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.add_contact),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.add_contact_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.EMAIL, text),
- text.hashCode()));
- return actions;
- }
-
- @NonNull
- private static List<LabeledIntent> createForPhone(Context context, String text) {
- final List<LabeledIntent> actions = new ArrayList<>();
- final UserManager userManager = context.getSystemService(UserManager.class);
- final Bundle userRestrictions = userManager != null
- ? userManager.getUserRestrictions() : new Bundle();
- if (!userRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS, false)) {
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.dial),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.dial_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_DIAL).setData(
- Uri.parse(String.format("tel:%s", text))),
- LabeledIntent.DEFAULT_REQUEST_CODE));
- }
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.add_contact),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.add_contact_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.PHONE, text),
- text.hashCode()));
- if (!userRestrictions.getBoolean(UserManager.DISALLOW_SMS, false)) {
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.sms),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.sms_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("smsto:%s", text))),
- LabeledIntent.DEFAULT_REQUEST_CODE));
- }
- return actions;
- }
-
- @NonNull
- private static List<LabeledIntent> createForAddress(Context context, String text) {
- final List<LabeledIntent> actions = new ArrayList<>();
- try {
- final String encText = URLEncoder.encode(text, "UTF-8");
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.map),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.map_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_VIEW)
- .setData(Uri.parse(String.format("geo:0,0?q=%s", encText))),
- LabeledIntent.DEFAULT_REQUEST_CODE));
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, "Could not encode address", e);
- }
- return actions;
- }
-
- @NonNull
- private static List<LabeledIntent> createForUrl(Context context, String text) {
- if (Uri.parse(text).getScheme() == null) {
- text = "http://" + text;
- }
- final List<LabeledIntent> actions = new ArrayList<>();
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.browse),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.browse_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_VIEW)
- .setDataAndNormalize(Uri.parse(text))
- .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()),
- LabeledIntent.DEFAULT_REQUEST_CODE));
- return actions;
- }
-
- @NonNull
- private static List<LabeledIntent> createForDatetime(
- Context context, String type, @Nullable Instant referenceTime,
- Instant parsedTime) {
- if (referenceTime == null) {
- // If no reference time was given, use now.
- referenceTime = Instant.now();
- }
- List<LabeledIntent> actions = new ArrayList<>();
- actions.add(createCalendarViewIntent(context, parsedTime));
- final long millisUntilEvent = referenceTime.until(parsedTime, MILLIS);
- if (millisUntilEvent > MIN_EVENT_FUTURE_MILLIS) {
- actions.add(createCalendarCreateEventIntent(context, parsedTime, type));
- }
- return actions;
- }
-
- @NonNull
- private static List<LabeledIntent> createForFlight(Context context, String text) {
- final List<LabeledIntent> actions = new ArrayList<>();
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.view_flight),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.view_flight_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_WEB_SEARCH)
- .putExtra(SearchManager.QUERY, text),
- text.hashCode()));
- return actions;
- }
-
- @NonNull
- private static LabeledIntent createCalendarViewIntent(Context context, Instant parsedTime) {
- Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
- builder.appendPath("time");
- ContentUris.appendId(builder, parsedTime.toEpochMilli());
- return new LabeledIntent(
- context.getString(com.android.internal.R.string.view_calendar),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.view_calendar_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_VIEW).setData(builder.build()),
- LabeledIntent.DEFAULT_REQUEST_CODE);
- }
-
- @NonNull
- private static LabeledIntent createCalendarCreateEventIntent(
- Context context, Instant parsedTime, @TextClassifier.EntityType String type) {
- final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
- return new LabeledIntent(
- context.getString(com.android.internal.R.string.add_calendar_event),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.add_calendar_event_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_INSERT)
- .setData(CalendarContract.Events.CONTENT_URI)
- .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
- .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME,
- parsedTime.toEpochMilli())
- .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
- parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION),
- parsedTime.hashCode());
- }
-
- @NonNull
- private static List<LabeledIntent> createForDictionary(Context context, String text) {
- final List<LabeledIntent> actions = new ArrayList<>();
- actions.add(new LabeledIntent(
- context.getString(com.android.internal.R.string.define),
- /* titleWithEntity */ null,
- context.getString(com.android.internal.R.string.define_desc),
- /* descriptionWithAppName */ null,
- new Intent(Intent.ACTION_DEFINE)
- .putExtra(Intent.EXTRA_TEXT, text),
- text.hashCode()));
- return actions;
- }
-}
diff --git a/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
deleted file mode 100644
index aef4bd6..0000000
--- a/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.intent;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.view.textclassifier.Log;
-import android.view.textclassifier.TextClassifier;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-
-import com.google.android.textclassifier.AnnotatorModel;
-import com.google.android.textclassifier.RemoteActionTemplate;
-
-import java.time.Instant;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Creates intents based on {@link RemoteActionTemplate} objects for a ClassificationResult.
- *
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class TemplateClassificationIntentFactory implements ClassificationIntentFactory {
- private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
- private final TemplateIntentFactory mTemplateIntentFactory;
- private final ClassificationIntentFactory mFallback;
-
- public TemplateClassificationIntentFactory(TemplateIntentFactory templateIntentFactory,
- ClassificationIntentFactory fallback) {
- mTemplateIntentFactory = Objects.requireNonNull(templateIntentFactory);
- mFallback = Objects.requireNonNull(fallback);
- }
-
- /**
- * Returns a list of {@link LabeledIntent}
- * that are constructed from the classification result.
- */
- @NonNull
- @Override
- public List<LabeledIntent> create(
- Context context,
- String text,
- boolean foreignText,
- @Nullable Instant referenceTime,
- @Nullable AnnotatorModel.ClassificationResult classification) {
- if (classification == null) {
- return Collections.emptyList();
- }
- RemoteActionTemplate[] remoteActionTemplates = classification.getRemoteActionTemplates();
- if (remoteActionTemplates == null) {
- // RemoteActionTemplate is missing, fallback.
- Log.w(TAG, "RemoteActionTemplate is missing, fallback to"
- + " LegacyClassificationIntentFactory.");
- return mFallback.create(context, text, foreignText, referenceTime, classification);
- }
- final List<LabeledIntent> labeledIntents =
- mTemplateIntentFactory.create(remoteActionTemplates);
- if (foreignText) {
- ClassificationIntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
- }
- return labeledIntents;
- }
-}
diff --git a/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
deleted file mode 100644
index 7a39569..0000000
--- a/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.intent;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.textclassifier.Log;
-import android.view.textclassifier.TextClassifier;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.textclassifier.NamedVariant;
-import com.google.android.textclassifier.RemoteActionTemplate;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Creates intents based on {@link RemoteActionTemplate} objects.
- *
- * @hide
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class TemplateIntentFactory {
- private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
-
- /**
- * Constructs and returns a list of {@link LabeledIntent} based on the given templates.
- */
- @Nullable
- public List<LabeledIntent> create(
- @NonNull RemoteActionTemplate[] remoteActionTemplates) {
- if (remoteActionTemplates.length == 0) {
- return new ArrayList<>();
- }
- final List<LabeledIntent> labeledIntents = new ArrayList<>();
- for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
- if (!isValidTemplate(remoteActionTemplate)) {
- Log.w(TAG, "Invalid RemoteActionTemplate skipped.");
- continue;
- }
- labeledIntents.add(
- new LabeledIntent(
- remoteActionTemplate.titleWithoutEntity,
- remoteActionTemplate.titleWithEntity,
- remoteActionTemplate.description,
- remoteActionTemplate.descriptionWithAppName,
- createIntent(remoteActionTemplate),
- remoteActionTemplate.requestCode == null
- ? LabeledIntent.DEFAULT_REQUEST_CODE
- : remoteActionTemplate.requestCode));
- }
- return labeledIntents;
- }
-
- private static boolean isValidTemplate(@Nullable RemoteActionTemplate remoteActionTemplate) {
- if (remoteActionTemplate == null) {
- Log.w(TAG, "Invalid RemoteActionTemplate: is null");
- return false;
- }
- if (TextUtils.isEmpty(remoteActionTemplate.titleWithEntity)
- && TextUtils.isEmpty(remoteActionTemplate.titleWithoutEntity)) {
- Log.w(TAG, "Invalid RemoteActionTemplate: title is null");
- return false;
- }
- if (TextUtils.isEmpty(remoteActionTemplate.description)) {
- Log.w(TAG, "Invalid RemoteActionTemplate: description is null");
- return false;
- }
- if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) {
- Log.w(TAG, "Invalid RemoteActionTemplate: package name is set");
- return false;
- }
- if (TextUtils.isEmpty(remoteActionTemplate.action)) {
- Log.w(TAG, "Invalid RemoteActionTemplate: intent action not set");
- return false;
- }
- return true;
- }
-
- private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) {
- final Intent intent = new Intent(remoteActionTemplate.action);
- final Uri uri = TextUtils.isEmpty(remoteActionTemplate.data)
- ? null : Uri.parse(remoteActionTemplate.data).normalizeScheme();
- final String type = TextUtils.isEmpty(remoteActionTemplate.type)
- ? null : Intent.normalizeMimeType(remoteActionTemplate.type);
- intent.setDataAndType(uri, type);
- intent.setFlags(remoteActionTemplate.flags == null ? 0 : remoteActionTemplate.flags);
- if (remoteActionTemplate.category != null) {
- for (String category : remoteActionTemplate.category) {
- if (category != null) {
- intent.addCategory(category);
- }
- }
- }
- intent.putExtras(nameVariantsToBundle(remoteActionTemplate.extras));
- return intent;
- }
-
- /**
- * Converts an array of {@link NamedVariant} to a Bundle and returns it.
- */
- public static Bundle nameVariantsToBundle(@Nullable NamedVariant[] namedVariants) {
- if (namedVariants == null) {
- return Bundle.EMPTY;
- }
- Bundle bundle = new Bundle();
- for (NamedVariant namedVariant : namedVariants) {
- if (namedVariant == null) {
- continue;
- }
- switch (namedVariant.getType()) {
- case NamedVariant.TYPE_INT:
- bundle.putInt(namedVariant.getName(), namedVariant.getInt());
- break;
- case NamedVariant.TYPE_LONG:
- bundle.putLong(namedVariant.getName(), namedVariant.getLong());
- break;
- case NamedVariant.TYPE_FLOAT:
- bundle.putFloat(namedVariant.getName(), namedVariant.getFloat());
- break;
- case NamedVariant.TYPE_DOUBLE:
- bundle.putDouble(namedVariant.getName(), namedVariant.getDouble());
- break;
- case NamedVariant.TYPE_BOOL:
- bundle.putBoolean(namedVariant.getName(), namedVariant.getBool());
- break;
- case NamedVariant.TYPE_STRING:
- bundle.putString(namedVariant.getName(), namedVariant.getString());
- break;
- default:
- Log.w(TAG,
- "Unsupported type found in nameVariantsToBundle : "
- + namedVariant.getType());
- }
- }
- return bundle;
- }
-}
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
deleted file mode 100644
index 28cb80d..0000000
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright (C) 2017 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.logging;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.metrics.LogMaker;
-import android.os.Build;
-import android.util.Log;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextSelection;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.Preconditions;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-import java.util.UUID;
-
-/**
- * A selection event tracker.
- * @hide
- */
-//TODO: Do not allow any crashes from this class.
-public final class SmartSelectionEventTracker {
-
- private static final String LOG_TAG = "SmartSelectEventTracker";
- private static final boolean DEBUG_LOG_ENABLED = true;
-
- private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
- private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
- private static final int INDEX = MetricsEvent.FIELD_SELECTION_SESSION_INDEX;
- private static final int WIDGET_TYPE = MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
- private static final int WIDGET_VERSION = MetricsEvent.FIELD_SELECTION_WIDGET_VERSION;
- private static final int MODEL_NAME = MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
- private static final int ENTITY_TYPE = MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
- private static final int SMART_START = MetricsEvent.FIELD_SELECTION_SMART_RANGE_START;
- private static final int SMART_END = MetricsEvent.FIELD_SELECTION_SMART_RANGE_END;
- private static final int EVENT_START = MetricsEvent.FIELD_SELECTION_RANGE_START;
- private static final int EVENT_END = MetricsEvent.FIELD_SELECTION_RANGE_END;
- private static final int SESSION_ID = MetricsEvent.FIELD_SELECTION_SESSION_ID;
-
- private static final String ZERO = "0";
- private static final String TEXTVIEW = "textview";
- private static final String EDITTEXT = "edittext";
- private static final String UNSELECTABLE_TEXTVIEW = "nosel-textview";
- private static final String WEBVIEW = "webview";
- private static final String EDIT_WEBVIEW = "edit-webview";
- private static final String CUSTOM_TEXTVIEW = "customview";
- private static final String CUSTOM_EDITTEXT = "customedit";
- private static final String CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
- private static final String UNKNOWN = "unknown";
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({WidgetType.UNSPECIFIED, WidgetType.TEXTVIEW, WidgetType.WEBVIEW,
- WidgetType.EDITTEXT, WidgetType.EDIT_WEBVIEW})
- public @interface WidgetType {
- int UNSPECIFIED = 0;
- int TEXTVIEW = 1;
- int WEBVIEW = 2;
- int EDITTEXT = 3;
- int EDIT_WEBVIEW = 4;
- int UNSELECTABLE_TEXTVIEW = 5;
- int CUSTOM_TEXTVIEW = 6;
- int CUSTOM_EDITTEXT = 7;
- int CUSTOM_UNSELECTABLE_TEXTVIEW = 8;
- }
-
- private final MetricsLogger mMetricsLogger = new MetricsLogger();
- private final int mWidgetType;
- @Nullable private final String mWidgetVersion;
- private final Context mContext;
-
- @Nullable private String mSessionId;
- private final int[] mSmartIndices = new int[2];
- private final int[] mPrevIndices = new int[2];
- private int mOrigStart;
- private int mIndex;
- private long mSessionStartTime;
- private long mLastEventTime;
- private boolean mSmartSelectionTriggered;
- private String mModelName;
-
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
- mWidgetType = widgetType;
- mWidgetVersion = null;
- mContext = Objects.requireNonNull(context);
- }
-
- public SmartSelectionEventTracker(
- @NonNull Context context, @WidgetType int widgetType, @Nullable String widgetVersion) {
- mWidgetType = widgetType;
- mWidgetVersion = widgetVersion;
- mContext = Objects.requireNonNull(context);
- }
-
- /**
- * Logs a selection event.
- *
- * @param event the selection event
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public void logEvent(@NonNull SelectionEvent event) {
- Objects.requireNonNull(event);
-
- if (event.mEventType != SelectionEvent.EventType.SELECTION_STARTED && mSessionId == null
- && DEBUG_LOG_ENABLED) {
- Log.d(LOG_TAG, "Selection session not yet started. Ignoring event");
- return;
- }
-
- final long now = System.currentTimeMillis();
- switch (event.mEventType) {
- case SelectionEvent.EventType.SELECTION_STARTED:
- mSessionId = startNewSession();
- Preconditions.checkArgument(event.mEnd == event.mStart + 1);
- mOrigStart = event.mStart;
- mSessionStartTime = now;
- break;
- case SelectionEvent.EventType.SMART_SELECTION_SINGLE: // fall through
- case SelectionEvent.EventType.SMART_SELECTION_MULTI:
- mSmartSelectionTriggered = true;
- mModelName = getModelName(event);
- mSmartIndices[0] = event.mStart;
- mSmartIndices[1] = event.mEnd;
- break;
- case SelectionEvent.EventType.SELECTION_MODIFIED: // fall through
- case SelectionEvent.EventType.AUTO_SELECTION:
- if (mPrevIndices[0] == event.mStart && mPrevIndices[1] == event.mEnd) {
- // Selection did not change. Ignore event.
- return;
- }
- }
- writeEvent(event, now);
-
- if (event.isTerminal()) {
- endSession();
- }
- }
-
- private void writeEvent(SelectionEvent event, long now) {
- final long prevEventDelta = mLastEventTime == 0 ? 0 : now - mLastEventTime;
- final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
- .setType(getLogType(event))
- .setSubtype(MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL)
- .setPackageName(mContext.getPackageName())
- .addTaggedData(START_EVENT_DELTA, now - mSessionStartTime)
- .addTaggedData(PREV_EVENT_DELTA, prevEventDelta)
- .addTaggedData(INDEX, mIndex)
- .addTaggedData(WIDGET_TYPE, getWidgetTypeName())
- .addTaggedData(WIDGET_VERSION, mWidgetVersion)
- .addTaggedData(MODEL_NAME, mModelName)
- .addTaggedData(ENTITY_TYPE, event.mEntityType)
- .addTaggedData(SMART_START, getSmartRangeDelta(mSmartIndices[0]))
- .addTaggedData(SMART_END, getSmartRangeDelta(mSmartIndices[1]))
- .addTaggedData(EVENT_START, getRangeDelta(event.mStart))
- .addTaggedData(EVENT_END, getRangeDelta(event.mEnd))
- .addTaggedData(SESSION_ID, mSessionId);
- mMetricsLogger.write(log);
- debugLog(log);
- mLastEventTime = now;
- mPrevIndices[0] = event.mStart;
- mPrevIndices[1] = event.mEnd;
- mIndex++;
- }
-
- private String startNewSession() {
- endSession();
- mSessionId = createSessionId();
- return mSessionId;
- }
-
- private void endSession() {
- // Reset fields.
- mOrigStart = 0;
- mSmartIndices[0] = mSmartIndices[1] = 0;
- mPrevIndices[0] = mPrevIndices[1] = 0;
- mIndex = 0;
- mSessionStartTime = 0;
- mLastEventTime = 0;
- mSmartSelectionTriggered = false;
- mModelName = getModelName(null);
- mSessionId = null;
- }
-
- private static int getLogType(SelectionEvent event) {
- switch (event.mEventType) {
- case SelectionEvent.ActionType.OVERTYPE:
- return MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE;
- case SelectionEvent.ActionType.COPY:
- return MetricsEvent.ACTION_TEXT_SELECTION_COPY;
- case SelectionEvent.ActionType.PASTE:
- return MetricsEvent.ACTION_TEXT_SELECTION_PASTE;
- case SelectionEvent.ActionType.CUT:
- return MetricsEvent.ACTION_TEXT_SELECTION_CUT;
- case SelectionEvent.ActionType.SHARE:
- return MetricsEvent.ACTION_TEXT_SELECTION_SHARE;
- case SelectionEvent.ActionType.SMART_SHARE:
- return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
- case SelectionEvent.ActionType.DRAG:
- return MetricsEvent.ACTION_TEXT_SELECTION_DRAG;
- case SelectionEvent.ActionType.ABANDON:
- return MetricsEvent.ACTION_TEXT_SELECTION_ABANDON;
- case SelectionEvent.ActionType.OTHER:
- return MetricsEvent.ACTION_TEXT_SELECTION_OTHER;
- case SelectionEvent.ActionType.SELECT_ALL:
- return MetricsEvent.ACTION_TEXT_SELECTION_SELECT_ALL;
- case SelectionEvent.ActionType.RESET:
- return MetricsEvent.ACTION_TEXT_SELECTION_RESET;
- case SelectionEvent.EventType.SELECTION_STARTED:
- return MetricsEvent.ACTION_TEXT_SELECTION_START;
- case SelectionEvent.EventType.SELECTION_MODIFIED:
- return MetricsEvent.ACTION_TEXT_SELECTION_MODIFY;
- case SelectionEvent.EventType.SMART_SELECTION_SINGLE:
- return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SINGLE;
- case SelectionEvent.EventType.SMART_SELECTION_MULTI:
- return MetricsEvent.ACTION_TEXT_SELECTION_SMART_MULTI;
- case SelectionEvent.EventType.AUTO_SELECTION:
- return MetricsEvent.ACTION_TEXT_SELECTION_AUTO;
- default:
- return MetricsEvent.VIEW_UNKNOWN;
- }
- }
-
- private static String getLogTypeString(int logType) {
- switch (logType) {
- case MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE:
- return "OVERTYPE";
- case MetricsEvent.ACTION_TEXT_SELECTION_COPY:
- return "COPY";
- case MetricsEvent.ACTION_TEXT_SELECTION_PASTE:
- return "PASTE";
- case MetricsEvent.ACTION_TEXT_SELECTION_CUT:
- return "CUT";
- case MetricsEvent.ACTION_TEXT_SELECTION_SHARE:
- return "SHARE";
- case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE:
- return "SMART_SHARE";
- case MetricsEvent.ACTION_TEXT_SELECTION_DRAG:
- return "DRAG";
- case MetricsEvent.ACTION_TEXT_SELECTION_ABANDON:
- return "ABANDON";
- case MetricsEvent.ACTION_TEXT_SELECTION_OTHER:
- return "OTHER";
- case MetricsEvent.ACTION_TEXT_SELECTION_SELECT_ALL:
- return "SELECT_ALL";
- case MetricsEvent.ACTION_TEXT_SELECTION_RESET:
- return "RESET";
- case MetricsEvent.ACTION_TEXT_SELECTION_START:
- return "SELECTION_STARTED";
- case MetricsEvent.ACTION_TEXT_SELECTION_MODIFY:
- return "SELECTION_MODIFIED";
- case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SINGLE:
- return "SMART_SELECTION_SINGLE";
- case MetricsEvent.ACTION_TEXT_SELECTION_SMART_MULTI:
- return "SMART_SELECTION_MULTI";
- case MetricsEvent.ACTION_TEXT_SELECTION_AUTO:
- return "AUTO_SELECTION";
- default:
- return UNKNOWN;
- }
- }
-
- private int getRangeDelta(int offset) {
- return offset - mOrigStart;
- }
-
- private int getSmartRangeDelta(int offset) {
- return mSmartSelectionTriggered ? getRangeDelta(offset) : 0;
- }
-
- private String getWidgetTypeName() {
- switch (mWidgetType) {
- case WidgetType.TEXTVIEW:
- return TEXTVIEW;
- case WidgetType.WEBVIEW:
- return WEBVIEW;
- case WidgetType.EDITTEXT:
- return EDITTEXT;
- case WidgetType.EDIT_WEBVIEW:
- return EDIT_WEBVIEW;
- case WidgetType.UNSELECTABLE_TEXTVIEW:
- return UNSELECTABLE_TEXTVIEW;
- case WidgetType.CUSTOM_TEXTVIEW:
- return CUSTOM_TEXTVIEW;
- case WidgetType.CUSTOM_EDITTEXT:
- return CUSTOM_EDITTEXT;
- case WidgetType.CUSTOM_UNSELECTABLE_TEXTVIEW:
- return CUSTOM_UNSELECTABLE_TEXTVIEW;
- default:
- return UNKNOWN;
- }
- }
-
- private String getModelName(@Nullable SelectionEvent event) {
- return event == null
- ? SelectionEvent.NO_VERSION_TAG
- : Objects.toString(event.mVersionTag, SelectionEvent.NO_VERSION_TAG);
- }
-
- private static String createSessionId() {
- return UUID.randomUUID().toString();
- }
-
- private static void debugLog(LogMaker log) {
- if (!DEBUG_LOG_ENABLED) return;
-
- final String widgetType = Objects.toString(log.getTaggedData(WIDGET_TYPE), UNKNOWN);
- final String widgetVersion = Objects.toString(log.getTaggedData(WIDGET_VERSION), "");
- final String widget = widgetVersion.isEmpty()
- ? widgetType : widgetType + "-" + widgetVersion;
- final int index = Integer.parseInt(Objects.toString(log.getTaggedData(INDEX), ZERO));
- if (log.getType() == MetricsEvent.ACTION_TEXT_SELECTION_START) {
- String sessionId = Objects.toString(log.getTaggedData(SESSION_ID), "");
- sessionId = sessionId.substring(sessionId.lastIndexOf("-") + 1);
- Log.d(LOG_TAG, String.format("New selection session: %s (%s)", widget, sessionId));
- }
-
- final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
- final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
- final String type = getLogTypeString(log.getType());
- final int smartStart = Integer.parseInt(
- Objects.toString(log.getTaggedData(SMART_START), ZERO));
- final int smartEnd = Integer.parseInt(
- Objects.toString(log.getTaggedData(SMART_END), ZERO));
- final int eventStart = Integer.parseInt(
- Objects.toString(log.getTaggedData(EVENT_START), ZERO));
- final int eventEnd = Integer.parseInt(
- Objects.toString(log.getTaggedData(EVENT_END), ZERO));
-
- Log.d(LOG_TAG, String.format("%2d: %s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
- index, type, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model));
- }
-
- /**
- * A selection event.
- * Specify index parameters as word token indices.
- */
- public static final class SelectionEvent {
-
- /**
- * Use this to specify an indeterminate positive index.
- */
- public static final int OUT_OF_BOUNDS = Integer.MAX_VALUE;
-
- /**
- * Use this to specify an indeterminate negative index.
- */
- public static final int OUT_OF_BOUNDS_NEGATIVE = Integer.MIN_VALUE;
-
- private static final String NO_VERSION_TAG = "";
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ActionType.OVERTYPE, ActionType.COPY, ActionType.PASTE, ActionType.CUT,
- ActionType.SHARE, ActionType.SMART_SHARE, ActionType.DRAG, ActionType.ABANDON,
- ActionType.OTHER, ActionType.SELECT_ALL, ActionType.RESET})
- public @interface ActionType {
- /** User typed over the selection. */
- int OVERTYPE = 100;
- /** User copied the selection. */
- int COPY = 101;
- /** User pasted over the selection. */
- int PASTE = 102;
- /** User cut the selection. */
- int CUT = 103;
- /** User shared the selection. */
- int SHARE = 104;
- /** User clicked the textAssist menu item. */
- int SMART_SHARE = 105;
- /** User dragged+dropped the selection. */
- int DRAG = 106;
- /** User abandoned the selection. */
- int ABANDON = 107;
- /** User performed an action on the selection. */
- int OTHER = 108;
-
- /* Non-terminal actions. */
- /** User activated Select All */
- int SELECT_ALL = 200;
- /** User reset the smart selection. */
- int RESET = 201;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ActionType.OVERTYPE, ActionType.COPY, ActionType.PASTE, ActionType.CUT,
- ActionType.SHARE, ActionType.SMART_SHARE, ActionType.DRAG, ActionType.ABANDON,
- ActionType.OTHER, ActionType.SELECT_ALL, ActionType.RESET,
- EventType.SELECTION_STARTED, EventType.SELECTION_MODIFIED,
- EventType.SMART_SELECTION_SINGLE, EventType.SMART_SELECTION_MULTI,
- EventType.AUTO_SELECTION})
- private @interface EventType {
- /** User started a new selection. */
- int SELECTION_STARTED = 1;
- /** User modified an existing selection. */
- int SELECTION_MODIFIED = 2;
- /** Smart selection triggered for a single token (word). */
- int SMART_SELECTION_SINGLE = 3;
- /** Smart selection triggered spanning multiple tokens (words). */
- int SMART_SELECTION_MULTI = 4;
- /** Something else other than User or the default TextClassifier triggered a selection. */
- int AUTO_SELECTION = 5;
- }
-
- private final int mStart;
- private final int mEnd;
- private @EventType int mEventType;
- private final @TextClassifier.EntityType String mEntityType;
- private final String mVersionTag;
-
- private SelectionEvent(
- int start, int end, int eventType,
- @TextClassifier.EntityType String entityType, String versionTag) {
- Preconditions.checkArgument(end >= start, "end cannot be less than start");
- mStart = start;
- mEnd = end;
- mEventType = eventType;
- mEntityType = Objects.requireNonNull(entityType);
- mVersionTag = Objects.requireNonNull(versionTag);
- }
-
- /**
- * Creates a "selection started" event.
- *
- * @param start the word index of the selected word
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public static SelectionEvent selectionStarted(int start) {
- return new SelectionEvent(
- start, start + 1, EventType.SELECTION_STARTED,
- TextClassifier.TYPE_UNKNOWN, NO_VERSION_TAG);
- }
-
- /**
- * Creates a "selection modified" event.
- * Use when the user modifies the selection.
- *
- * @param start the start word (inclusive) index of the selection
- * @param end the end word (exclusive) index of the selection
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public static SelectionEvent selectionModified(int start, int end) {
- return new SelectionEvent(
- start, end, EventType.SELECTION_MODIFIED,
- TextClassifier.TYPE_UNKNOWN, NO_VERSION_TAG);
- }
-
- /**
- * Creates a "selection modified" event.
- * Use when the user modifies the selection and the selection's entity type is known.
- *
- * @param start the start word (inclusive) index of the selection
- * @param end the end word (exclusive) index of the selection
- * @param classification the TextClassification object returned by the TextClassifier that
- * classified the selected text
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public static SelectionEvent selectionModified(
- int start, int end, @NonNull TextClassification classification) {
- final String entityType = classification.getEntityCount() > 0
- ? classification.getEntity(0)
- : TextClassifier.TYPE_UNKNOWN;
- final String versionTag = getVersionInfo(classification.getId());
- return new SelectionEvent(
- start, end, EventType.SELECTION_MODIFIED, entityType, versionTag);
- }
-
- /**
- * Creates a "selection modified" event.
- * Use when a TextClassifier modifies the selection.
- *
- * @param start the start word (inclusive) index of the selection
- * @param end the end word (exclusive) index of the selection
- * @param selection the TextSelection object returned by the TextClassifier for the
- * specified selection
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public static SelectionEvent selectionModified(
- int start, int end, @NonNull TextSelection selection) {
- final boolean smartSelection = getSourceClassifier(selection.getId())
- .equals(TextClassifier.DEFAULT_LOG_TAG);
- final int eventType;
- if (smartSelection) {
- eventType = end - start > 1
- ? EventType.SMART_SELECTION_MULTI
- : EventType.SMART_SELECTION_SINGLE;
-
- } else {
- eventType = EventType.AUTO_SELECTION;
- }
- final String entityType = selection.getEntityCount() > 0
- ? selection.getEntity(0)
- : TextClassifier.TYPE_UNKNOWN;
- final String versionTag = getVersionInfo(selection.getId());
- return new SelectionEvent(start, end, eventType, entityType, versionTag);
- }
-
- /**
- * Creates an event specifying an action taken on a selection.
- * Use when the user clicks on an action to act on the selected text.
- *
- * @param start the start word (inclusive) index of the selection
- * @param end the end word (exclusive) index of the selection
- * @param actionType the action that was performed on the selection
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public static SelectionEvent selectionAction(
- int start, int end, @ActionType int actionType) {
- return new SelectionEvent(
- start, end, actionType, TextClassifier.TYPE_UNKNOWN, NO_VERSION_TAG);
- }
-
- /**
- * Creates an event specifying an action taken on a selection.
- * Use when the user clicks on an action to act on the selected text and the selection's
- * entity type is known.
- *
- * @param start the start word (inclusive) index of the selection
- * @param end the end word (exclusive) index of the selection
- * @param actionType the action that was performed on the selection
- * @param classification the TextClassification object returned by the TextClassifier that
- * classified the selected text
- */
- @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
- publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
- public static SelectionEvent selectionAction(
- int start, int end, @ActionType int actionType,
- @NonNull TextClassification classification) {
- final String entityType = classification.getEntityCount() > 0
- ? classification.getEntity(0)
- : TextClassifier.TYPE_UNKNOWN;
- final String versionTag = getVersionInfo(classification.getId());
- return new SelectionEvent(start, end, actionType, entityType, versionTag);
- }
-
- @VisibleForTesting
- public static String getVersionInfo(String signature) {
- final int start = signature.indexOf("|") + 1;
- final int end = signature.indexOf("|", start);
- if (start >= 1 && end >= start) {
- return signature.substring(start, end);
- }
- return "";
- }
-
- private static String getSourceClassifier(String signature) {
- final int end = signature.indexOf("|");
- if (end >= 0) {
- return signature.substring(0, end);
- }
- return "";
- }
-
- private boolean isTerminal() {
- switch (mEventType) {
- case ActionType.OVERTYPE: // fall through
- case ActionType.COPY: // fall through
- case ActionType.PASTE: // fall through
- case ActionType.CUT: // fall through
- case ActionType.SHARE: // fall through
- case ActionType.SMART_SHARE: // fall through
- case ActionType.DRAG: // fall through
- case ActionType.ABANDON: // fall through
- case ActionType.OTHER: // fall through
- return true;
- default:
- return false;
- }
- }
- }
-}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4ef3f61..45943f5 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -39,7 +39,6 @@
import android.view.textclassifier.ExtrasUtils;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.SelectionEvent.InvocationMethod;
-import android.view.textclassifier.SelectionSessionLogger;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationContext;
@@ -705,7 +704,7 @@
SelectionMetricsLogger(TextView textView) {
Objects.requireNonNull(textView);
mEditTextLogger = textView.isTextEditable();
- mTokenIterator = SelectionSessionLogger.getTokenIterator(textView.getTextLocale());
+ mTokenIterator = BreakIterator.getWordInstance(textView.getTextLocale());
}
public void logSelectionStarted(
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 7a0afa2..9bdfa4a 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.Slog;
import android.widget.Toast;
@@ -153,6 +154,9 @@
}
private boolean shouldShowDisclosure(@Nullable ResolveInfo ri, Intent intent) {
+ if (!isDeviceProvisioned()) {
+ return false;
+ }
if (ri == null || ri.activityInfo == null) {
return true;
}
@@ -163,6 +167,11 @@
return !isTargetResolverOrChooserActivity(ri.activityInfo);
}
+ private boolean isDeviceProvisioned() {
+ return Settings.Global.getInt(getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, /* def= */ 0) != 0;
+ }
+
private boolean isTextMessageIntent(Intent intent) {
return (Intent.ACTION_SENDTO.equals(intent.getAction()) || isViewActionIntent(intent))
&& ALLOWED_TEXT_MESSAGE_SCHEMES.contains(intent.getScheme());
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsModelParamsSupplierTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsModelParamsSupplierTest.java
deleted file mode 100644
index 8744997..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsModelParamsSupplierTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.Locale;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ActionsModelParamsSupplierTest {
-
- @Test
- public void getSerializedPreconditions_validActionsModelParams() {
- ModelFileManager.ModelFile modelFile = new ModelFileManager.ModelFile(
- new File("/model/file"),
- 200 /* version */,
- Collections.singletonList(Locale.forLanguageTag("en")),
- "en",
- false);
- byte[] serializedPreconditions = new byte[]{0x12, 0x24, 0x36};
- ActionsModelParamsSupplier.ActionsModelParams params =
- new ActionsModelParamsSupplier.ActionsModelParams(
- 200 /* version */,
- "en",
- serializedPreconditions);
-
- byte[] actual = params.getSerializedPreconditions(modelFile);
-
- assertThat(actual).isEqualTo(serializedPreconditions);
- }
-
- @Test
- public void getSerializedPreconditions_invalidVersion() {
- ModelFileManager.ModelFile modelFile = new ModelFileManager.ModelFile(
- new File("/model/file"),
- 201 /* version */,
- Collections.singletonList(Locale.forLanguageTag("en")),
- "en",
- false);
- byte[] serializedPreconditions = new byte[]{0x12, 0x24, 0x36};
- ActionsModelParamsSupplier.ActionsModelParams params =
- new ActionsModelParamsSupplier.ActionsModelParams(
- 200 /* version */,
- "en",
- serializedPreconditions);
-
- byte[] actual = params.getSerializedPreconditions(modelFile);
-
- assertThat(actual).isNull();
- }
-
- @Test
- public void getSerializedPreconditions_invalidLocales() {
- final String LANGUAGE_TAG = "zh";
- ModelFileManager.ModelFile modelFile = new ModelFileManager.ModelFile(
- new File("/model/file"),
- 200 /* version */,
- Collections.singletonList(Locale.forLanguageTag(LANGUAGE_TAG)),
- LANGUAGE_TAG,
- false);
- byte[] serializedPreconditions = new byte[]{0x12, 0x24, 0x36};
- ActionsModelParamsSupplier.ActionsModelParams params =
- new ActionsModelParamsSupplier.ActionsModelParams(
- 200 /* version */,
- "en",
- serializedPreconditions);
-
- byte[] actual = params.getSerializedPreconditions(modelFile);
-
- assertThat(actual).isNull();
- }
-
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
deleted file mode 100644
index ec7e83f..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * 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 android.view.textclassifier.ConversationActions.Message.PERSON_USER_OTHERS;
-import static android.view.textclassifier.ConversationActions.Message.PERSON_USER_SELF;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.PendingIntent;
-import android.app.Person;
-import android.app.RemoteAction;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.textclassifier.intent.LabeledIntent;
-import android.view.textclassifier.intent.TemplateIntentFactory;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.textclassifier.ActionsSuggestionsModel;
-import com.google.android.textclassifier.RemoteActionTemplate;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.function.Function;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ActionsSuggestionsHelperTest {
- private static final String LOCALE_TAG = Locale.US.toLanguageTag();
- private static final Function<CharSequence, String> LANGUAGE_DETECTOR =
- charSequence -> LOCALE_TAG;
-
- @Test
- public void testToNativeMessages_emptyInput() {
- ActionsSuggestionsModel.ConversationMessage[] conversationMessages =
- ActionsSuggestionsHelper.toNativeMessages(
- Collections.emptyList(), LANGUAGE_DETECTOR);
-
- assertThat(conversationMessages).isEmpty();
- }
-
- @Test
- public void testToNativeMessages_noTextMessages() {
- ConversationActions.Message messageWithoutText =
- new ConversationActions.Message.Builder(PERSON_USER_OTHERS).build();
-
- ActionsSuggestionsModel.ConversationMessage[] conversationMessages =
- ActionsSuggestionsHelper.toNativeMessages(
- Collections.singletonList(messageWithoutText), LANGUAGE_DETECTOR);
-
- assertThat(conversationMessages).isEmpty();
- }
-
- @Test
- public void testToNativeMessages_userIdEncoding() {
- Person userA = new Person.Builder().setName("userA").build();
- Person userB = new Person.Builder().setName("userB").build();
-
- ConversationActions.Message firstMessage =
- new ConversationActions.Message.Builder(userB)
- .setText("first")
- .build();
- ConversationActions.Message secondMessage =
- new ConversationActions.Message.Builder(userA)
- .setText("second")
- .build();
- ConversationActions.Message thirdMessage =
- new ConversationActions.Message.Builder(PERSON_USER_SELF)
- .setText("third")
- .build();
- ConversationActions.Message fourthMessage =
- new ConversationActions.Message.Builder(userA)
- .setText("fourth")
- .build();
-
- ActionsSuggestionsModel.ConversationMessage[] conversationMessages =
- ActionsSuggestionsHelper.toNativeMessages(
- Arrays.asList(firstMessage, secondMessage, thirdMessage, fourthMessage),
- LANGUAGE_DETECTOR);
-
- assertThat(conversationMessages).hasLength(4);
- assertNativeMessage(conversationMessages[0], firstMessage.getText(), 2, 0);
- assertNativeMessage(conversationMessages[1], secondMessage.getText(), 1, 0);
- assertNativeMessage(conversationMessages[2], thirdMessage.getText(), 0, 0);
- assertNativeMessage(conversationMessages[3], fourthMessage.getText(), 1, 0);
- }
-
- @Test
- public void testToNativeMessages_referenceTime() {
- ConversationActions.Message firstMessage =
- new ConversationActions.Message.Builder(PERSON_USER_OTHERS)
- .setText("first")
- .setReferenceTime(createZonedDateTimeFromMsUtc(1000))
- .build();
- ConversationActions.Message secondMessage =
- new ConversationActions.Message.Builder(PERSON_USER_OTHERS)
- .setText("second")
- .build();
- ConversationActions.Message thirdMessage =
- new ConversationActions.Message.Builder(PERSON_USER_OTHERS)
- .setText("third")
- .setReferenceTime(createZonedDateTimeFromMsUtc(2000))
- .build();
-
- ActionsSuggestionsModel.ConversationMessage[] conversationMessages =
- ActionsSuggestionsHelper.toNativeMessages(
- Arrays.asList(firstMessage, secondMessage, thirdMessage),
- LANGUAGE_DETECTOR);
-
- assertThat(conversationMessages).hasLength(3);
- assertNativeMessage(conversationMessages[0], firstMessage.getText(), 1, 1000);
- assertNativeMessage(conversationMessages[1], secondMessage.getText(), 1, 0);
- assertNativeMessage(conversationMessages[2], thirdMessage.getText(), 1, 2000);
- }
-
- @Test
- public void testDeduplicateActions() {
- Bundle phoneExtras = new Bundle();
- Intent phoneIntent = new Intent();
- phoneIntent.setComponent(new ComponentName("phone", "intent"));
- ExtrasUtils.putActionIntent(phoneExtras, phoneIntent);
-
- Bundle anotherPhoneExtras = new Bundle();
- Intent anotherPhoneIntent = new Intent();
- anotherPhoneIntent.setComponent(new ComponentName("phone", "another.intent"));
- ExtrasUtils.putActionIntent(anotherPhoneExtras, anotherPhoneIntent);
-
- Bundle urlExtras = new Bundle();
- Intent urlIntent = new Intent();
- urlIntent.setComponent(new ComponentName("url", "intent"));
- ExtrasUtils.putActionIntent(urlExtras, urlIntent);
-
- PendingIntent pendingIntent = PendingIntent.getActivity(
- InstrumentationRegistry.getTargetContext(),
- 0,
- phoneIntent,
- 0);
- Icon icon = Icon.createWithData(new byte[0], 0, 0);
- ConversationAction action =
- new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
- .setAction(new RemoteAction(icon, "label", "1", pendingIntent))
- .setExtras(phoneExtras)
- .build();
- ConversationAction actionWithSameLabel =
- new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
- .setAction(new RemoteAction(
- icon, "label", "2", pendingIntent))
- .setExtras(phoneExtras)
- .build();
- ConversationAction actionWithSamePackageButDifferentClass =
- new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
- .setAction(new RemoteAction(
- icon, "label", "3", pendingIntent))
- .setExtras(anotherPhoneExtras)
- .build();
- ConversationAction actionWithDifferentLabel =
- new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
- .setAction(new RemoteAction(
- icon, "another_label", "4", pendingIntent))
- .setExtras(phoneExtras)
- .build();
- ConversationAction actionWithDifferentPackage =
- new ConversationAction.Builder(ConversationAction.TYPE_OPEN_URL)
- .setAction(new RemoteAction(icon, "label", "5", pendingIntent))
- .setExtras(urlExtras)
- .build();
- ConversationAction actionWithoutRemoteAction =
- new ConversationAction.Builder(ConversationAction.TYPE_CREATE_REMINDER)
- .build();
-
- List<ConversationAction> conversationActions =
- ActionsSuggestionsHelper.removeActionsWithDuplicates(
- Arrays.asList(action, actionWithSameLabel,
- actionWithSamePackageButDifferentClass, actionWithDifferentLabel,
- actionWithDifferentPackage, actionWithoutRemoteAction));
-
- assertThat(conversationActions).hasSize(3);
- assertThat(conversationActions.get(0).getAction().getContentDescription()).isEqualTo("4");
- assertThat(conversationActions.get(1).getAction().getContentDescription()).isEqualTo("5");
- assertThat(conversationActions.get(2).getAction()).isNull();
- }
-
- @Test
- public void testDeduplicateActions_nullComponent() {
- Bundle phoneExtras = new Bundle();
- Intent phoneIntent = new Intent(Intent.ACTION_DIAL);
- ExtrasUtils.putActionIntent(phoneExtras, phoneIntent);
- PendingIntent pendingIntent = PendingIntent.getActivity(
- InstrumentationRegistry.getTargetContext(),
- 0,
- phoneIntent,
- 0);
- Icon icon = Icon.createWithData(new byte[0], 0, 0);
- ConversationAction action =
- new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
- .setAction(new RemoteAction(icon, "label", "1", pendingIntent))
- .setExtras(phoneExtras)
- .build();
- ConversationAction actionWithSameLabel =
- new ConversationAction.Builder(ConversationAction.TYPE_CALL_PHONE)
- .setAction(new RemoteAction(
- icon, "label", "2", pendingIntent))
- .setExtras(phoneExtras)
- .build();
-
- List<ConversationAction> conversationActions =
- ActionsSuggestionsHelper.removeActionsWithDuplicates(
- Arrays.asList(action, actionWithSameLabel));
-
- assertThat(conversationActions).isEmpty();
- }
-
- @Test
- public void createLabeledIntentResult_null() {
- ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
- new ActionsSuggestionsModel.ActionSuggestion(
- "text",
- ConversationAction.TYPE_OPEN_URL,
- 1.0f,
- null,
- null,
- null
- );
-
- LabeledIntent.Result labeledIntentResult =
- ActionsSuggestionsHelper.createLabeledIntentResult(
- InstrumentationRegistry.getTargetContext(),
- new TemplateIntentFactory(),
- nativeSuggestion);
-
- assertThat(labeledIntentResult).isNull();
- }
-
- @Test
- public void createLabeledIntentResult_emptyList() {
- ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
- new ActionsSuggestionsModel.ActionSuggestion(
- "text",
- ConversationAction.TYPE_OPEN_URL,
- 1.0f,
- null,
- null,
- new RemoteActionTemplate[0]
- );
-
- LabeledIntent.Result labeledIntentResult =
- ActionsSuggestionsHelper.createLabeledIntentResult(
- InstrumentationRegistry.getTargetContext(),
- new TemplateIntentFactory(),
- nativeSuggestion);
-
- assertThat(labeledIntentResult).isNull();
- }
-
- @Test
- public void createLabeledIntentResult() {
- ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
- new ActionsSuggestionsModel.ActionSuggestion(
- "text",
- ConversationAction.TYPE_OPEN_URL,
- 1.0f,
- null,
- null,
- new RemoteActionTemplate[]{
- new RemoteActionTemplate(
- "title",
- null,
- "description",
- null,
- Intent.ACTION_VIEW,
- Uri.parse("http://www.android.com").toString(),
- null,
- 0,
- null,
- null,
- null,
- 0)});
-
- LabeledIntent.Result labeledIntentResult =
- ActionsSuggestionsHelper.createLabeledIntentResult(
- InstrumentationRegistry.getTargetContext(),
- new TemplateIntentFactory(),
- nativeSuggestion);
-
- assertThat(labeledIntentResult.remoteAction.getTitle()).isEqualTo("title");
- assertThat(labeledIntentResult.resolvedIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
- }
-
- private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
- return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneId.of("UTC"));
- }
-
- private static void assertNativeMessage(
- ActionsSuggestionsModel.ConversationMessage nativeMessage,
- CharSequence text,
- int userId,
- long referenceTimeInMsUtc) {
- assertThat(nativeMessage.getText()).isEqualTo(text.toString());
- assertThat(nativeMessage.getUserId()).isEqualTo(userId);
- assertThat(nativeMessage.getDetectedTextLanguageTags()).isEqualTo(LOCALE_TAG);
- assertThat(nativeMessage.getReferenceTimeMsUtc()).isEqualTo(referenceTimeInMsUtc);
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
deleted file mode 100644
index 79e1406..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * 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.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.os.LocaleList;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ModelFileManagerTest {
- private static final Locale DEFAULT_LOCALE = Locale.forLanguageTag("en-US");
- @Mock
- private Supplier<List<ModelFileManager.ModelFile>> mModelFileSupplier;
- private ModelFileManager.ModelFileSupplierImpl mModelFileSupplierImpl;
- private ModelFileManager mModelFileManager;
- private File mRootTestDir;
- private File mFactoryModelDir;
- private File mUpdatedModelFile;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mModelFileManager = new ModelFileManager(mModelFileSupplier);
- mRootTestDir = InstrumentationRegistry.getContext().getCacheDir();
- mFactoryModelDir = new File(mRootTestDir, "factory");
- mUpdatedModelFile = new File(mRootTestDir, "updated.model");
-
- mModelFileSupplierImpl =
- new ModelFileManager.ModelFileSupplierImpl(
- mFactoryModelDir,
- "test\\d.model",
- mUpdatedModelFile,
- fd -> 1,
- fd -> ModelFileManager.ModelFile.LANGUAGE_INDEPENDENT
- );
-
- mRootTestDir.mkdirs();
- mFactoryModelDir.mkdirs();
-
- Locale.setDefault(DEFAULT_LOCALE);
- }
-
- @After
- public void removeTestDir() {
- recursiveDelete(mRootTestDir);
- }
-
- @Test
- public void get() {
- ModelFileManager.ModelFile modelFile =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1, Collections.emptyList(), "", true);
- when(mModelFileSupplier.get()).thenReturn(Collections.singletonList(modelFile));
-
- List<ModelFileManager.ModelFile> modelFiles = mModelFileManager.listModelFiles();
-
- assertThat(modelFiles).hasSize(1);
- assertThat(modelFiles.get(0)).isEqualTo(modelFile);
- }
-
- @Test
- public void findBestModel_versionCode() {
- ModelFileManager.ModelFile olderModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.emptyList(), "", true);
-
- ModelFileManager.ModelFile newerModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 2,
- Collections.emptyList(), "", true);
- when(mModelFileSupplier.get())
- .thenReturn(Arrays.asList(olderModelFile, newerModelFile));
-
- ModelFileManager.ModelFile bestModelFile =
- mModelFileManager.findBestModelFile(LocaleList.getEmptyLocaleList());
-
- assertThat(bestModelFile).isEqualTo(newerModelFile);
- }
-
- @Test
- public void findBestModel_languageDependentModelIsPreferred() {
- Locale locale = Locale.forLanguageTag("ja");
- ModelFileManager.ModelFile languageIndependentModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.emptyList(), "", true);
-
- ModelFileManager.ModelFile languageDependentModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 1,
- Collections.singletonList(locale), locale.toLanguageTag(), false);
- when(mModelFileSupplier.get())
- .thenReturn(
- Arrays.asList(languageIndependentModelFile, languageDependentModelFile));
-
- ModelFileManager.ModelFile bestModelFile =
- mModelFileManager.findBestModelFile(
- LocaleList.forLanguageTags(locale.toLanguageTag()));
- assertThat(bestModelFile).isEqualTo(languageDependentModelFile);
- }
-
- @Test
- public void findBestModel_noMatchedLanguageModel() {
- Locale locale = Locale.forLanguageTag("ja");
- ModelFileManager.ModelFile languageIndependentModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.emptyList(), "", true);
-
- ModelFileManager.ModelFile languageDependentModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 1,
- Collections.singletonList(locale), locale.toLanguageTag(), false);
-
- when(mModelFileSupplier.get())
- .thenReturn(
- Arrays.asList(languageIndependentModelFile, languageDependentModelFile));
-
- ModelFileManager.ModelFile bestModelFile =
- mModelFileManager.findBestModelFile(
- LocaleList.forLanguageTags("zh-hk"));
- assertThat(bestModelFile).isEqualTo(languageIndependentModelFile);
- }
-
- @Test
- public void findBestModel_noMatchedLanguageModel_defaultLocaleModelExists() {
- ModelFileManager.ModelFile languageIndependentModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.emptyList(), "", true);
-
- ModelFileManager.ModelFile languageDependentModelFile =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 1,
- Collections.singletonList(
- DEFAULT_LOCALE), DEFAULT_LOCALE.toLanguageTag(), false);
-
- when(mModelFileSupplier.get())
- .thenReturn(
- Arrays.asList(languageIndependentModelFile, languageDependentModelFile));
-
- ModelFileManager.ModelFile bestModelFile =
- mModelFileManager.findBestModelFile(
- LocaleList.forLanguageTags("zh-hk"));
- assertThat(bestModelFile).isEqualTo(languageIndependentModelFile);
- }
-
- @Test
- public void findBestModel_languageIsMoreImportantThanVersion() {
- ModelFileManager.ModelFile matchButOlderModel =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("fr")), "fr", false);
-
- ModelFileManager.ModelFile mismatchButNewerModel =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 2,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- when(mModelFileSupplier.get())
- .thenReturn(
- Arrays.asList(matchButOlderModel, mismatchButNewerModel));
-
- ModelFileManager.ModelFile bestModelFile =
- mModelFileManager.findBestModelFile(
- LocaleList.forLanguageTags("fr"));
- assertThat(bestModelFile).isEqualTo(matchButOlderModel);
- }
-
- @Test
- public void findBestModel_languageIsMoreImportantThanVersion_bestModelComesFirst() {
- ModelFileManager.ModelFile matchLocaleModel =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- ModelFileManager.ModelFile languageIndependentModel =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 2,
- Collections.emptyList(), "", true);
- when(mModelFileSupplier.get())
- .thenReturn(
- Arrays.asList(matchLocaleModel, languageIndependentModel));
-
- ModelFileManager.ModelFile bestModelFile =
- mModelFileManager.findBestModelFile(
- LocaleList.forLanguageTags("ja"));
-
- assertThat(bestModelFile).isEqualTo(matchLocaleModel);
- }
-
- @Test
- public void modelFileEquals() {
- ModelFileManager.ModelFile modelA =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- ModelFileManager.ModelFile modelB =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- assertThat(modelA).isEqualTo(modelB);
- }
-
- @Test
- public void modelFile_different() {
- ModelFileManager.ModelFile modelA =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- ModelFileManager.ModelFile modelB =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- assertThat(modelA).isNotEqualTo(modelB);
- }
-
-
- @Test
- public void modelFile_getPath() {
- ModelFileManager.ModelFile modelA =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- assertThat(modelA.getPath()).isEqualTo("/path/a");
- }
-
- @Test
- public void modelFile_getName() {
- ModelFileManager.ModelFile modelA =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- assertThat(modelA.getName()).isEqualTo("a");
- }
-
- @Test
- public void modelFile_isPreferredTo_languageDependentIsBetter() {
- ModelFileManager.ModelFile modelA =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 1,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- ModelFileManager.ModelFile modelB =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 2,
- Collections.emptyList(), "", true);
-
- assertThat(modelA.isPreferredTo(modelB)).isTrue();
- }
-
- @Test
- public void modelFile_isPreferredTo_version() {
- ModelFileManager.ModelFile modelA =
- new ModelFileManager.ModelFile(
- new File("/path/a"), 2,
- Collections.singletonList(Locale.forLanguageTag("ja")), "ja", false);
-
- ModelFileManager.ModelFile modelB =
- new ModelFileManager.ModelFile(
- new File("/path/b"), 1,
- Collections.emptyList(), "", false);
-
- assertThat(modelA.isPreferredTo(modelB)).isTrue();
- }
-
- @Test
- public void testFileSupplierImpl_updatedFileOnly() throws IOException {
- mUpdatedModelFile.createNewFile();
- File model1 = new File(mFactoryModelDir, "test1.model");
- model1.createNewFile();
- File model2 = new File(mFactoryModelDir, "test2.model");
- model2.createNewFile();
- new File(mFactoryModelDir, "not_match_regex.model").createNewFile();
-
- List<ModelFileManager.ModelFile> modelFiles = mModelFileSupplierImpl.get();
- List<String> modelFilePaths =
- modelFiles
- .stream()
- .map(modelFile -> modelFile.getPath())
- .collect(Collectors.toList());
-
- assertThat(modelFiles).hasSize(3);
- assertThat(modelFilePaths).containsExactly(
- mUpdatedModelFile.getAbsolutePath(),
- model1.getAbsolutePath(),
- model2.getAbsolutePath());
- }
-
- @Test
- public void testFileSupplierImpl_empty() {
- mFactoryModelDir.delete();
- List<ModelFileManager.ModelFile> modelFiles = mModelFileSupplierImpl.get();
-
- assertThat(modelFiles).hasSize(0);
- }
-
- private static void recursiveDelete(File f) {
- if (f.isDirectory()) {
- for (File innerFile : f.listFiles()) {
- recursiveDelete(innerFile);
- }
- }
- f.delete();
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 82fa73f..2f21b7f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -16,7 +16,6 @@
package android.view.textclassifier;
-import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.provider.DeviceConfig;
@@ -24,8 +23,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.google.common.primitives.Floats;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,17 +54,17 @@
public void testLoadFromDeviceConfig_IntValue() throws Exception {
// Saves config original value.
final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH);
+ TextClassificationConstants.GENERATE_LINKS_MAX_TEXT_LENGTH);
final TextClassificationConstants constants = new TextClassificationConstants();
try {
// Sets and checks different value.
- setDeviceConfig(TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH, "8");
- assertWithMessage(TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH)
- .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8);
+ setDeviceConfig(TextClassificationConstants.GENERATE_LINKS_MAX_TEXT_LENGTH, "8");
+ assertWithMessage(TextClassificationConstants.GENERATE_LINKS_MAX_TEXT_LENGTH)
+ .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(8);
} finally {
// Restores config original value.
- setDeviceConfig(TextClassificationConstants.SUGGEST_SELECTION_MAX_RANGE_LENGTH,
+ setDeviceConfig(TextClassificationConstants.GENERATE_LINKS_MAX_TEXT_LENGTH,
originalValue);
}
}
@@ -94,61 +91,6 @@
}
}
- @Test
- public void testLoadFromDeviceConfig_FloatValue() throws Exception {
- // Saves config original value.
- final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE);
-
- final TextClassificationConstants constants = new TextClassificationConstants();
- try {
- // Sets and checks different value.
- setDeviceConfig(TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE, "2");
- assertWithMessage(TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE)
- .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
- } finally {
- // Restores config original value.
- setDeviceConfig(TextClassificationConstants.LANG_ID_THRESHOLD_OVERRIDE, originalValue);
- }
- }
-
- @Test
- public void testLoadFromDeviceConfig_StringList() throws Exception {
- // Saves config original value.
- final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- TextClassificationConstants.ENTITY_LIST_DEFAULT);
-
- final TextClassificationConstants constants = new TextClassificationConstants();
- try {
- // Sets and checks different value.
- setDeviceConfig(TextClassificationConstants.ENTITY_LIST_DEFAULT, "email:url");
- assertWithMessage(TextClassificationConstants.ENTITY_LIST_DEFAULT)
- .that(constants.getEntityListDefault())
- .containsExactly("email", "url");
- } finally {
- // Restores config original value.
- setDeviceConfig(TextClassificationConstants.ENTITY_LIST_DEFAULT, originalValue);
- }
- }
-
- @Test
- public void testLoadFromDeviceConfig_FloatList() throws Exception {
- // Saves config original value.
- final String originalValue = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- TextClassificationConstants.LANG_ID_CONTEXT_SETTINGS);
-
- final TextClassificationConstants constants = new TextClassificationConstants();
- try {
- // Sets and checks different value.
- setDeviceConfig(TextClassificationConstants.LANG_ID_CONTEXT_SETTINGS, "30:0.5:0.3");
- assertThat(Floats.asList(constants.getLangIdContextSettings())).containsExactly(30f,
- 0.5f, 0.3f).inOrder();
- } finally {
- // Restores config original value.
- setDeviceConfig(TextClassificationConstants.LANG_ID_CONTEXT_SETTINGS, originalValue);
- }
- }
-
private void setDeviceConfig(String key, String value) {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, key,
value, /* makeDefault */ false);
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 1ca4649..628252d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -16,19 +16,15 @@
package android.view.textclassifier;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.mock;
import android.content.Context;
-import android.content.Intent;
-import android.os.LocaleList;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
@@ -38,14 +34,12 @@
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
- private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
-
private Context mContext;
private TextClassificationManager mTcm;
@Before
public void setup() {
- mContext = InstrumentationRegistry.getTargetContext();
+ mContext = ApplicationProvider.getApplicationContext();
mTcm = mContext.getSystemService(TextClassificationManager.class);
}
@@ -53,45 +47,17 @@
public void testSetTextClassifier() {
TextClassifier classifier = mock(TextClassifier.class);
mTcm.setTextClassifier(classifier);
- assertEquals(classifier, mTcm.getTextClassifier());
+ assertThat(mTcm.getTextClassifier()).isEqualTo(classifier);
}
@Test
public void testGetLocalTextClassifier() {
- assertTrue(mTcm.getTextClassifier(TextClassifier.LOCAL) instanceof TextClassifierImpl);
+ assertThat(mTcm.getTextClassifier(TextClassifier.LOCAL)).isSameAs(TextClassifier.NO_OP);
}
@Test
public void testGetSystemTextClassifier() {
- assertTrue(mTcm.getTextClassifier(TextClassifier.SYSTEM) instanceof SystemTextClassifier);
- }
-
- @Test
- public void testCannotResolveIntent() {
- Context fakeContext = new FakeContextBuilder()
- .setAllIntentComponent(FakeContextBuilder.DEFAULT_COMPONENT)
- .setIntentComponent(Intent.ACTION_INSERT_OR_EDIT, null)
- .build();
-
- TextClassifier fallback = TextClassifier.NO_OP;
- TextClassifier classifier = new TextClassifierImpl(
- fakeContext, new TextClassificationConstants(), fallback);
-
- String text = "Contact me at +12122537077";
- String classifiedText = "+12122537077";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification result = classifier.classifyText(request);
- TextClassification fallbackResult = fallback.classifyText(request);
-
- // classifier should not totally fail in which case it returns a fallback result.
- // It should skip the failing intent and return a result for non-failing intents.
- assertFalse(result.getActions().isEmpty());
- assertNotSame(result, fallbackResult);
+ assertThat(mTcm.getTextClassifier(TextClassifier.SYSTEM))
+ .isInstanceOf(SystemTextClassifier.class);
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
deleted file mode 100644
index 372a478..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ /dev/null
@@ -1,719 +0,0 @@
-/*
- * 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 org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.app.RemoteAction;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.service.textclassifier.TextClassifierService;
-import android.text.Spannable;
-import android.text.SpannableString;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-
-import com.google.common.truth.Truth;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Testing {@link TextClassifierTest} APIs on local and system textclassifier.
- * <p>
- * Tests are skipped if such a textclassifier does not exist.
- */
-@SmallTest
-@RunWith(Parameterized.class)
-public class TextClassifierTest {
- private static final String LOCAL = "local";
- private static final String SESSION = "session";
- private static final String DEFAULT = "default";
-
- // TODO: Add SYSTEM, which tests TextClassifier.SYSTEM.
- @Parameterized.Parameters(name = "{0}")
- public static Iterable<Object> textClassifierTypes() {
- return Arrays.asList(LOCAL, SESSION, DEFAULT);
- }
-
- @Parameterized.Parameter
- public String mTextClassifierType;
-
- private static final TextClassificationConstants TC_CONSTANTS =
- new TextClassificationConstants();
- private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
- private static final String NO_TYPE = null;
-
- private Context mContext;
- private TextClassificationManager mTcm;
- private TextClassifier mClassifier;
-
- @Before
- public void setup() {
- mContext = InstrumentationRegistry.getTargetContext();
- mTcm = mContext.getSystemService(TextClassificationManager.class);
-
- if (mTextClassifierType.equals(LOCAL)) {
- mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
- } else if (mTextClassifierType.equals(SESSION)) {
- mClassifier = mTcm.createTextClassificationSession(
- new TextClassificationContext.Builder(
- "android",
- TextClassifier.WIDGET_TYPE_NOTIFICATION)
- .build(),
- mTcm.getTextClassifier(TextClassifier.LOCAL));
- } else {
- mClassifier = TextClassifierService.getDefaultTextClassifierImplementation(mContext);
- }
- }
-
- @Test
- public void testSuggestSelection() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String selected = "droid";
- String suggested = "droid@android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
- TextSelection.Request request = new TextSelection.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextSelection selection = mClassifier.suggestSelection(request);
- assertThat(selection,
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testSuggestSelection_url() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit http://www.android.com for more information";
- String selected = "http";
- String suggested = "http://www.android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
- TextSelection.Request request = new TextSelection.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextSelection selection = mClassifier.suggestSelection(request);
- assertThat(selection,
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
- }
-
- @Test
- public void testSmartSelection_withEmoji() {
- if (isTextClassifierDisabled()) return;
-
- String text = "\uD83D\uDE02 Hello.";
- String selected = "Hello";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- TextSelection.Request request = new TextSelection.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextSelection selection = mClassifier.suggestSelection(request);
- assertThat(selection,
- isTextSelection(startIndex, endIndex, NO_TYPE));
- }
-
- @Test
- public void testClassifyText() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String classifiedText = "droid@android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testClassifyText_url() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit www.android.com for more information";
- String classifiedText = "www.android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
- assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
- }
-
- @Test
- public void testClassifyText_address() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Brandschenkestrasse 110, Zürich, Switzerland";
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, 0, text.length())
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(text, TextClassifier.TYPE_ADDRESS));
- }
-
- @Test
- public void testClassifyText_url_inCaps() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit HTTP://ANDROID.COM for more information";
- String classifiedText = "HTTP://ANDROID.COM";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
- assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
- }
-
- @Test
- public void testClassifyText_date() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Let's meet on January 9, 2018.";
- String classifiedText = "January 9, 2018";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_DATE));
- Bundle extras = classification.getExtras();
- List<Bundle> entities = ExtrasUtils.getEntities(extras);
- Truth.assertThat(entities).hasSize(1);
- Bundle entity = entities.get(0);
- Truth.assertThat(ExtrasUtils.getEntityType(entity)).isEqualTo(TextClassifier.TYPE_DATE);
- }
-
- @Test
- public void testClassifyText_datetime() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Let's meet 2018/01/01 10:30:20.";
- String classifiedText = "2018/01/01 10:30:20";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification,
- isTextClassification(classifiedText, TextClassifier.TYPE_DATE_TIME));
- }
-
- @Test
- public void testClassifyText_foreignText() {
- LocaleList originalLocales = LocaleList.getDefault();
- LocaleList.setDefault(LocaleList.forLanguageTags("en"));
- String japaneseText = "これは日本語のテキストです";
-
- Context context = new FakeContextBuilder()
- .setIntentComponent(Intent.ACTION_TRANSLATE, FakeContextBuilder.DEFAULT_COMPONENT)
- .build();
- TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS);
- TextClassification.Request request = new TextClassification.Request.Builder(
- japaneseText, 0, japaneseText.length())
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = classifier.classifyText(request);
- RemoteAction translateAction = classification.getActions().get(0);
- assertEquals(1, classification.getActions().size());
- assertEquals(
- context.getString(com.android.internal.R.string.translate),
- translateAction.getTitle());
-
- assertEquals(translateAction, ExtrasUtils.findTranslateAction(classification));
- Intent intent = ExtrasUtils.getActionsIntents(classification).get(0);
- assertEquals(Intent.ACTION_TRANSLATE, intent.getAction());
- Bundle foreignLanguageInfo = ExtrasUtils.getForeignLanguageExtra(classification);
- assertEquals("ja", ExtrasUtils.getEntityType(foreignLanguageInfo));
- assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) >= 0);
- assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) <= 1);
- assertTrue(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER));
- assertEquals("ja", ExtrasUtils.getTopLanguage(intent).getLanguage());
-
- LocaleList.setDefault(originalLocales);
- }
-
- @Test
- public void testGenerateLinks_phone() {
- if (isTextClassifierDisabled()) return;
- String text = "The number is +12122537077. See you tonight!";
- TextLinks.Request request = new TextLinks.Request.Builder(text).build();
- assertThat(mClassifier.generateLinks(request),
- isTextLinksContaining(text, "+12122537077", TextClassifier.TYPE_PHONE));
- }
-
- @Test
- public void testGenerateLinks_exclude() {
- if (isTextClassifierDisabled()) return;
- String text = "You want apple@banana.com. See you tonight!";
- List<String> hints = Collections.EMPTY_LIST;
- List<String> included = Collections.EMPTY_LIST;
- List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
- TextLinks.Request request = new TextLinks.Request.Builder(text)
- .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
- .setDefaultLocales(LOCALES)
- .build();
- assertThat(mClassifier.generateLinks(request),
- not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
- }
-
- @Test
- public void testGenerateLinks_explicit_address() {
- if (isTextClassifierDisabled()) return;
- String text = "The address is 1600 Amphitheater Parkway, Mountain View, CA. See you!";
- List<String> explicit = Arrays.asList(TextClassifier.TYPE_ADDRESS);
- TextLinks.Request request = new TextLinks.Request.Builder(text)
- .setEntityConfig(TextClassifier.EntityConfig.createWithExplicitEntityList(explicit))
- .setDefaultLocales(LOCALES)
- .build();
- assertThat(mClassifier.generateLinks(request),
- isTextLinksContaining(text, "1600 Amphitheater Parkway, Mountain View, CA",
- TextClassifier.TYPE_ADDRESS));
- }
-
- @Test
- public void testGenerateLinks_exclude_override() {
- if (isTextClassifierDisabled()) return;
- String text = "You want apple@banana.com. See you tonight!";
- List<String> hints = Collections.EMPTY_LIST;
- List<String> included = Arrays.asList(TextClassifier.TYPE_EMAIL);
- List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
- TextLinks.Request request = new TextLinks.Request.Builder(text)
- .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
- .setDefaultLocales(LOCALES)
- .build();
- assertThat(mClassifier.generateLinks(request),
- not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
- }
-
- @Test
- public void testGenerateLinks_maxLength() {
- if (isTextClassifierDisabled()) return;
- char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
- Arrays.fill(manySpaces, ' ');
- TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
- TextLinks links = mClassifier.generateLinks(request);
- assertTrue(links.getLinks().isEmpty());
- }
-
- @Test
- public void testApplyLinks_unsupportedCharacter() {
- if (isTextClassifierDisabled()) return;
- Spannable url = new SpannableString("\u202Emoc.diordna.com");
- TextLinks.Request request = new TextLinks.Request.Builder(url).build();
- assertEquals(
- TextLinks.STATUS_UNSUPPORTED_CHARACTER,
- mClassifier.generateLinks(request).apply(url, 0, null));
- }
-
- @Test
- public void testGenerateLinks_tooLong() {
- if (isTextClassifierDisabled()) return;
- char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
- Arrays.fill(manySpaces, ' ');
- TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
- TextLinks links = mClassifier.generateLinks(request);
- assertTrue(links.getLinks().isEmpty());
- }
-
- @Test
- public void testGenerateLinks_entityData() {
- if (isTextClassifierDisabled()) return;
- String text = "The number is +12122537077.";
- Bundle extras = new Bundle();
- ExtrasUtils.putIsSerializedEntityDataEnabled(extras, true);
- TextLinks.Request request = new TextLinks.Request.Builder(text).setExtras(extras).build();
-
- TextLinks textLinks = mClassifier.generateLinks(request);
-
- Truth.assertThat(textLinks.getLinks()).hasSize(1);
- TextLinks.TextLink textLink = textLinks.getLinks().iterator().next();
- List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras());
- Truth.assertThat(entities).hasSize(1);
- Bundle entity = entities.get(0);
- Truth.assertThat(ExtrasUtils.getEntityType(entity)).isEqualTo(TextClassifier.TYPE_PHONE);
- }
-
- @Test
- public void testGenerateLinks_entityData_disabled() {
- if (isTextClassifierDisabled()) return;
- String text = "The number is +12122537077.";
- TextLinks.Request request = new TextLinks.Request.Builder(text).build();
-
- TextLinks textLinks = mClassifier.generateLinks(request);
-
- Truth.assertThat(textLinks.getLinks()).hasSize(1);
- TextLinks.TextLink textLink = textLinks.getLinks().iterator().next();
- List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras());
- Truth.assertThat(entities).isNull();
- }
-
- @Test
- public void testDetectLanguage() {
- if (isTextClassifierDisabled()) return;
- String text = "This is English text";
- TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
- TextLanguage textLanguage = mClassifier.detectLanguage(request);
- assertThat(textLanguage, isTextLanguage("en"));
- }
-
- @Test
- public void testDetectLanguage_japanese() {
- if (isTextClassifierDisabled()) return;
- String text = "これは日本語のテキストです";
- TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
- TextLanguage textLanguage = mClassifier.detectLanguage(request);
- assertThat(textLanguage, isTextLanguage("ja"));
- }
-
- @Ignore // Doesn't work without a language-based model.
- @Test
- public void testSuggestConversationActions_textReplyOnly_maxOne() {
- if (isTextClassifierDisabled()) return;
- ConversationActions.Message message =
- new ConversationActions.Message.Builder(
- ConversationActions.Message.PERSON_USER_OTHERS)
- .setText("Where are you?")
- .build();
- TextClassifier.EntityConfig typeConfig =
- new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
- .setIncludedTypes(
- Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
- .build();
- ConversationActions.Request request =
- new ConversationActions.Request.Builder(Collections.singletonList(message))
- .setMaxSuggestions(1)
- .setTypeConfig(typeConfig)
- .build();
-
- ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
- Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
- ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
- Truth.assertThat(conversationAction.getType()).isEqualTo(
- ConversationAction.TYPE_TEXT_REPLY);
- Truth.assertThat(conversationAction.getTextReply()).isNotNull();
- }
-
- @Ignore // Doesn't work without a language-based model.
- @Test
- public void testSuggestConversationActions_textReplyOnly_noMax() {
- if (isTextClassifierDisabled()) return;
- ConversationActions.Message message =
- new ConversationActions.Message.Builder(
- ConversationActions.Message.PERSON_USER_OTHERS)
- .setText("Where are you?")
- .build();
- TextClassifier.EntityConfig typeConfig =
- new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
- .setIncludedTypes(
- Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
- .build();
- ConversationActions.Request request =
- new ConversationActions.Request.Builder(Collections.singletonList(message))
- .setTypeConfig(typeConfig)
- .build();
-
- ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
- assertTrue(conversationActions.getConversationActions().size() > 1);
- for (ConversationAction conversationAction :
- conversationActions.getConversationActions()) {
- assertThat(conversationAction,
- isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
- }
- }
-
- @Test
- public void testSuggestConversationActions_openUrl() {
- if (isTextClassifierDisabled()) return;
- ConversationActions.Message message =
- new ConversationActions.Message.Builder(
- ConversationActions.Message.PERSON_USER_OTHERS)
- .setText("Check this out: https://www.android.com")
- .build();
- TextClassifier.EntityConfig typeConfig =
- new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
- .setIncludedTypes(
- Collections.singletonList(ConversationAction.TYPE_OPEN_URL))
- .build();
- ConversationActions.Request request =
- new ConversationActions.Request.Builder(Collections.singletonList(message))
- .setMaxSuggestions(1)
- .setTypeConfig(typeConfig)
- .build();
-
- ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
- Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
- ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
- Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_OPEN_URL);
- Intent actionIntent = ExtrasUtils.getActionIntent(conversationAction.getExtras());
- Truth.assertThat(actionIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
- Truth.assertThat(actionIntent.getData()).isEqualTo(Uri.parse("https://www.android.com"));
- }
-
- @Ignore // Doesn't work without a language-based model.
- @Test
- public void testSuggestConversationActions_copy() {
- if (isTextClassifierDisabled()) return;
- ConversationActions.Message message =
- new ConversationActions.Message.Builder(
- ConversationActions.Message.PERSON_USER_OTHERS)
- .setText("Authentication code: 12345")
- .build();
- TextClassifier.EntityConfig typeConfig =
- new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
- .setIncludedTypes(
- Collections.singletonList(ConversationAction.TYPE_COPY))
- .build();
- ConversationActions.Request request =
- new ConversationActions.Request.Builder(Collections.singletonList(message))
- .setMaxSuggestions(1)
- .setTypeConfig(typeConfig)
- .build();
-
- ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
- Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
- ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
- Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_COPY);
- Truth.assertThat(conversationAction.getTextReply()).isAnyOf(null, "");
- Truth.assertThat(conversationAction.getAction()).isNull();
- String code = ExtrasUtils.getCopyText(conversationAction.getExtras());
- Truth.assertThat(code).isEqualTo("12345");
- Truth.assertThat(
- ExtrasUtils.getSerializedEntityData(conversationAction.getExtras())).isNotEmpty();
- }
-
- @Test
- public void testSuggestConversationActions_deduplicate() {
- Context context = new FakeContextBuilder()
- .setIntentComponent(Intent.ACTION_SENDTO, FakeContextBuilder.DEFAULT_COMPONENT)
- .build();
- ConversationActions.Message message =
- new ConversationActions.Message.Builder(
- ConversationActions.Message.PERSON_USER_OTHERS)
- .setText("a@android.com b@android.com")
- .build();
- ConversationActions.Request request =
- new ConversationActions.Request.Builder(Collections.singletonList(message))
- .setMaxSuggestions(3)
- .build();
-
- TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS);
- ConversationActions conversationActions = classifier.suggestConversationActions(request);
-
- Truth.assertThat(conversationActions.getConversationActions()).isEmpty();
- }
-
- private boolean isTextClassifierDisabled() {
- return mClassifier == null || mClassifier == TextClassifier.NO_OP;
- }
-
- private static Matcher<TextSelection> isTextSelection(
- final int startIndex, final int endIndex, final String type) {
- return new BaseMatcher<TextSelection>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextSelection) {
- TextSelection selection = (TextSelection) o;
- return startIndex == selection.getSelectionStartIndex()
- && endIndex == selection.getSelectionEndIndex()
- && typeMatches(selection, type);
- }
- return false;
- }
-
- private boolean typeMatches(TextSelection selection, String type) {
- return type == null
- || (selection.getEntityCount() > 0
- && type.trim().equalsIgnoreCase(selection.getEntity(0)));
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendValue(
- String.format("%d, %d, %s", startIndex, endIndex, type));
- }
- };
- }
-
- private static Matcher<TextLinks> isTextLinksContaining(
- final String text, final String substring, final String type) {
- return new BaseMatcher<TextLinks>() {
-
- @Override
- public void describeTo(Description description) {
- description.appendText("text=").appendValue(text)
- .appendText(", substring=").appendValue(substring)
- .appendText(", type=").appendValue(type);
- }
-
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextLinks) {
- for (TextLinks.TextLink link : ((TextLinks) o).getLinks()) {
- if (text.subSequence(link.getStart(), link.getEnd()).equals(substring)) {
- return type.equals(link.getEntity(0));
- }
- }
- }
- return false;
- }
- };
- }
-
- private static Matcher<TextClassification> isTextClassification(
- final String text, final String type) {
- return new BaseMatcher<TextClassification>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextClassification) {
- TextClassification result = (TextClassification) o;
- return text.equals(result.getText())
- && result.getEntityCount() > 0
- && type.equals(result.getEntity(0));
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("text=").appendValue(text)
- .appendText(", type=").appendValue(type);
- }
- };
- }
-
- private static Matcher<TextClassification> containsIntentWithAction(final String action) {
- return new BaseMatcher<TextClassification>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextClassification) {
- TextClassification result = (TextClassification) o;
- return ExtrasUtils.findAction(result, action) != null;
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("intent action=").appendValue(action);
- }
- };
- }
-
- private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
- return new BaseMatcher<TextLanguage>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextLanguage) {
- TextLanguage result = (TextLanguage) o;
- return result.getLocaleHypothesisCount() > 0
- && languageTag.equals(result.getLocale(0).toLanguageTag());
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("locale=").appendValue(languageTag);
- }
- };
- }
-
- private static Matcher<ConversationAction> isConversationAction(String actionType) {
- return new BaseMatcher<ConversationAction>() {
- @Override
- public boolean matches(Object o) {
- if (!(o instanceof ConversationAction)) {
- return false;
- }
- ConversationAction conversationAction =
- (ConversationAction) o;
- if (!actionType.equals(conversationAction.getType())) {
- return false;
- }
- if (ConversationAction.TYPE_TEXT_REPLY.equals(actionType)) {
- if (conversationAction.getTextReply() == null) {
- return false;
- }
- }
- if (conversationAction.getConfidenceScore() < 0
- || conversationAction.getConfidenceScore() > 1) {
- return false;
- }
- return true;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("actionType=").appendValue(actionType);
- }
- };
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
deleted file mode 100644
index 3ad26f5..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.intent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.textclassifier.FakeContextBuilder;
-import android.view.textclassifier.TextClassifier;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class LabeledIntentTest {
- private static final String TITLE_WITHOUT_ENTITY = "Map";
- private static final String TITLE_WITH_ENTITY = "Map NW14D1";
- private static final String DESCRIPTION = "Check the map";
- private static final String DESCRIPTION_WITH_APP_NAME = "Use %1$s to open map";
- private static final Intent INTENT =
- new Intent(Intent.ACTION_VIEW).setDataAndNormalize(Uri.parse("http://www.android.com"));
- private static final int REQUEST_CODE = 42;
- private static final Bundle TEXT_LANGUAGES_BUNDLE = Bundle.EMPTY;
- private static final String APP_LABEL = "fake";
-
- private Context mContext;
-
- @Before
- public void setup() {
- final ComponentName component = FakeContextBuilder.DEFAULT_COMPONENT;
- mContext = new FakeContextBuilder()
- .setIntentComponent(Intent.ACTION_VIEW, component)
- .setAppLabel(component.getPackageName(), APP_LABEL)
- .build();
- }
-
- @Test
- public void resolve_preferTitleWithEntity() {
- LabeledIntent labeledIntent = new LabeledIntent(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- DESCRIPTION,
- null,
- INTENT,
- REQUEST_CODE
- );
-
- LabeledIntent.Result result = labeledIntent.resolve(
- mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
-
- assertThat(result).isNotNull();
- assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITH_ENTITY);
- assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
- Intent intent = result.resolvedIntent;
- assertThat(intent.getAction()).isEqualTo(intent.getAction());
- assertThat(intent.getComponent()).isNotNull();
- assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
- }
-
- @Test
- public void resolve_useAvailableTitle() {
- LabeledIntent labeledIntent = new LabeledIntent(
- TITLE_WITHOUT_ENTITY,
- null,
- DESCRIPTION,
- null,
- INTENT,
- REQUEST_CODE
- );
-
- LabeledIntent.Result result = labeledIntent.resolve(
- mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
-
- assertThat(result).isNotNull();
- assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
- assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
- Intent intent = result.resolvedIntent;
- assertThat(intent.getAction()).isEqualTo(intent.getAction());
- assertThat(intent.getComponent()).isNotNull();
- }
-
- @Test
- public void resolve_titleChooser() {
- LabeledIntent labeledIntent = new LabeledIntent(
- TITLE_WITHOUT_ENTITY,
- null,
- DESCRIPTION,
- null,
- INTENT,
- REQUEST_CODE
- );
-
- LabeledIntent.Result result = labeledIntent.resolve(
- mContext, (labeledIntent1, resolveInfo) -> "chooser", TEXT_LANGUAGES_BUNDLE);
-
- assertThat(result).isNotNull();
- assertThat(result.remoteAction.getTitle()).isEqualTo("chooser");
- assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
- Intent intent = result.resolvedIntent;
- assertThat(intent.getAction()).isEqualTo(intent.getAction());
- assertThat(intent.getComponent()).isNotNull();
- }
-
- @Test
- public void resolve_titleChooserReturnsNull() {
- LabeledIntent labeledIntent = new LabeledIntent(
- TITLE_WITHOUT_ENTITY,
- null,
- DESCRIPTION,
- null,
- INTENT,
- REQUEST_CODE
- );
-
- LabeledIntent.Result result = labeledIntent.resolve(
- mContext, (labeledIntent1, resolveInfo) -> null, TEXT_LANGUAGES_BUNDLE);
-
- assertThat(result).isNotNull();
- assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
- assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
- Intent intent = result.resolvedIntent;
- assertThat(intent.getAction()).isEqualTo(intent.getAction());
- assertThat(intent.getComponent()).isNotNull();
- }
-
- @Test
- public void resolve_missingTitle() {
- assertThrows(
- IllegalArgumentException.class,
- () ->
- new LabeledIntent(
- null,
- null,
- DESCRIPTION,
- null,
- INTENT,
- REQUEST_CODE
- ));
- }
-
- @Test
- public void resolve_noIntentHandler() {
- // See setup(). mContext can only resolve Intent.ACTION_VIEW.
- Intent unresolvableIntent = new Intent(Intent.ACTION_TRANSLATE);
- LabeledIntent labeledIntent = new LabeledIntent(
- TITLE_WITHOUT_ENTITY,
- null,
- DESCRIPTION,
- null,
- unresolvableIntent,
- REQUEST_CODE);
-
- LabeledIntent.Result result = labeledIntent.resolve(mContext, null, null);
-
- assertThat(result).isNull();
- }
-
- @Test
- public void resolve_descriptionWithAppName() {
- LabeledIntent labeledIntent = new LabeledIntent(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- INTENT,
- REQUEST_CODE
- );
-
- LabeledIntent.Result result = labeledIntent.resolve(
- mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
-
- assertThat(result).isNotNull();
- assertThat(result.remoteAction.getContentDescription()).isEqualTo("Use fake to open map");
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
deleted file mode 100644
index 8891d3f..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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.intent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Intent;
-import android.view.textclassifier.TextClassifier;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.textclassifier.AnnotatorModel;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class LegacyIntentClassificationFactoryTest {
-
- private static final String TEXT = "text";
-
- private LegacyClassificationIntentFactory mLegacyIntentClassificationFactory;
-
- @Before
- public void setup() {
- mLegacyIntentClassificationFactory = new LegacyClassificationIntentFactory();
- }
-
- @Test
- public void create_typeDictionary() {
- AnnotatorModel.ClassificationResult classificationResult =
- new AnnotatorModel.ClassificationResult(
- TextClassifier.TYPE_DICTIONARY,
- 1.0f,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- 0L,
- 0L,
- 0d);
-
- List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
- InstrumentationRegistry.getContext(),
- TEXT,
- /* foreignText */ false,
- null,
- classificationResult);
-
- assertThat(intents).hasSize(1);
- LabeledIntent labeledIntent = intents.get(0);
- Intent intent = labeledIntent.intent;
- assertThat(intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
- assertThat(intent.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(TEXT);
- }
-
- @Test
- public void create_translateAndDictionary() {
- AnnotatorModel.ClassificationResult classificationResult =
- new AnnotatorModel.ClassificationResult(
- TextClassifier.TYPE_DICTIONARY,
- 1.0f,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- 0L,
- 0L,
- 0d);
-
- List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
- InstrumentationRegistry.getContext(),
- TEXT,
- /* foreignText */ true,
- null,
- classificationResult);
-
- assertThat(intents).hasSize(2);
- assertThat(intents.get(0).intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
- assertThat(intents.get(1).intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
deleted file mode 100644
index bcea5fe..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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.intent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.same;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.Intent;
-import android.view.textclassifier.TextClassifier;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.textclassifier.AnnotatorModel;
-import com.google.android.textclassifier.RemoteActionTemplate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TemplateClassificationIntentFactoryTest {
-
- private static final String TEXT = "text";
- private static final String TITLE_WITHOUT_ENTITY = "Map";
- private static final String DESCRIPTION = "Opens in Maps";
- private static final String DESCRIPTION_WITH_APP_NAME = "Use %1$s to open Map";
- private static final String ACTION = Intent.ACTION_VIEW;
-
- @Mock
- private ClassificationIntentFactory mFallback;
- private TemplateClassificationIntentFactory mTemplateClassificationIntentFactory;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mTemplateClassificationIntentFactory = new TemplateClassificationIntentFactory(
- new TemplateIntentFactory(),
- mFallback);
- }
-
- @Test
- public void create_foreignText() {
- AnnotatorModel.ClassificationResult classificationResult =
- new AnnotatorModel.ClassificationResult(
- TextClassifier.TYPE_ADDRESS,
- 1.0f,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- createRemoteActionTemplates(),
- 0L,
- 0L,
- 0d);
-
- List<LabeledIntent> intents =
- mTemplateClassificationIntentFactory.create(
- InstrumentationRegistry.getContext(),
- TEXT,
- /* foreignText */ true,
- null,
- classificationResult);
-
- assertThat(intents).hasSize(2);
- LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
- Intent intent = labeledIntent.intent;
- assertThat(intent.getAction()).isEqualTo(ACTION);
-
- labeledIntent = intents.get(1);
- intent = labeledIntent.intent;
- assertThat(intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
- }
-
- @Test
- public void create_notForeignText() {
- AnnotatorModel.ClassificationResult classificationResult =
- new AnnotatorModel.ClassificationResult(
- TextClassifier.TYPE_ADDRESS,
- 1.0f,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- createRemoteActionTemplates(),
- 0L,
- 0L,
- 0d);
-
- List<LabeledIntent> intents =
- mTemplateClassificationIntentFactory.create(
- InstrumentationRegistry.getContext(),
- TEXT,
- /* foreignText */ false,
- null,
- classificationResult);
-
- assertThat(intents).hasSize(1);
- LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
- Intent intent = labeledIntent.intent;
- assertThat(intent.getAction()).isEqualTo(ACTION);
- }
-
- @Test
- public void create_nullTemplate() {
- AnnotatorModel.ClassificationResult classificationResult =
- new AnnotatorModel.ClassificationResult(
- TextClassifier.TYPE_ADDRESS,
- 1.0f,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- 0L,
- 0L,
- 0d);
-
- mTemplateClassificationIntentFactory.create(
- InstrumentationRegistry.getContext(),
- TEXT,
- /* foreignText */ false,
- null,
- classificationResult);
-
-
- verify(mFallback).create(
- same(InstrumentationRegistry.getContext()), eq(TEXT), eq(false), eq(null),
- same(classificationResult));
- }
-
- @Test
- public void create_emptyResult() {
- AnnotatorModel.ClassificationResult classificationResult =
- new AnnotatorModel.ClassificationResult(
- TextClassifier.TYPE_ADDRESS,
- 1.0f,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- new RemoteActionTemplate[0],
- 0L,
- 0L,
- 0d);
-
- mTemplateClassificationIntentFactory.create(
- InstrumentationRegistry.getContext(),
- TEXT,
- /* foreignText */ false,
- null,
- classificationResult);
-
-
- verify(mFallback, never()).create(
- any(Context.class), eq(TEXT), eq(false), eq(null),
- any(AnnotatorModel.ClassificationResult.class));
- }
-
-
- private static RemoteActionTemplate[] createRemoteActionTemplates() {
- return new RemoteActionTemplate[]{
- new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- null,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- ACTION,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- )
- };
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
deleted file mode 100644
index a33c358..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * 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.intent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Intent;
-import android.net.Uri;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.textclassifier.NamedVariant;
-import com.google.android.textclassifier.RemoteActionTemplate;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TemplateIntentFactoryTest {
-
- private static final String TEXT = "text";
- private static final String TITLE_WITHOUT_ENTITY = "Map";
- private static final String TITLE_WITH_ENTITY = "Map NW14D1";
- private static final String DESCRIPTION = "Check the map";
- private static final String DESCRIPTION_WITH_APP_NAME = "Use %1$s to open map";
- private static final String ACTION = Intent.ACTION_VIEW;
- private static final String DATA = Uri.parse("http://www.android.com").toString();
- private static final String TYPE = "text/html";
- private static final Integer FLAG = Intent.FLAG_ACTIVITY_NEW_TASK;
- private static final String[] CATEGORY =
- new String[]{Intent.CATEGORY_DEFAULT, Intent.CATEGORY_APP_BROWSER};
- private static final String PACKAGE_NAME = "pkg.name";
- private static final String KEY_ONE = "key1";
- private static final String VALUE_ONE = "value1";
- private static final String KEY_TWO = "key2";
- private static final int VALUE_TWO = 42;
-
- private static final NamedVariant[] NAMED_VARIANTS = new NamedVariant[]{
- new NamedVariant(KEY_ONE, VALUE_ONE),
- new NamedVariant(KEY_TWO, VALUE_TWO)
- };
- private static final Integer REQUEST_CODE = 10;
-
- private TemplateIntentFactory mTemplateIntentFactory;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mTemplateIntentFactory = new TemplateIntentFactory();
- }
-
- @Test
- public void create_full() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- ACTION,
- DATA,
- TYPE,
- FLAG,
- CATEGORY,
- /* packageName */ null,
- NAMED_VARIANTS,
- REQUEST_CODE
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
-
- assertThat(intents).hasSize(1);
- LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
- assertThat(labeledIntent.titleWithEntity).isEqualTo(TITLE_WITH_ENTITY);
- assertThat(labeledIntent.description).isEqualTo(DESCRIPTION);
- assertThat(labeledIntent.descriptionWithAppName).isEqualTo(DESCRIPTION_WITH_APP_NAME);
- assertThat(labeledIntent.requestCode).isEqualTo(REQUEST_CODE);
- Intent intent = labeledIntent.intent;
- assertThat(intent.getAction()).isEqualTo(ACTION);
- assertThat(intent.getData().toString()).isEqualTo(DATA);
- assertThat(intent.getType()).isEqualTo(TYPE);
- assertThat(intent.getFlags()).isEqualTo(FLAG);
- assertThat(intent.getCategories()).containsExactly((Object[]) CATEGORY);
- assertThat(intent.getPackage()).isNull();
- assertThat(intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
- assertThat(intent.getIntExtra(KEY_TWO, 0)).isEqualTo(VALUE_TWO);
- }
-
- @Test
- public void normalizesScheme() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- ACTION,
- "HTTp://www.android.com",
- TYPE,
- FLAG,
- CATEGORY,
- /* packageName */ null,
- NAMED_VARIANTS,
- REQUEST_CODE
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
-
- String data = intents.get(0).intent.getData().toString();
- assertThat(data).isEqualTo("http://www.android.com");
- }
-
- @Test
- public void create_minimal() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- null,
- DESCRIPTION,
- null,
- ACTION,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
-
- assertThat(intents).hasSize(1);
- LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
- assertThat(labeledIntent.titleWithEntity).isNull();
- assertThat(labeledIntent.description).isEqualTo(DESCRIPTION);
- assertThat(labeledIntent.requestCode).isEqualTo(
- LabeledIntent.DEFAULT_REQUEST_CODE);
- Intent intent = labeledIntent.intent;
- assertThat(intent.getAction()).isEqualTo(ACTION);
- assertThat(intent.getData()).isNull();
- assertThat(intent.getType()).isNull();
- assertThat(intent.getFlags()).isEqualTo(0);
- assertThat(intent.getCategories()).isNull();
- assertThat(intent.getPackage()).isNull();
- }
-
- @Test
- public void invalidTemplate_nullTemplate() {
- RemoteActionTemplate remoteActionTemplate = null;
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
-
- assertThat(intents).isEmpty();
- }
-
- @Test
- public void invalidTemplate_nonEmptyPackageName() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- ACTION,
- DATA,
- TYPE,
- FLAG,
- CATEGORY,
- PACKAGE_NAME,
- NAMED_VARIANTS,
- REQUEST_CODE
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
-
- assertThat(intents).isEmpty();
- }
-
- @Test
- public void invalidTemplate_emptyTitle() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- null,
- null,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- ACTION,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
-
- assertThat(intents).isEmpty();
- }
-
- @Test
- public void invalidTemplate_emptyDescription() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- null,
- null,
- ACTION,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
-
- assertThat(intents).isEmpty();
- }
-
- @Test
- public void invalidTemplate_emptyIntentAction() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE_WITHOUT_ENTITY,
- TITLE_WITH_ENTITY,
- DESCRIPTION,
- DESCRIPTION_WITH_APP_NAME,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
-
- List<LabeledIntent> intents =
- mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
-
- assertThat(intents).isEmpty();
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
deleted file mode 100644
index 5e8e582..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2017 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.logging;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-
-import android.metrics.LogMaker;
-import android.util.ArrayMap;
-import android.view.textclassifier.GenerateLinksLogger;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class GenerateLinksLoggerTest {
-
- private static final String PACKAGE_NAME = "packageName";
- private static final String ZERO = "0";
- private static final int LATENCY_MS = 123;
-
- @Test
- public void testLogGenerateLinks() {
- final String phoneText = "+12122537077";
- final String addressText = "1600 Amphitheater Parkway, Mountain View, CA";
- final String testText = "The number is " + phoneText + ", the address is " + addressText;
- final int phoneOffset = testText.indexOf(phoneText);
- final int addressOffset = testText.indexOf(addressText);
-
- final Map<String, Float> phoneEntityScores = new ArrayMap<>();
- phoneEntityScores.put(TextClassifier.TYPE_PHONE, 0.9f);
- phoneEntityScores.put(TextClassifier.TYPE_OTHER, 0.1f);
- final Map<String, Float> addressEntityScores = new ArrayMap<>();
- addressEntityScores.put(TextClassifier.TYPE_ADDRESS, 1f);
-
- TextLinks links = new TextLinks.Builder(testText)
- .addLink(phoneOffset, phoneOffset + phoneText.length(), phoneEntityScores)
- .addLink(addressOffset, addressOffset + addressText.length(), addressEntityScores)
- .build();
-
- // Set up mock.
- MetricsLogger metricsLogger = mock(MetricsLogger.class);
- ArgumentCaptor<LogMaker> logMakerCapture = ArgumentCaptor.forClass(LogMaker.class);
- doNothing().when(metricsLogger).write(logMakerCapture.capture());
-
- // Generate the log.
- GenerateLinksLogger logger = new GenerateLinksLogger(1 /* sampleRate */, metricsLogger);
- logger.logGenerateLinks(testText, links, PACKAGE_NAME, LATENCY_MS);
-
- // Validate.
- List<LogMaker> logs = logMakerCapture.getAllValues();
- assertEquals(3, logs.size());
- assertHasLog(logs, "" /* entityType */, 2, phoneText.length() + addressText.length(),
- testText.length());
- assertHasLog(logs, TextClassifier.TYPE_ADDRESS, 1, addressText.length(),
- testText.length());
- assertHasLog(logs, TextClassifier.TYPE_PHONE, 1, phoneText.length(),
- testText.length());
- }
-
- private void assertHasLog(List<LogMaker> logs, String entityType, int numLinks,
- int linkTextLength, int textLength) {
- for (LogMaker log : logs) {
- if (!entityType.equals(getEntityType(log))) {
- continue;
- }
- assertEquals(PACKAGE_NAME, log.getPackageName());
- assertNotNull(Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_CALL_ID)));
- assertEquals(numLinks, getIntValue(log, MetricsEvent.FIELD_LINKIFY_NUM_LINKS));
- assertEquals(linkTextLength, getIntValue(log, MetricsEvent.FIELD_LINKIFY_LINK_LENGTH));
- assertEquals(textLength, getIntValue(log, MetricsEvent.FIELD_LINKIFY_TEXT_LENGTH));
- assertEquals(LATENCY_MS, getIntValue(log, MetricsEvent.FIELD_LINKIFY_LATENCY));
- return;
- }
- fail("No log for entity type \"" + entityType + "\"");
- }
-
- private static String getEntityType(LogMaker log) {
- return Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_ENTITY_TYPE), "");
- }
-
- private static int getIntValue(LogMaker log, int eventField) {
- return Integer.parseInt(Objects.toString(log.getTaggedData(eventField), ZERO));
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java
deleted file mode 100644
index 321a7f2..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.logging;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.google.common.truth.Truth;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SmartSelectionEventTrackerTest {
-
- @Test
- public void getVersionInfo_valid() {
- String signature = "a|702|b";
- String versionInfo = SmartSelectionEventTracker.SelectionEvent.getVersionInfo(signature);
- Truth.assertThat(versionInfo).isEqualTo("702");
- }
-
- @Test
- public void getVersionInfo_invalid() {
- String signature = "|702";
- String versionInfo = SmartSelectionEventTracker.SelectionEvent.getVersionInfo(signature);
- Truth.assertThat(versionInfo).isEmpty();
- }
-}
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
deleted file mode 100644
index 2c540e5..0000000
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.logging;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.CONVERSATION_ACTIONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME;
-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_WIDGET_TYPE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.metrics.LogMaker;
-import android.view.textclassifier.ConversationAction;
-import android.view.textclassifier.TextClassificationContext;
-import android.view.textclassifier.TextClassifierEvent;
-import android.view.textclassifier.TextClassifierEventTronLogger;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.logging.MetricsLogger;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TextClassifierEventTronLoggerTest {
- private static final String WIDGET_TYPE = "notification";
- private static final String PACKAGE_NAME = "pkg";
-
- @Mock
- private MetricsLogger mMetricsLogger;
- private TextClassifierEventTronLogger mTextClassifierEventTronLogger;
-
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mTextClassifierEventTronLogger = new TextClassifierEventTronLogger(mMetricsLogger);
- }
-
- @Test
- public void testWriteEvent() {
- TextClassificationContext textClassificationContext =
- new TextClassificationContext.Builder(PACKAGE_NAME, WIDGET_TYPE)
- .build();
- TextClassifierEvent.ConversationActionsEvent textClassifierEvent =
- new TextClassifierEvent.ConversationActionsEvent.Builder(
- TextClassifierEvent.TYPE_SMART_ACTION)
- .setEntityTypes(ConversationAction.TYPE_CALL_PHONE)
- .setScores(0.5f)
- .setEventContext(textClassificationContext)
- .build();
-
- mTextClassifierEventTronLogger.writeEvent(textClassifierEvent);
-
- ArgumentCaptor<LogMaker> captor = ArgumentCaptor.forClass(LogMaker.class);
- Mockito.verify(mMetricsLogger).write(captor.capture());
- LogMaker logMaker = captor.getValue();
- assertThat(logMaker.getCategory()).isEqualTo(CONVERSATION_ACTIONS);
- assertThat(logMaker.getSubtype()).isEqualTo(ACTION_TEXT_SELECTION_SMART_SHARE);
- assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE))
- .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
- assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE))
- .isWithin(0.00001f).of(0.5f);
- // Never write event time.
- assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME)).isNull();
- assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
- assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE))
- .isEqualTo(WIDGET_TYPE);
-
- }
-
- @Test
- public void testWriteEvent_unsupportedCategory() {
- TextClassifierEvent.TextSelectionEvent textClassifierEvent =
- new TextClassifierEvent.TextSelectionEvent.Builder(
- TextClassifierEvent.TYPE_SMART_ACTION)
- .build();
-
- mTextClassifierEventTronLogger.writeEvent(textClassifierEvent);
-
- Mockito.verify(mMetricsLogger, Mockito.never()).write(Mockito.any(LogMaker.class));
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index abfb4fb..8cf146e 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -48,6 +48,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
@@ -56,6 +57,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -87,6 +89,7 @@
static {
MANAGED_PROFILE_INFO.id = 10;
MANAGED_PROFILE_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE;
+ MANAGED_PROFILE_INFO.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
}
private static UserInfo CURRENT_USER_INFO = new UserInfo();
@@ -116,12 +119,21 @@
private Context mContext;
public static final String PHONE_NUMBER = "123-456-789";
+ private int mDeviceProvisionedInitialValue;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getTargetContext();
sInjector = spy(new TestInjector());
+ mDeviceProvisionedInitialValue = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, /* def= */ 0);
+ }
+
+ @After
+ public void tearDown() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
+ mDeviceProvisionedInitialValue);
}
@Test
@@ -533,6 +545,22 @@
}
@Test
+ public void shouldSkipDisclosure_duringDeviceSetup() throws RemoteException {
+ setupShouldSkipDisclosureTest();
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
+ /* value= */ 0);
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class)
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.fromParts("http", "apache.org", null));
+
+ mActivityRule.launchActivity(intent);
+
+ verify(mIPm).canForwardTo(any(), any(), anyInt(), anyInt());
+ verify(sInjector, never()).showToast(anyInt(), anyInt());
+ }
+
+ @Test
public void forwardToManagedProfile_LoggingTest() throws Exception {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
@@ -590,6 +618,8 @@
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
sActivityName = "MyTestActivity";
sPackageName = "test.package.name";
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
+ /* value= */ 1);
when(mApplicationInfo.isSystemApp()).thenReturn(true);
// Managed profile exists.
List<UserInfo> profiles = new ArrayList<>();
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index e748bd8..6c6c5c9 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -15,1474 +15,1478 @@
/* 11 */ {'C', 'a', 'r', 'i'},
/* 12 */ {'C', 'h', 'a', 'm'},
/* 13 */ {'C', 'h', 'e', 'r'},
- /* 14 */ {'C', 'o', 'p', 't'},
- /* 15 */ {'C', 'p', 'r', 't'},
- /* 16 */ {'C', 'y', 'r', 'l'},
- /* 17 */ {'D', 'e', 'v', 'a'},
- /* 18 */ {'E', 'g', 'y', 'p'},
- /* 19 */ {'E', 't', 'h', 'i'},
- /* 20 */ {'G', 'e', 'o', 'r'},
- /* 21 */ {'G', 'o', 'n', 'g'},
- /* 22 */ {'G', 'o', 'n', 'm'},
- /* 23 */ {'G', 'o', 't', 'h'},
- /* 24 */ {'G', 'r', 'e', 'k'},
- /* 25 */ {'G', 'u', 'j', 'r'},
- /* 26 */ {'G', 'u', 'r', 'u'},
- /* 27 */ {'H', 'a', 'n', 's'},
- /* 28 */ {'H', 'a', 'n', 't'},
- /* 29 */ {'H', 'a', 't', 'r'},
- /* 30 */ {'H', 'e', 'b', 'r'},
- /* 31 */ {'H', 'l', 'u', 'w'},
- /* 32 */ {'H', 'm', 'n', 'g'},
- /* 33 */ {'H', 'm', 'n', 'p'},
- /* 34 */ {'I', 't', 'a', 'l'},
- /* 35 */ {'J', 'p', 'a', 'n'},
- /* 36 */ {'K', 'a', 'l', 'i'},
- /* 37 */ {'K', 'a', 'n', 'a'},
- /* 38 */ {'K', 'h', 'a', 'r'},
- /* 39 */ {'K', 'h', 'm', 'r'},
- /* 40 */ {'K', 'n', 'd', 'a'},
- /* 41 */ {'K', 'o', 'r', 'e'},
- /* 42 */ {'L', 'a', 'n', 'a'},
- /* 43 */ {'L', 'a', 'o', 'o'},
- /* 44 */ {'L', 'a', 't', 'n'},
- /* 45 */ {'L', 'e', 'p', 'c'},
- /* 46 */ {'L', 'i', 'n', 'a'},
- /* 47 */ {'L', 'i', 's', 'u'},
- /* 48 */ {'L', 'y', 'c', 'i'},
- /* 49 */ {'L', 'y', 'd', 'i'},
- /* 50 */ {'M', 'a', 'n', 'd'},
- /* 51 */ {'M', 'a', 'n', 'i'},
- /* 52 */ {'M', 'e', 'r', 'c'},
- /* 53 */ {'M', 'l', 'y', 'm'},
- /* 54 */ {'M', 'o', 'n', 'g'},
- /* 55 */ {'M', 'r', 'o', 'o'},
- /* 56 */ {'M', 'y', 'm', 'r'},
- /* 57 */ {'N', 'a', 'r', 'b'},
- /* 58 */ {'N', 'k', 'o', 'o'},
- /* 59 */ {'N', 's', 'h', 'u'},
- /* 60 */ {'O', 'g', 'a', 'm'},
- /* 61 */ {'O', 'r', 'k', 'h'},
- /* 62 */ {'O', 'r', 'y', 'a'},
- /* 63 */ {'O', 's', 'g', 'e'},
- /* 64 */ {'P', 'a', 'u', 'c'},
- /* 65 */ {'P', 'h', 'l', 'i'},
- /* 66 */ {'P', 'h', 'n', 'x'},
- /* 67 */ {'P', 'l', 'r', 'd'},
- /* 68 */ {'P', 'r', 't', 'i'},
- /* 69 */ {'R', 'u', 'n', 'r'},
- /* 70 */ {'S', 'a', 'm', 'r'},
- /* 71 */ {'S', 'a', 'r', 'b'},
- /* 72 */ {'S', 'a', 'u', 'r'},
- /* 73 */ {'S', 'g', 'n', 'w'},
- /* 74 */ {'S', 'i', 'n', 'h'},
- /* 75 */ {'S', 'o', 'g', 'd'},
- /* 76 */ {'S', 'o', 'r', 'a'},
- /* 77 */ {'S', 'o', 'y', 'o'},
- /* 78 */ {'S', 'y', 'r', 'c'},
- /* 79 */ {'T', 'a', 'l', 'e'},
- /* 80 */ {'T', 'a', 'l', 'u'},
- /* 81 */ {'T', 'a', 'm', 'l'},
- /* 82 */ {'T', 'a', 'n', 'g'},
- /* 83 */ {'T', 'a', 'v', 't'},
- /* 84 */ {'T', 'e', 'l', 'u'},
- /* 85 */ {'T', 'f', 'n', 'g'},
- /* 86 */ {'T', 'h', 'a', 'a'},
- /* 87 */ {'T', 'h', 'a', 'i'},
- /* 88 */ {'T', 'i', 'b', 't'},
- /* 89 */ {'U', 'g', 'a', 'r'},
- /* 90 */ {'V', 'a', 'i', 'i'},
- /* 91 */ {'W', 'c', 'h', 'o'},
- /* 92 */ {'X', 'p', 'e', 'o'},
- /* 93 */ {'X', 's', 'u', 'x'},
- /* 94 */ {'Y', 'i', 'i', 'i'},
- /* 95 */ {'~', '~', '~', 'A'},
- /* 96 */ {'~', '~', '~', 'B'},
+ /* 14 */ {'C', 'h', 'r', 's'},
+ /* 15 */ {'C', 'o', 'p', 't'},
+ /* 16 */ {'C', 'p', 'r', 't'},
+ /* 17 */ {'C', 'y', 'r', 'l'},
+ /* 18 */ {'D', 'e', 'v', 'a'},
+ /* 19 */ {'E', 'g', 'y', 'p'},
+ /* 20 */ {'E', 't', 'h', 'i'},
+ /* 21 */ {'G', 'e', 'o', 'r'},
+ /* 22 */ {'G', 'o', 'n', 'g'},
+ /* 23 */ {'G', 'o', 'n', 'm'},
+ /* 24 */ {'G', 'o', 't', 'h'},
+ /* 25 */ {'G', 'r', 'e', 'k'},
+ /* 26 */ {'G', 'u', 'j', 'r'},
+ /* 27 */ {'G', 'u', 'r', 'u'},
+ /* 28 */ {'H', 'a', 'n', 's'},
+ /* 29 */ {'H', 'a', 'n', 't'},
+ /* 30 */ {'H', 'a', 't', 'r'},
+ /* 31 */ {'H', 'e', 'b', 'r'},
+ /* 32 */ {'H', 'l', 'u', 'w'},
+ /* 33 */ {'H', 'm', 'n', 'g'},
+ /* 34 */ {'H', 'm', 'n', 'p'},
+ /* 35 */ {'I', 't', 'a', 'l'},
+ /* 36 */ {'J', 'p', 'a', 'n'},
+ /* 37 */ {'K', 'a', 'l', 'i'},
+ /* 38 */ {'K', 'a', 'n', 'a'},
+ /* 39 */ {'K', 'h', 'a', 'r'},
+ /* 40 */ {'K', 'h', 'm', 'r'},
+ /* 41 */ {'K', 'i', 't', 's'},
+ /* 42 */ {'K', 'n', 'd', 'a'},
+ /* 43 */ {'K', 'o', 'r', 'e'},
+ /* 44 */ {'L', 'a', 'n', 'a'},
+ /* 45 */ {'L', 'a', 'o', 'o'},
+ /* 46 */ {'L', 'a', 't', 'n'},
+ /* 47 */ {'L', 'e', 'p', 'c'},
+ /* 48 */ {'L', 'i', 'n', 'a'},
+ /* 49 */ {'L', 'i', 's', 'u'},
+ /* 50 */ {'L', 'y', 'c', 'i'},
+ /* 51 */ {'L', 'y', 'd', 'i'},
+ /* 52 */ {'M', 'a', 'n', 'd'},
+ /* 53 */ {'M', 'a', 'n', 'i'},
+ /* 54 */ {'M', 'e', 'r', 'c'},
+ /* 55 */ {'M', 'l', 'y', 'm'},
+ /* 56 */ {'M', 'o', 'n', 'g'},
+ /* 57 */ {'M', 'r', 'o', 'o'},
+ /* 58 */ {'M', 'y', 'm', 'r'},
+ /* 59 */ {'N', 'a', 'r', 'b'},
+ /* 60 */ {'N', 'k', 'o', 'o'},
+ /* 61 */ {'N', 's', 'h', 'u'},
+ /* 62 */ {'O', 'g', 'a', 'm'},
+ /* 63 */ {'O', 'r', 'k', 'h'},
+ /* 64 */ {'O', 'r', 'y', 'a'},
+ /* 65 */ {'O', 's', 'g', 'e'},
+ /* 66 */ {'P', 'a', 'u', 'c'},
+ /* 67 */ {'P', 'h', 'l', 'i'},
+ /* 68 */ {'P', 'h', 'n', 'x'},
+ /* 69 */ {'P', 'l', 'r', 'd'},
+ /* 70 */ {'P', 'r', 't', 'i'},
+ /* 71 */ {'R', 'u', 'n', 'r'},
+ /* 72 */ {'S', 'a', 'm', 'r'},
+ /* 73 */ {'S', 'a', 'r', 'b'},
+ /* 74 */ {'S', 'a', 'u', 'r'},
+ /* 75 */ {'S', 'g', 'n', 'w'},
+ /* 76 */ {'S', 'i', 'n', 'h'},
+ /* 77 */ {'S', 'o', 'g', 'd'},
+ /* 78 */ {'S', 'o', 'r', 'a'},
+ /* 79 */ {'S', 'o', 'y', 'o'},
+ /* 80 */ {'S', 'y', 'r', 'c'},
+ /* 81 */ {'T', 'a', 'l', 'e'},
+ /* 82 */ {'T', 'a', 'l', 'u'},
+ /* 83 */ {'T', 'a', 'm', 'l'},
+ /* 84 */ {'T', 'a', 'n', 'g'},
+ /* 85 */ {'T', 'a', 'v', 't'},
+ /* 86 */ {'T', 'e', 'l', 'u'},
+ /* 87 */ {'T', 'f', 'n', 'g'},
+ /* 88 */ {'T', 'h', 'a', 'a'},
+ /* 89 */ {'T', 'h', 'a', 'i'},
+ /* 90 */ {'T', 'i', 'b', 't'},
+ /* 91 */ {'U', 'g', 'a', 'r'},
+ /* 92 */ {'V', 'a', 'i', 'i'},
+ /* 93 */ {'W', 'c', 'h', 'o'},
+ /* 94 */ {'X', 'p', 'e', 'o'},
+ /* 95 */ {'X', 's', 'u', 'x'},
+ /* 96 */ {'Y', 'i', 'i', 'i'},
+ /* 97 */ {'~', '~', '~', 'A'},
+ /* 98 */ {'~', '~', '~', 'B'},
};
const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
- {0x61610000u, 44u}, // aa -> Latn
- {0xA0000000u, 44u}, // aai -> Latn
- {0xA8000000u, 44u}, // aak -> Latn
- {0xD0000000u, 44u}, // aau -> Latn
- {0x61620000u, 16u}, // ab -> Cyrl
- {0xA0200000u, 44u}, // abi -> Latn
- {0xC0200000u, 16u}, // abq -> Cyrl
- {0xC4200000u, 44u}, // abr -> Latn
- {0xCC200000u, 44u}, // abt -> Latn
- {0xE0200000u, 44u}, // aby -> Latn
- {0x8C400000u, 44u}, // acd -> Latn
- {0x90400000u, 44u}, // ace -> Latn
- {0x9C400000u, 44u}, // ach -> Latn
- {0x80600000u, 44u}, // ada -> Latn
- {0x90600000u, 44u}, // ade -> Latn
- {0xA4600000u, 44u}, // adj -> Latn
- {0xBC600000u, 88u}, // adp -> Tibt
- {0xE0600000u, 16u}, // ady -> Cyrl
- {0xE4600000u, 44u}, // adz -> Latn
+ {0x61610000u, 46u}, // aa -> Latn
+ {0xA0000000u, 46u}, // aai -> Latn
+ {0xA8000000u, 46u}, // aak -> Latn
+ {0xD0000000u, 46u}, // aau -> Latn
+ {0x61620000u, 17u}, // ab -> Cyrl
+ {0xA0200000u, 46u}, // abi -> Latn
+ {0xC0200000u, 17u}, // abq -> Cyrl
+ {0xC4200000u, 46u}, // abr -> Latn
+ {0xCC200000u, 46u}, // abt -> Latn
+ {0xE0200000u, 46u}, // aby -> Latn
+ {0x8C400000u, 46u}, // acd -> Latn
+ {0x90400000u, 46u}, // ace -> Latn
+ {0x9C400000u, 46u}, // ach -> Latn
+ {0x80600000u, 46u}, // ada -> Latn
+ {0x90600000u, 46u}, // ade -> Latn
+ {0xA4600000u, 46u}, // adj -> Latn
+ {0xBC600000u, 90u}, // adp -> Tibt
+ {0xE0600000u, 17u}, // ady -> Cyrl
+ {0xE4600000u, 46u}, // adz -> Latn
{0x61650000u, 4u}, // ae -> Avst
{0x84800000u, 1u}, // aeb -> Arab
- {0xE0800000u, 44u}, // aey -> Latn
- {0x61660000u, 44u}, // af -> Latn
- {0x88C00000u, 44u}, // agc -> Latn
- {0x8CC00000u, 44u}, // agd -> Latn
- {0x98C00000u, 44u}, // agg -> Latn
- {0xB0C00000u, 44u}, // agm -> Latn
- {0xB8C00000u, 44u}, // ago -> Latn
- {0xC0C00000u, 44u}, // agq -> Latn
- {0x80E00000u, 44u}, // aha -> Latn
- {0xACE00000u, 44u}, // ahl -> Latn
+ {0xE0800000u, 46u}, // aey -> Latn
+ {0x61660000u, 46u}, // af -> Latn
+ {0x88C00000u, 46u}, // agc -> Latn
+ {0x8CC00000u, 46u}, // agd -> Latn
+ {0x98C00000u, 46u}, // agg -> Latn
+ {0xB0C00000u, 46u}, // agm -> Latn
+ {0xB8C00000u, 46u}, // ago -> Latn
+ {0xC0C00000u, 46u}, // agq -> Latn
+ {0x80E00000u, 46u}, // aha -> Latn
+ {0xACE00000u, 46u}, // ahl -> Latn
{0xB8E00000u, 0u}, // aho -> Ahom
- {0x99200000u, 44u}, // ajg -> Latn
- {0x616B0000u, 44u}, // ak -> Latn
- {0xA9400000u, 93u}, // akk -> Xsux
- {0x81600000u, 44u}, // ala -> Latn
- {0xA1600000u, 44u}, // ali -> Latn
- {0xB5600000u, 44u}, // aln -> Latn
- {0xCD600000u, 16u}, // alt -> Cyrl
- {0x616D0000u, 19u}, // am -> Ethi
- {0xB1800000u, 44u}, // amm -> Latn
- {0xB5800000u, 44u}, // amn -> Latn
- {0xB9800000u, 44u}, // amo -> Latn
- {0xBD800000u, 44u}, // amp -> Latn
- {0x616E0000u, 44u}, // an -> Latn
- {0x89A00000u, 44u}, // anc -> Latn
- {0xA9A00000u, 44u}, // ank -> Latn
- {0xB5A00000u, 44u}, // ann -> Latn
- {0xE1A00000u, 44u}, // any -> Latn
- {0xA5C00000u, 44u}, // aoj -> Latn
- {0xB1C00000u, 44u}, // aom -> Latn
- {0xE5C00000u, 44u}, // aoz -> Latn
+ {0x99200000u, 46u}, // ajg -> Latn
+ {0x616B0000u, 46u}, // ak -> Latn
+ {0xA9400000u, 95u}, // akk -> Xsux
+ {0x81600000u, 46u}, // ala -> Latn
+ {0xA1600000u, 46u}, // ali -> Latn
+ {0xB5600000u, 46u}, // aln -> Latn
+ {0xCD600000u, 17u}, // alt -> Cyrl
+ {0x616D0000u, 20u}, // am -> Ethi
+ {0xB1800000u, 46u}, // amm -> Latn
+ {0xB5800000u, 46u}, // amn -> Latn
+ {0xB9800000u, 46u}, // amo -> Latn
+ {0xBD800000u, 46u}, // amp -> Latn
+ {0x616E0000u, 46u}, // an -> Latn
+ {0x89A00000u, 46u}, // anc -> Latn
+ {0xA9A00000u, 46u}, // ank -> Latn
+ {0xB5A00000u, 46u}, // ann -> Latn
+ {0xE1A00000u, 46u}, // any -> Latn
+ {0xA5C00000u, 46u}, // aoj -> Latn
+ {0xB1C00000u, 46u}, // aom -> Latn
+ {0xE5C00000u, 46u}, // aoz -> Latn
{0x89E00000u, 1u}, // apc -> Arab
{0x8DE00000u, 1u}, // apd -> Arab
- {0x91E00000u, 44u}, // ape -> Latn
- {0xC5E00000u, 44u}, // apr -> Latn
- {0xC9E00000u, 44u}, // aps -> Latn
- {0xE5E00000u, 44u}, // apz -> Latn
+ {0x91E00000u, 46u}, // ape -> Latn
+ {0xC5E00000u, 46u}, // apr -> Latn
+ {0xC9E00000u, 46u}, // aps -> Latn
+ {0xE5E00000u, 46u}, // apz -> Latn
{0x61720000u, 1u}, // ar -> Arab
- {0x61725842u, 96u}, // ar-XB -> ~~~B
+ {0x61725842u, 98u}, // ar-XB -> ~~~B
{0x8A200000u, 2u}, // arc -> Armi
- {0x9E200000u, 44u}, // arh -> Latn
- {0xB6200000u, 44u}, // arn -> Latn
- {0xBA200000u, 44u}, // aro -> Latn
+ {0x9E200000u, 46u}, // arh -> Latn
+ {0xB6200000u, 46u}, // arn -> Latn
+ {0xBA200000u, 46u}, // aro -> Latn
{0xC2200000u, 1u}, // arq -> Arab
{0xCA200000u, 1u}, // ars -> Arab
{0xE2200000u, 1u}, // ary -> Arab
{0xE6200000u, 1u}, // arz -> Arab
{0x61730000u, 7u}, // as -> Beng
- {0x82400000u, 44u}, // asa -> Latn
- {0x92400000u, 73u}, // ase -> Sgnw
- {0x9A400000u, 44u}, // asg -> Latn
- {0xBA400000u, 44u}, // aso -> Latn
- {0xCE400000u, 44u}, // ast -> Latn
- {0x82600000u, 44u}, // ata -> Latn
- {0x9A600000u, 44u}, // atg -> Latn
- {0xA6600000u, 44u}, // atj -> Latn
- {0xE2800000u, 44u}, // auy -> Latn
- {0x61760000u, 16u}, // av -> Cyrl
+ {0x82400000u, 46u}, // asa -> Latn
+ {0x92400000u, 75u}, // ase -> Sgnw
+ {0x9A400000u, 46u}, // asg -> Latn
+ {0xBA400000u, 46u}, // aso -> Latn
+ {0xCE400000u, 46u}, // ast -> Latn
+ {0x82600000u, 46u}, // ata -> Latn
+ {0x9A600000u, 46u}, // atg -> Latn
+ {0xA6600000u, 46u}, // atj -> Latn
+ {0xE2800000u, 46u}, // auy -> Latn
+ {0x61760000u, 17u}, // av -> Cyrl
{0xAEA00000u, 1u}, // avl -> Arab
- {0xB6A00000u, 44u}, // avn -> Latn
- {0xCEA00000u, 44u}, // avt -> Latn
- {0xD2A00000u, 44u}, // avu -> Latn
- {0x82C00000u, 17u}, // awa -> Deva
- {0x86C00000u, 44u}, // awb -> Latn
- {0xBAC00000u, 44u}, // awo -> Latn
- {0xDEC00000u, 44u}, // awx -> Latn
- {0x61790000u, 44u}, // ay -> Latn
- {0x87000000u, 44u}, // ayb -> Latn
- {0x617A0000u, 44u}, // az -> Latn
+ {0xB6A00000u, 46u}, // avn -> Latn
+ {0xCEA00000u, 46u}, // avt -> Latn
+ {0xD2A00000u, 46u}, // avu -> Latn
+ {0x82C00000u, 18u}, // awa -> Deva
+ {0x86C00000u, 46u}, // awb -> Latn
+ {0xBAC00000u, 46u}, // awo -> Latn
+ {0xDEC00000u, 46u}, // awx -> Latn
+ {0x61790000u, 46u}, // ay -> Latn
+ {0x87000000u, 46u}, // ayb -> Latn
+ {0x617A0000u, 46u}, // az -> Latn
{0x617A4951u, 1u}, // az-IQ -> Arab
{0x617A4952u, 1u}, // az-IR -> Arab
- {0x617A5255u, 16u}, // az-RU -> Cyrl
- {0x62610000u, 16u}, // ba -> Cyrl
+ {0x617A5255u, 17u}, // az-RU -> Cyrl
+ {0x62610000u, 17u}, // ba -> Cyrl
{0xAC010000u, 1u}, // bal -> Arab
- {0xB4010000u, 44u}, // ban -> Latn
- {0xBC010000u, 17u}, // bap -> Deva
- {0xC4010000u, 44u}, // bar -> Latn
- {0xC8010000u, 44u}, // bas -> Latn
- {0xD4010000u, 44u}, // bav -> Latn
+ {0xB4010000u, 46u}, // ban -> Latn
+ {0xBC010000u, 18u}, // bap -> Deva
+ {0xC4010000u, 46u}, // bar -> Latn
+ {0xC8010000u, 46u}, // bas -> Latn
+ {0xD4010000u, 46u}, // bav -> Latn
{0xDC010000u, 5u}, // bax -> Bamu
- {0x80210000u, 44u}, // bba -> Latn
- {0x84210000u, 44u}, // bbb -> Latn
- {0x88210000u, 44u}, // bbc -> Latn
- {0x8C210000u, 44u}, // bbd -> Latn
- {0xA4210000u, 44u}, // bbj -> Latn
- {0xBC210000u, 44u}, // bbp -> Latn
- {0xC4210000u, 44u}, // bbr -> Latn
- {0x94410000u, 44u}, // bcf -> Latn
- {0x9C410000u, 44u}, // bch -> Latn
- {0xA0410000u, 44u}, // bci -> Latn
- {0xB0410000u, 44u}, // bcm -> Latn
- {0xB4410000u, 44u}, // bcn -> Latn
- {0xB8410000u, 44u}, // bco -> Latn
- {0xC0410000u, 19u}, // bcq -> Ethi
- {0xD0410000u, 44u}, // bcu -> Latn
- {0x8C610000u, 44u}, // bdd -> Latn
- {0x62650000u, 16u}, // be -> Cyrl
- {0x94810000u, 44u}, // bef -> Latn
- {0x9C810000u, 44u}, // beh -> Latn
+ {0x80210000u, 46u}, // bba -> Latn
+ {0x84210000u, 46u}, // bbb -> Latn
+ {0x88210000u, 46u}, // bbc -> Latn
+ {0x8C210000u, 46u}, // bbd -> Latn
+ {0xA4210000u, 46u}, // bbj -> Latn
+ {0xBC210000u, 46u}, // bbp -> Latn
+ {0xC4210000u, 46u}, // bbr -> Latn
+ {0x94410000u, 46u}, // bcf -> Latn
+ {0x9C410000u, 46u}, // bch -> Latn
+ {0xA0410000u, 46u}, // bci -> Latn
+ {0xB0410000u, 46u}, // bcm -> Latn
+ {0xB4410000u, 46u}, // bcn -> Latn
+ {0xB8410000u, 46u}, // bco -> Latn
+ {0xC0410000u, 20u}, // bcq -> Ethi
+ {0xD0410000u, 46u}, // bcu -> Latn
+ {0x8C610000u, 46u}, // bdd -> Latn
+ {0x62650000u, 17u}, // be -> Cyrl
+ {0x94810000u, 46u}, // bef -> Latn
+ {0x9C810000u, 46u}, // beh -> Latn
{0xA4810000u, 1u}, // bej -> Arab
- {0xB0810000u, 44u}, // bem -> Latn
- {0xCC810000u, 44u}, // bet -> Latn
- {0xD8810000u, 44u}, // bew -> Latn
- {0xDC810000u, 44u}, // bex -> Latn
- {0xE4810000u, 44u}, // bez -> Latn
- {0x8CA10000u, 44u}, // bfd -> Latn
- {0xC0A10000u, 81u}, // bfq -> Taml
+ {0xB0810000u, 46u}, // bem -> Latn
+ {0xCC810000u, 46u}, // bet -> Latn
+ {0xD8810000u, 46u}, // bew -> Latn
+ {0xDC810000u, 46u}, // bex -> Latn
+ {0xE4810000u, 46u}, // bez -> Latn
+ {0x8CA10000u, 46u}, // bfd -> Latn
+ {0xC0A10000u, 83u}, // bfq -> Taml
{0xCCA10000u, 1u}, // bft -> Arab
- {0xE0A10000u, 17u}, // bfy -> Deva
- {0x62670000u, 16u}, // bg -> Cyrl
- {0x88C10000u, 17u}, // bgc -> Deva
+ {0xE0A10000u, 18u}, // bfy -> Deva
+ {0x62670000u, 17u}, // bg -> Cyrl
+ {0x88C10000u, 18u}, // bgc -> Deva
{0xB4C10000u, 1u}, // bgn -> Arab
- {0xDCC10000u, 24u}, // bgx -> Grek
- {0x84E10000u, 17u}, // bhb -> Deva
- {0x98E10000u, 44u}, // bhg -> Latn
- {0xA0E10000u, 17u}, // bhi -> Deva
- {0xACE10000u, 44u}, // bhl -> Latn
- {0xB8E10000u, 17u}, // bho -> Deva
- {0xE0E10000u, 44u}, // bhy -> Latn
- {0x62690000u, 44u}, // bi -> Latn
- {0x85010000u, 44u}, // bib -> Latn
- {0x99010000u, 44u}, // big -> Latn
- {0xA9010000u, 44u}, // bik -> Latn
- {0xB1010000u, 44u}, // bim -> Latn
- {0xB5010000u, 44u}, // bin -> Latn
- {0xB9010000u, 44u}, // bio -> Latn
- {0xC1010000u, 44u}, // biq -> Latn
- {0x9D210000u, 44u}, // bjh -> Latn
- {0xA1210000u, 19u}, // bji -> Ethi
- {0xA5210000u, 17u}, // bjj -> Deva
- {0xB5210000u, 44u}, // bjn -> Latn
- {0xB9210000u, 44u}, // bjo -> Latn
- {0xC5210000u, 44u}, // bjr -> Latn
- {0xCD210000u, 44u}, // bjt -> Latn
- {0xE5210000u, 44u}, // bjz -> Latn
- {0x89410000u, 44u}, // bkc -> Latn
- {0xB1410000u, 44u}, // bkm -> Latn
- {0xC1410000u, 44u}, // bkq -> Latn
- {0xD1410000u, 44u}, // bku -> Latn
- {0xD5410000u, 44u}, // bkv -> Latn
- {0xCD610000u, 83u}, // blt -> Tavt
- {0x626D0000u, 44u}, // bm -> Latn
- {0x9D810000u, 44u}, // bmh -> Latn
- {0xA9810000u, 44u}, // bmk -> Latn
- {0xC1810000u, 44u}, // bmq -> Latn
- {0xD1810000u, 44u}, // bmu -> Latn
+ {0xDCC10000u, 25u}, // bgx -> Grek
+ {0x84E10000u, 18u}, // bhb -> Deva
+ {0x98E10000u, 46u}, // bhg -> Latn
+ {0xA0E10000u, 18u}, // bhi -> Deva
+ {0xACE10000u, 46u}, // bhl -> Latn
+ {0xB8E10000u, 18u}, // bho -> Deva
+ {0xE0E10000u, 46u}, // bhy -> Latn
+ {0x62690000u, 46u}, // bi -> Latn
+ {0x85010000u, 46u}, // bib -> Latn
+ {0x99010000u, 46u}, // big -> Latn
+ {0xA9010000u, 46u}, // bik -> Latn
+ {0xB1010000u, 46u}, // bim -> Latn
+ {0xB5010000u, 46u}, // bin -> Latn
+ {0xB9010000u, 46u}, // bio -> Latn
+ {0xC1010000u, 46u}, // biq -> Latn
+ {0x9D210000u, 46u}, // bjh -> Latn
+ {0xA1210000u, 20u}, // bji -> Ethi
+ {0xA5210000u, 18u}, // bjj -> Deva
+ {0xB5210000u, 46u}, // bjn -> Latn
+ {0xB9210000u, 46u}, // bjo -> Latn
+ {0xC5210000u, 46u}, // bjr -> Latn
+ {0xCD210000u, 46u}, // bjt -> Latn
+ {0xE5210000u, 46u}, // bjz -> Latn
+ {0x89410000u, 46u}, // bkc -> Latn
+ {0xB1410000u, 46u}, // bkm -> Latn
+ {0xC1410000u, 46u}, // bkq -> Latn
+ {0xD1410000u, 46u}, // bku -> Latn
+ {0xD5410000u, 46u}, // bkv -> Latn
+ {0xCD610000u, 85u}, // blt -> Tavt
+ {0x626D0000u, 46u}, // bm -> Latn
+ {0x9D810000u, 46u}, // bmh -> Latn
+ {0xA9810000u, 46u}, // bmk -> Latn
+ {0xC1810000u, 46u}, // bmq -> Latn
+ {0xD1810000u, 46u}, // bmu -> Latn
{0x626E0000u, 7u}, // bn -> Beng
- {0x99A10000u, 44u}, // bng -> Latn
- {0xB1A10000u, 44u}, // bnm -> Latn
- {0xBDA10000u, 44u}, // bnp -> Latn
- {0x626F0000u, 88u}, // bo -> Tibt
- {0xA5C10000u, 44u}, // boj -> Latn
- {0xB1C10000u, 44u}, // bom -> Latn
- {0xB5C10000u, 44u}, // bon -> Latn
+ {0x99A10000u, 46u}, // bng -> Latn
+ {0xB1A10000u, 46u}, // bnm -> Latn
+ {0xBDA10000u, 46u}, // bnp -> Latn
+ {0x626F0000u, 90u}, // bo -> Tibt
+ {0xA5C10000u, 46u}, // boj -> Latn
+ {0xB1C10000u, 46u}, // bom -> Latn
+ {0xB5C10000u, 46u}, // bon -> Latn
{0xE1E10000u, 7u}, // bpy -> Beng
- {0x8A010000u, 44u}, // bqc -> Latn
+ {0x8A010000u, 46u}, // bqc -> Latn
{0xA2010000u, 1u}, // bqi -> Arab
- {0xBE010000u, 44u}, // bqp -> Latn
- {0xD6010000u, 44u}, // bqv -> Latn
- {0x62720000u, 44u}, // br -> Latn
- {0x82210000u, 17u}, // bra -> Deva
+ {0xBE010000u, 46u}, // bqp -> Latn
+ {0xD6010000u, 46u}, // bqv -> Latn
+ {0x62720000u, 46u}, // br -> Latn
+ {0x82210000u, 18u}, // bra -> Deva
{0x9E210000u, 1u}, // brh -> Arab
- {0xDE210000u, 17u}, // brx -> Deva
- {0xE6210000u, 44u}, // brz -> Latn
- {0x62730000u, 44u}, // bs -> Latn
- {0xA6410000u, 44u}, // bsj -> Latn
+ {0xDE210000u, 18u}, // brx -> Deva
+ {0xE6210000u, 46u}, // brz -> Latn
+ {0x62730000u, 46u}, // bs -> Latn
+ {0xA6410000u, 46u}, // bsj -> Latn
{0xC2410000u, 6u}, // bsq -> Bass
- {0xCA410000u, 44u}, // bss -> Latn
- {0xCE410000u, 19u}, // bst -> Ethi
- {0xBA610000u, 44u}, // bto -> Latn
- {0xCE610000u, 44u}, // btt -> Latn
- {0xD6610000u, 17u}, // btv -> Deva
- {0x82810000u, 16u}, // bua -> Cyrl
- {0x8A810000u, 44u}, // buc -> Latn
- {0x8E810000u, 44u}, // bud -> Latn
- {0x9A810000u, 44u}, // bug -> Latn
- {0xAA810000u, 44u}, // buk -> Latn
- {0xB2810000u, 44u}, // bum -> Latn
- {0xBA810000u, 44u}, // buo -> Latn
- {0xCA810000u, 44u}, // bus -> Latn
- {0xD2810000u, 44u}, // buu -> Latn
- {0x86A10000u, 44u}, // bvb -> Latn
- {0x8EC10000u, 44u}, // bwd -> Latn
- {0xC6C10000u, 44u}, // bwr -> Latn
- {0x9EE10000u, 44u}, // bxh -> Latn
- {0x93010000u, 44u}, // bye -> Latn
- {0xB7010000u, 19u}, // byn -> Ethi
- {0xC7010000u, 44u}, // byr -> Latn
- {0xCB010000u, 44u}, // bys -> Latn
- {0xD7010000u, 44u}, // byv -> Latn
- {0xDF010000u, 44u}, // byx -> Latn
- {0x83210000u, 44u}, // bza -> Latn
- {0x93210000u, 44u}, // bze -> Latn
- {0x97210000u, 44u}, // bzf -> Latn
- {0x9F210000u, 44u}, // bzh -> Latn
- {0xDB210000u, 44u}, // bzw -> Latn
- {0x63610000u, 44u}, // ca -> Latn
- {0xB4020000u, 44u}, // can -> Latn
- {0xA4220000u, 44u}, // cbj -> Latn
- {0x9C420000u, 44u}, // cch -> Latn
+ {0xCA410000u, 46u}, // bss -> Latn
+ {0xCE410000u, 20u}, // bst -> Ethi
+ {0xBA610000u, 46u}, // bto -> Latn
+ {0xCE610000u, 46u}, // btt -> Latn
+ {0xD6610000u, 18u}, // btv -> Deva
+ {0x82810000u, 17u}, // bua -> Cyrl
+ {0x8A810000u, 46u}, // buc -> Latn
+ {0x8E810000u, 46u}, // bud -> Latn
+ {0x9A810000u, 46u}, // bug -> Latn
+ {0xAA810000u, 46u}, // buk -> Latn
+ {0xB2810000u, 46u}, // bum -> Latn
+ {0xBA810000u, 46u}, // buo -> Latn
+ {0xCA810000u, 46u}, // bus -> Latn
+ {0xD2810000u, 46u}, // buu -> Latn
+ {0x86A10000u, 46u}, // bvb -> Latn
+ {0x8EC10000u, 46u}, // bwd -> Latn
+ {0xC6C10000u, 46u}, // bwr -> Latn
+ {0x9EE10000u, 46u}, // bxh -> Latn
+ {0x93010000u, 46u}, // bye -> Latn
+ {0xB7010000u, 20u}, // byn -> Ethi
+ {0xC7010000u, 46u}, // byr -> Latn
+ {0xCB010000u, 46u}, // bys -> Latn
+ {0xD7010000u, 46u}, // byv -> Latn
+ {0xDF010000u, 46u}, // byx -> Latn
+ {0x83210000u, 46u}, // bza -> Latn
+ {0x93210000u, 46u}, // bze -> Latn
+ {0x97210000u, 46u}, // bzf -> Latn
+ {0x9F210000u, 46u}, // bzh -> Latn
+ {0xDB210000u, 46u}, // bzw -> Latn
+ {0x63610000u, 46u}, // ca -> Latn
+ {0xB4020000u, 46u}, // can -> Latn
+ {0xA4220000u, 46u}, // cbj -> Latn
+ {0x9C420000u, 46u}, // cch -> Latn
{0xBC420000u, 9u}, // ccp -> Cakm
- {0x63650000u, 16u}, // ce -> Cyrl
- {0x84820000u, 44u}, // ceb -> Latn
- {0x80A20000u, 44u}, // cfa -> Latn
- {0x98C20000u, 44u}, // cgg -> Latn
- {0x63680000u, 44u}, // ch -> Latn
- {0xA8E20000u, 44u}, // chk -> Latn
- {0xB0E20000u, 16u}, // chm -> Cyrl
- {0xB8E20000u, 44u}, // cho -> Latn
- {0xBCE20000u, 44u}, // chp -> Latn
+ {0x63650000u, 17u}, // ce -> Cyrl
+ {0x84820000u, 46u}, // ceb -> Latn
+ {0x80A20000u, 46u}, // cfa -> Latn
+ {0x98C20000u, 46u}, // cgg -> Latn
+ {0x63680000u, 46u}, // ch -> Latn
+ {0xA8E20000u, 46u}, // chk -> Latn
+ {0xB0E20000u, 17u}, // chm -> Cyrl
+ {0xB8E20000u, 46u}, // cho -> Latn
+ {0xBCE20000u, 46u}, // chp -> Latn
{0xC4E20000u, 13u}, // chr -> Cher
- {0x89020000u, 44u}, // cic -> Latn
+ {0x89020000u, 46u}, // cic -> Latn
{0x81220000u, 1u}, // cja -> Arab
{0xB1220000u, 12u}, // cjm -> Cham
- {0xD5220000u, 44u}, // cjv -> Latn
+ {0xD5220000u, 46u}, // cjv -> Latn
{0x85420000u, 1u}, // ckb -> Arab
- {0xAD420000u, 44u}, // ckl -> Latn
- {0xB9420000u, 44u}, // cko -> Latn
- {0xE1420000u, 44u}, // cky -> Latn
- {0x81620000u, 44u}, // cla -> Latn
- {0x91820000u, 44u}, // cme -> Latn
- {0x99820000u, 77u}, // cmg -> Soyo
- {0x636F0000u, 44u}, // co -> Latn
- {0xBDC20000u, 14u}, // cop -> Copt
- {0xC9E20000u, 44u}, // cps -> Latn
+ {0xAD420000u, 46u}, // ckl -> Latn
+ {0xB9420000u, 46u}, // cko -> Latn
+ {0xE1420000u, 46u}, // cky -> Latn
+ {0x81620000u, 46u}, // cla -> Latn
+ {0x91820000u, 46u}, // cme -> Latn
+ {0x99820000u, 79u}, // cmg -> Soyo
+ {0x636F0000u, 46u}, // co -> Latn
+ {0xBDC20000u, 15u}, // cop -> Copt
+ {0xC9E20000u, 46u}, // cps -> Latn
{0x63720000u, 10u}, // cr -> Cans
- {0x9E220000u, 16u}, // crh -> Cyrl
+ {0x9E220000u, 17u}, // crh -> Cyrl
{0xA6220000u, 10u}, // crj -> Cans
{0xAA220000u, 10u}, // crk -> Cans
{0xAE220000u, 10u}, // crl -> Cans
{0xB2220000u, 10u}, // crm -> Cans
- {0xCA220000u, 44u}, // crs -> Latn
- {0x63730000u, 44u}, // cs -> Latn
- {0x86420000u, 44u}, // csb -> Latn
+ {0xCA220000u, 46u}, // crs -> Latn
+ {0x63730000u, 46u}, // cs -> Latn
+ {0x86420000u, 46u}, // csb -> Latn
{0xDA420000u, 10u}, // csw -> Cans
- {0x8E620000u, 64u}, // ctd -> Pauc
- {0x63750000u, 16u}, // cu -> Cyrl
- {0x63760000u, 16u}, // cv -> Cyrl
- {0x63790000u, 44u}, // cy -> Latn
- {0x64610000u, 44u}, // da -> Latn
- {0x8C030000u, 44u}, // dad -> Latn
- {0x94030000u, 44u}, // daf -> Latn
- {0x98030000u, 44u}, // dag -> Latn
- {0x9C030000u, 44u}, // dah -> Latn
- {0xA8030000u, 44u}, // dak -> Latn
- {0xC4030000u, 16u}, // dar -> Cyrl
- {0xD4030000u, 44u}, // dav -> Latn
- {0x8C230000u, 44u}, // dbd -> Latn
- {0xC0230000u, 44u}, // dbq -> Latn
+ {0x8E620000u, 66u}, // ctd -> Pauc
+ {0x63750000u, 17u}, // cu -> Cyrl
+ {0x63760000u, 17u}, // cv -> Cyrl
+ {0x63790000u, 46u}, // cy -> Latn
+ {0x64610000u, 46u}, // da -> Latn
+ {0x8C030000u, 46u}, // dad -> Latn
+ {0x94030000u, 46u}, // daf -> Latn
+ {0x98030000u, 46u}, // dag -> Latn
+ {0x9C030000u, 46u}, // dah -> Latn
+ {0xA8030000u, 46u}, // dak -> Latn
+ {0xC4030000u, 17u}, // dar -> Cyrl
+ {0xD4030000u, 46u}, // dav -> Latn
+ {0x8C230000u, 46u}, // dbd -> Latn
+ {0xC0230000u, 46u}, // dbq -> Latn
{0x88430000u, 1u}, // dcc -> Arab
- {0xB4630000u, 44u}, // ddn -> Latn
- {0x64650000u, 44u}, // de -> Latn
- {0x8C830000u, 44u}, // ded -> Latn
- {0xB4830000u, 44u}, // den -> Latn
- {0x80C30000u, 44u}, // dga -> Latn
- {0x9CC30000u, 44u}, // dgh -> Latn
- {0xA0C30000u, 44u}, // dgi -> Latn
+ {0xB4630000u, 46u}, // ddn -> Latn
+ {0x64650000u, 46u}, // de -> Latn
+ {0x8C830000u, 46u}, // ded -> Latn
+ {0xB4830000u, 46u}, // den -> Latn
+ {0x80C30000u, 46u}, // dga -> Latn
+ {0x9CC30000u, 46u}, // dgh -> Latn
+ {0xA0C30000u, 46u}, // dgi -> Latn
{0xACC30000u, 1u}, // dgl -> Arab
- {0xC4C30000u, 44u}, // dgr -> Latn
- {0xE4C30000u, 44u}, // dgz -> Latn
- {0x81030000u, 44u}, // dia -> Latn
- {0x91230000u, 44u}, // dje -> Latn
- {0xA5A30000u, 44u}, // dnj -> Latn
- {0x85C30000u, 44u}, // dob -> Latn
+ {0xC4C30000u, 46u}, // dgr -> Latn
+ {0xE4C30000u, 46u}, // dgz -> Latn
+ {0x81030000u, 46u}, // dia -> Latn
+ {0x91230000u, 46u}, // dje -> Latn
+ {0xA5A30000u, 46u}, // dnj -> Latn
+ {0x85C30000u, 46u}, // dob -> Latn
{0xA1C30000u, 1u}, // doi -> Arab
- {0xBDC30000u, 44u}, // dop -> Latn
- {0xD9C30000u, 44u}, // dow -> Latn
- {0x9E230000u, 54u}, // drh -> Mong
- {0xA2230000u, 44u}, // dri -> Latn
- {0xCA230000u, 19u}, // drs -> Ethi
- {0x86430000u, 44u}, // dsb -> Latn
- {0xB2630000u, 44u}, // dtm -> Latn
- {0xBE630000u, 44u}, // dtp -> Latn
- {0xCA630000u, 44u}, // dts -> Latn
- {0xE2630000u, 17u}, // dty -> Deva
- {0x82830000u, 44u}, // dua -> Latn
- {0x8A830000u, 44u}, // duc -> Latn
- {0x8E830000u, 44u}, // dud -> Latn
- {0x9A830000u, 44u}, // dug -> Latn
- {0x64760000u, 86u}, // dv -> Thaa
- {0x82A30000u, 44u}, // dva -> Latn
- {0xDAC30000u, 44u}, // dww -> Latn
- {0xBB030000u, 44u}, // dyo -> Latn
- {0xD3030000u, 44u}, // dyu -> Latn
- {0x647A0000u, 88u}, // dz -> Tibt
- {0x9B230000u, 44u}, // dzg -> Latn
- {0xD0240000u, 44u}, // ebu -> Latn
- {0x65650000u, 44u}, // ee -> Latn
- {0xA0A40000u, 44u}, // efi -> Latn
- {0xACC40000u, 44u}, // egl -> Latn
- {0xE0C40000u, 18u}, // egy -> Egyp
- {0x81440000u, 44u}, // eka -> Latn
- {0xE1440000u, 36u}, // eky -> Kali
- {0x656C0000u, 24u}, // el -> Grek
- {0x81840000u, 44u}, // ema -> Latn
- {0xA1840000u, 44u}, // emi -> Latn
- {0x656E0000u, 44u}, // en -> Latn
- {0x656E5841u, 95u}, // en-XA -> ~~~A
- {0xB5A40000u, 44u}, // enn -> Latn
- {0xC1A40000u, 44u}, // enq -> Latn
- {0x656F0000u, 44u}, // eo -> Latn
- {0xA2240000u, 44u}, // eri -> Latn
- {0x65730000u, 44u}, // es -> Latn
- {0x9A440000u, 22u}, // esg -> Gonm
- {0xD2440000u, 44u}, // esu -> Latn
- {0x65740000u, 44u}, // et -> Latn
- {0xC6640000u, 44u}, // etr -> Latn
- {0xCE640000u, 34u}, // ett -> Ital
- {0xD2640000u, 44u}, // etu -> Latn
- {0xDE640000u, 44u}, // etx -> Latn
- {0x65750000u, 44u}, // eu -> Latn
- {0xBAC40000u, 44u}, // ewo -> Latn
- {0xCEE40000u, 44u}, // ext -> Latn
+ {0xBDC30000u, 46u}, // dop -> Latn
+ {0xD9C30000u, 46u}, // dow -> Latn
+ {0x9E230000u, 56u}, // drh -> Mong
+ {0xA2230000u, 46u}, // dri -> Latn
+ {0xCA230000u, 20u}, // drs -> Ethi
+ {0x86430000u, 46u}, // dsb -> Latn
+ {0xB2630000u, 46u}, // dtm -> Latn
+ {0xBE630000u, 46u}, // dtp -> Latn
+ {0xCA630000u, 46u}, // dts -> Latn
+ {0xE2630000u, 18u}, // dty -> Deva
+ {0x82830000u, 46u}, // dua -> Latn
+ {0x8A830000u, 46u}, // duc -> Latn
+ {0x8E830000u, 46u}, // dud -> Latn
+ {0x9A830000u, 46u}, // dug -> Latn
+ {0x64760000u, 88u}, // dv -> Thaa
+ {0x82A30000u, 46u}, // dva -> Latn
+ {0xDAC30000u, 46u}, // dww -> Latn
+ {0xBB030000u, 46u}, // dyo -> Latn
+ {0xD3030000u, 46u}, // dyu -> Latn
+ {0x647A0000u, 90u}, // dz -> Tibt
+ {0x9B230000u, 46u}, // dzg -> Latn
+ {0xD0240000u, 46u}, // ebu -> Latn
+ {0x65650000u, 46u}, // ee -> Latn
+ {0xA0A40000u, 46u}, // efi -> Latn
+ {0xACC40000u, 46u}, // egl -> Latn
+ {0xE0C40000u, 19u}, // egy -> Egyp
+ {0x81440000u, 46u}, // eka -> Latn
+ {0xE1440000u, 37u}, // eky -> Kali
+ {0x656C0000u, 25u}, // el -> Grek
+ {0x81840000u, 46u}, // ema -> Latn
+ {0xA1840000u, 46u}, // emi -> Latn
+ {0x656E0000u, 46u}, // en -> Latn
+ {0x656E5841u, 97u}, // en-XA -> ~~~A
+ {0xB5A40000u, 46u}, // enn -> Latn
+ {0xC1A40000u, 46u}, // enq -> Latn
+ {0x656F0000u, 46u}, // eo -> Latn
+ {0xA2240000u, 46u}, // eri -> Latn
+ {0x65730000u, 46u}, // es -> Latn
+ {0x9A440000u, 23u}, // esg -> Gonm
+ {0xD2440000u, 46u}, // esu -> Latn
+ {0x65740000u, 46u}, // et -> Latn
+ {0xC6640000u, 46u}, // etr -> Latn
+ {0xCE640000u, 35u}, // ett -> Ital
+ {0xD2640000u, 46u}, // etu -> Latn
+ {0xDE640000u, 46u}, // etx -> Latn
+ {0x65750000u, 46u}, // eu -> Latn
+ {0xBAC40000u, 46u}, // ewo -> Latn
+ {0xCEE40000u, 46u}, // ext -> Latn
{0x66610000u, 1u}, // fa -> Arab
- {0x80050000u, 44u}, // faa -> Latn
- {0x84050000u, 44u}, // fab -> Latn
- {0x98050000u, 44u}, // fag -> Latn
- {0xA0050000u, 44u}, // fai -> Latn
- {0xB4050000u, 44u}, // fan -> Latn
- {0x66660000u, 44u}, // ff -> Latn
- {0xA0A50000u, 44u}, // ffi -> Latn
- {0xB0A50000u, 44u}, // ffm -> Latn
- {0x66690000u, 44u}, // fi -> Latn
+ {0x80050000u, 46u}, // faa -> Latn
+ {0x84050000u, 46u}, // fab -> Latn
+ {0x98050000u, 46u}, // fag -> Latn
+ {0xA0050000u, 46u}, // fai -> Latn
+ {0xB4050000u, 46u}, // fan -> Latn
+ {0x66660000u, 46u}, // ff -> Latn
+ {0xA0A50000u, 46u}, // ffi -> Latn
+ {0xB0A50000u, 46u}, // ffm -> Latn
+ {0x66690000u, 46u}, // fi -> Latn
{0x81050000u, 1u}, // fia -> Arab
- {0xAD050000u, 44u}, // fil -> Latn
- {0xCD050000u, 44u}, // fit -> Latn
- {0x666A0000u, 44u}, // fj -> Latn
- {0xC5650000u, 44u}, // flr -> Latn
- {0xBD850000u, 44u}, // fmp -> Latn
- {0x666F0000u, 44u}, // fo -> Latn
- {0x8DC50000u, 44u}, // fod -> Latn
- {0xB5C50000u, 44u}, // fon -> Latn
- {0xC5C50000u, 44u}, // for -> Latn
- {0x91E50000u, 44u}, // fpe -> Latn
- {0xCA050000u, 44u}, // fqs -> Latn
- {0x66720000u, 44u}, // fr -> Latn
- {0x8A250000u, 44u}, // frc -> Latn
- {0xBE250000u, 44u}, // frp -> Latn
- {0xC6250000u, 44u}, // frr -> Latn
- {0xCA250000u, 44u}, // frs -> Latn
+ {0xAD050000u, 46u}, // fil -> Latn
+ {0xCD050000u, 46u}, // fit -> Latn
+ {0x666A0000u, 46u}, // fj -> Latn
+ {0xC5650000u, 46u}, // flr -> Latn
+ {0xBD850000u, 46u}, // fmp -> Latn
+ {0x666F0000u, 46u}, // fo -> Latn
+ {0x8DC50000u, 46u}, // fod -> Latn
+ {0xB5C50000u, 46u}, // fon -> Latn
+ {0xC5C50000u, 46u}, // for -> Latn
+ {0x91E50000u, 46u}, // fpe -> Latn
+ {0xCA050000u, 46u}, // fqs -> Latn
+ {0x66720000u, 46u}, // fr -> Latn
+ {0x8A250000u, 46u}, // frc -> Latn
+ {0xBE250000u, 46u}, // frp -> Latn
+ {0xC6250000u, 46u}, // frr -> Latn
+ {0xCA250000u, 46u}, // frs -> Latn
{0x86850000u, 1u}, // fub -> Arab
- {0x8E850000u, 44u}, // fud -> Latn
- {0x92850000u, 44u}, // fue -> Latn
- {0x96850000u, 44u}, // fuf -> Latn
- {0x9E850000u, 44u}, // fuh -> Latn
- {0xC2850000u, 44u}, // fuq -> Latn
- {0xC6850000u, 44u}, // fur -> Latn
- {0xD6850000u, 44u}, // fuv -> Latn
- {0xE2850000u, 44u}, // fuy -> Latn
- {0xC6A50000u, 44u}, // fvr -> Latn
- {0x66790000u, 44u}, // fy -> Latn
- {0x67610000u, 44u}, // ga -> Latn
- {0x80060000u, 44u}, // gaa -> Latn
- {0x94060000u, 44u}, // gaf -> Latn
- {0x98060000u, 44u}, // gag -> Latn
- {0x9C060000u, 44u}, // gah -> Latn
- {0xA4060000u, 44u}, // gaj -> Latn
- {0xB0060000u, 44u}, // gam -> Latn
- {0xB4060000u, 27u}, // gan -> Hans
- {0xD8060000u, 44u}, // gaw -> Latn
- {0xE0060000u, 44u}, // gay -> Latn
- {0x80260000u, 44u}, // gba -> Latn
- {0x94260000u, 44u}, // gbf -> Latn
- {0xB0260000u, 17u}, // gbm -> Deva
- {0xE0260000u, 44u}, // gby -> Latn
+ {0x8E850000u, 46u}, // fud -> Latn
+ {0x92850000u, 46u}, // fue -> Latn
+ {0x96850000u, 46u}, // fuf -> Latn
+ {0x9E850000u, 46u}, // fuh -> Latn
+ {0xC2850000u, 46u}, // fuq -> Latn
+ {0xC6850000u, 46u}, // fur -> Latn
+ {0xD6850000u, 46u}, // fuv -> Latn
+ {0xE2850000u, 46u}, // fuy -> Latn
+ {0xC6A50000u, 46u}, // fvr -> Latn
+ {0x66790000u, 46u}, // fy -> Latn
+ {0x67610000u, 46u}, // ga -> Latn
+ {0x80060000u, 46u}, // gaa -> Latn
+ {0x94060000u, 46u}, // gaf -> Latn
+ {0x98060000u, 46u}, // gag -> Latn
+ {0x9C060000u, 46u}, // gah -> Latn
+ {0xA4060000u, 46u}, // gaj -> Latn
+ {0xB0060000u, 46u}, // gam -> Latn
+ {0xB4060000u, 28u}, // gan -> Hans
+ {0xD8060000u, 46u}, // gaw -> Latn
+ {0xE0060000u, 46u}, // gay -> Latn
+ {0x80260000u, 46u}, // gba -> Latn
+ {0x94260000u, 46u}, // gbf -> Latn
+ {0xB0260000u, 18u}, // gbm -> Deva
+ {0xE0260000u, 46u}, // gby -> Latn
{0xE4260000u, 1u}, // gbz -> Arab
- {0xC4460000u, 44u}, // gcr -> Latn
- {0x67640000u, 44u}, // gd -> Latn
- {0x90660000u, 44u}, // gde -> Latn
- {0xB4660000u, 44u}, // gdn -> Latn
- {0xC4660000u, 44u}, // gdr -> Latn
- {0x84860000u, 44u}, // geb -> Latn
- {0xA4860000u, 44u}, // gej -> Latn
- {0xAC860000u, 44u}, // gel -> Latn
- {0xE4860000u, 19u}, // gez -> Ethi
- {0xA8A60000u, 44u}, // gfk -> Latn
- {0xB4C60000u, 17u}, // ggn -> Deva
- {0xC8E60000u, 44u}, // ghs -> Latn
- {0xAD060000u, 44u}, // gil -> Latn
- {0xB1060000u, 44u}, // gim -> Latn
+ {0xC4460000u, 46u}, // gcr -> Latn
+ {0x67640000u, 46u}, // gd -> Latn
+ {0x90660000u, 46u}, // gde -> Latn
+ {0xB4660000u, 46u}, // gdn -> Latn
+ {0xC4660000u, 46u}, // gdr -> Latn
+ {0x84860000u, 46u}, // geb -> Latn
+ {0xA4860000u, 46u}, // gej -> Latn
+ {0xAC860000u, 46u}, // gel -> Latn
+ {0xE4860000u, 20u}, // gez -> Ethi
+ {0xA8A60000u, 46u}, // gfk -> Latn
+ {0xB4C60000u, 18u}, // ggn -> Deva
+ {0xC8E60000u, 46u}, // ghs -> Latn
+ {0xAD060000u, 46u}, // gil -> Latn
+ {0xB1060000u, 46u}, // gim -> Latn
{0xA9260000u, 1u}, // gjk -> Arab
- {0xB5260000u, 44u}, // gjn -> Latn
+ {0xB5260000u, 46u}, // gjn -> Latn
{0xD1260000u, 1u}, // gju -> Arab
- {0xB5460000u, 44u}, // gkn -> Latn
- {0xBD460000u, 44u}, // gkp -> Latn
- {0x676C0000u, 44u}, // gl -> Latn
+ {0xB5460000u, 46u}, // gkn -> Latn
+ {0xBD460000u, 46u}, // gkp -> Latn
+ {0x676C0000u, 46u}, // gl -> Latn
{0xA9660000u, 1u}, // glk -> Arab
- {0xB1860000u, 44u}, // gmm -> Latn
- {0xD5860000u, 19u}, // gmv -> Ethi
- {0x676E0000u, 44u}, // gn -> Latn
- {0x8DA60000u, 44u}, // gnd -> Latn
- {0x99A60000u, 44u}, // gng -> Latn
- {0x8DC60000u, 44u}, // god -> Latn
- {0x95C60000u, 19u}, // gof -> Ethi
- {0xA1C60000u, 44u}, // goi -> Latn
- {0xB1C60000u, 17u}, // gom -> Deva
- {0xB5C60000u, 84u}, // gon -> Telu
- {0xC5C60000u, 44u}, // gor -> Latn
- {0xC9C60000u, 44u}, // gos -> Latn
- {0xCDC60000u, 23u}, // got -> Goth
- {0x86260000u, 44u}, // grb -> Latn
- {0x8A260000u, 15u}, // grc -> Cprt
+ {0xB1860000u, 46u}, // gmm -> Latn
+ {0xD5860000u, 20u}, // gmv -> Ethi
+ {0x676E0000u, 46u}, // gn -> Latn
+ {0x8DA60000u, 46u}, // gnd -> Latn
+ {0x99A60000u, 46u}, // gng -> Latn
+ {0x8DC60000u, 46u}, // god -> Latn
+ {0x95C60000u, 20u}, // gof -> Ethi
+ {0xA1C60000u, 46u}, // goi -> Latn
+ {0xB1C60000u, 18u}, // gom -> Deva
+ {0xB5C60000u, 86u}, // gon -> Telu
+ {0xC5C60000u, 46u}, // gor -> Latn
+ {0xC9C60000u, 46u}, // gos -> Latn
+ {0xCDC60000u, 24u}, // got -> Goth
+ {0x86260000u, 46u}, // grb -> Latn
+ {0x8A260000u, 16u}, // grc -> Cprt
{0xCE260000u, 7u}, // grt -> Beng
- {0xDA260000u, 44u}, // grw -> Latn
- {0xDA460000u, 44u}, // gsw -> Latn
- {0x67750000u, 25u}, // gu -> Gujr
- {0x86860000u, 44u}, // gub -> Latn
- {0x8A860000u, 44u}, // guc -> Latn
- {0x8E860000u, 44u}, // gud -> Latn
- {0xC6860000u, 44u}, // gur -> Latn
- {0xDA860000u, 44u}, // guw -> Latn
- {0xDE860000u, 44u}, // gux -> Latn
- {0xE6860000u, 44u}, // guz -> Latn
- {0x67760000u, 44u}, // gv -> Latn
- {0x96A60000u, 44u}, // gvf -> Latn
- {0xC6A60000u, 17u}, // gvr -> Deva
- {0xCAA60000u, 44u}, // gvs -> Latn
+ {0xDA260000u, 46u}, // grw -> Latn
+ {0xDA460000u, 46u}, // gsw -> Latn
+ {0x67750000u, 26u}, // gu -> Gujr
+ {0x86860000u, 46u}, // gub -> Latn
+ {0x8A860000u, 46u}, // guc -> Latn
+ {0x8E860000u, 46u}, // gud -> Latn
+ {0xC6860000u, 46u}, // gur -> Latn
+ {0xDA860000u, 46u}, // guw -> Latn
+ {0xDE860000u, 46u}, // gux -> Latn
+ {0xE6860000u, 46u}, // guz -> Latn
+ {0x67760000u, 46u}, // gv -> Latn
+ {0x96A60000u, 46u}, // gvf -> Latn
+ {0xC6A60000u, 18u}, // gvr -> Deva
+ {0xCAA60000u, 46u}, // gvs -> Latn
{0x8AC60000u, 1u}, // gwc -> Arab
- {0xA2C60000u, 44u}, // gwi -> Latn
+ {0xA2C60000u, 46u}, // gwi -> Latn
{0xCEC60000u, 1u}, // gwt -> Arab
- {0xA3060000u, 44u}, // gyi -> Latn
- {0x68610000u, 44u}, // ha -> Latn
+ {0xA3060000u, 46u}, // gyi -> Latn
+ {0x68610000u, 46u}, // ha -> Latn
{0x6861434Du, 1u}, // ha-CM -> Arab
{0x68615344u, 1u}, // ha-SD -> Arab
- {0x98070000u, 44u}, // hag -> Latn
- {0xA8070000u, 27u}, // hak -> Hans
- {0xB0070000u, 44u}, // ham -> Latn
- {0xD8070000u, 44u}, // haw -> Latn
+ {0x98070000u, 46u}, // hag -> Latn
+ {0xA8070000u, 28u}, // hak -> Hans
+ {0xB0070000u, 46u}, // ham -> Latn
+ {0xD8070000u, 46u}, // haw -> Latn
{0xE4070000u, 1u}, // haz -> Arab
- {0x84270000u, 44u}, // hbb -> Latn
- {0xE0670000u, 19u}, // hdy -> Ethi
- {0x68650000u, 30u}, // he -> Hebr
- {0xE0E70000u, 44u}, // hhy -> Latn
- {0x68690000u, 17u}, // hi -> Deva
- {0x81070000u, 44u}, // hia -> Latn
- {0x95070000u, 44u}, // hif -> Latn
- {0x99070000u, 44u}, // hig -> Latn
- {0x9D070000u, 44u}, // hih -> Latn
- {0xAD070000u, 44u}, // hil -> Latn
- {0x81670000u, 44u}, // hla -> Latn
- {0xD1670000u, 31u}, // hlu -> Hluw
- {0x8D870000u, 67u}, // hmd -> Plrd
- {0xCD870000u, 44u}, // hmt -> Latn
+ {0x84270000u, 46u}, // hbb -> Latn
+ {0xE0670000u, 20u}, // hdy -> Ethi
+ {0x68650000u, 31u}, // he -> Hebr
+ {0xE0E70000u, 46u}, // hhy -> Latn
+ {0x68690000u, 18u}, // hi -> Deva
+ {0x81070000u, 46u}, // hia -> Latn
+ {0x95070000u, 46u}, // hif -> Latn
+ {0x99070000u, 46u}, // hig -> Latn
+ {0x9D070000u, 46u}, // hih -> Latn
+ {0xAD070000u, 46u}, // hil -> Latn
+ {0x81670000u, 46u}, // hla -> Latn
+ {0xD1670000u, 32u}, // hlu -> Hluw
+ {0x8D870000u, 69u}, // hmd -> Plrd
+ {0xCD870000u, 46u}, // hmt -> Latn
{0x8DA70000u, 1u}, // hnd -> Arab
- {0x91A70000u, 17u}, // hne -> Deva
- {0xA5A70000u, 32u}, // hnj -> Hmng
- {0xB5A70000u, 44u}, // hnn -> Latn
+ {0x91A70000u, 18u}, // hne -> Deva
+ {0xA5A70000u, 33u}, // hnj -> Hmng
+ {0xB5A70000u, 46u}, // hnn -> Latn
{0xB9A70000u, 1u}, // hno -> Arab
- {0x686F0000u, 44u}, // ho -> Latn
- {0x89C70000u, 17u}, // hoc -> Deva
- {0xA5C70000u, 17u}, // hoj -> Deva
- {0xCDC70000u, 44u}, // hot -> Latn
- {0x68720000u, 44u}, // hr -> Latn
- {0x86470000u, 44u}, // hsb -> Latn
- {0xB6470000u, 27u}, // hsn -> Hans
- {0x68740000u, 44u}, // ht -> Latn
- {0x68750000u, 44u}, // hu -> Latn
- {0xA2870000u, 44u}, // hui -> Latn
+ {0x686F0000u, 46u}, // ho -> Latn
+ {0x89C70000u, 18u}, // hoc -> Deva
+ {0xA5C70000u, 18u}, // hoj -> Deva
+ {0xCDC70000u, 46u}, // hot -> Latn
+ {0x68720000u, 46u}, // hr -> Latn
+ {0x86470000u, 46u}, // hsb -> Latn
+ {0xB6470000u, 28u}, // hsn -> Hans
+ {0x68740000u, 46u}, // ht -> Latn
+ {0x68750000u, 46u}, // hu -> Latn
+ {0xA2870000u, 46u}, // hui -> Latn
{0x68790000u, 3u}, // hy -> Armn
- {0x687A0000u, 44u}, // hz -> Latn
- {0x69610000u, 44u}, // ia -> Latn
- {0xB4080000u, 44u}, // ian -> Latn
- {0xC4080000u, 44u}, // iar -> Latn
- {0x80280000u, 44u}, // iba -> Latn
- {0x84280000u, 44u}, // ibb -> Latn
- {0xE0280000u, 44u}, // iby -> Latn
- {0x80480000u, 44u}, // ica -> Latn
- {0x9C480000u, 44u}, // ich -> Latn
- {0x69640000u, 44u}, // id -> Latn
- {0x8C680000u, 44u}, // idd -> Latn
- {0xA0680000u, 44u}, // idi -> Latn
- {0xD0680000u, 44u}, // idu -> Latn
- {0x90A80000u, 44u}, // ife -> Latn
- {0x69670000u, 44u}, // ig -> Latn
- {0x84C80000u, 44u}, // igb -> Latn
- {0x90C80000u, 44u}, // ige -> Latn
- {0x69690000u, 94u}, // ii -> Yiii
- {0xA5280000u, 44u}, // ijj -> Latn
- {0x696B0000u, 44u}, // ik -> Latn
- {0xA9480000u, 44u}, // ikk -> Latn
- {0xCD480000u, 44u}, // ikt -> Latn
- {0xD9480000u, 44u}, // ikw -> Latn
- {0xDD480000u, 44u}, // ikx -> Latn
- {0xB9680000u, 44u}, // ilo -> Latn
- {0xB9880000u, 44u}, // imo -> Latn
- {0x696E0000u, 44u}, // in -> Latn
- {0x9DA80000u, 16u}, // inh -> Cyrl
- {0x696F0000u, 44u}, // io -> Latn
- {0xD1C80000u, 44u}, // iou -> Latn
- {0xA2280000u, 44u}, // iri -> Latn
- {0x69730000u, 44u}, // is -> Latn
- {0x69740000u, 44u}, // it -> Latn
+ {0x687A0000u, 46u}, // hz -> Latn
+ {0x69610000u, 46u}, // ia -> Latn
+ {0xB4080000u, 46u}, // ian -> Latn
+ {0xC4080000u, 46u}, // iar -> Latn
+ {0x80280000u, 46u}, // iba -> Latn
+ {0x84280000u, 46u}, // ibb -> Latn
+ {0xE0280000u, 46u}, // iby -> Latn
+ {0x80480000u, 46u}, // ica -> Latn
+ {0x9C480000u, 46u}, // ich -> Latn
+ {0x69640000u, 46u}, // id -> Latn
+ {0x8C680000u, 46u}, // idd -> Latn
+ {0xA0680000u, 46u}, // idi -> Latn
+ {0xD0680000u, 46u}, // idu -> Latn
+ {0x90A80000u, 46u}, // ife -> Latn
+ {0x69670000u, 46u}, // ig -> Latn
+ {0x84C80000u, 46u}, // igb -> Latn
+ {0x90C80000u, 46u}, // ige -> Latn
+ {0x69690000u, 96u}, // ii -> Yiii
+ {0xA5280000u, 46u}, // ijj -> Latn
+ {0x696B0000u, 46u}, // ik -> Latn
+ {0xA9480000u, 46u}, // ikk -> Latn
+ {0xCD480000u, 46u}, // ikt -> Latn
+ {0xD9480000u, 46u}, // ikw -> Latn
+ {0xDD480000u, 46u}, // ikx -> Latn
+ {0xB9680000u, 46u}, // ilo -> Latn
+ {0xB9880000u, 46u}, // imo -> Latn
+ {0x696E0000u, 46u}, // in -> Latn
+ {0x9DA80000u, 17u}, // inh -> Cyrl
+ {0x696F0000u, 46u}, // io -> Latn
+ {0xD1C80000u, 46u}, // iou -> Latn
+ {0xA2280000u, 46u}, // iri -> Latn
+ {0x69730000u, 46u}, // is -> Latn
+ {0x69740000u, 46u}, // it -> Latn
{0x69750000u, 10u}, // iu -> Cans
- {0x69770000u, 30u}, // iw -> Hebr
- {0xB2C80000u, 44u}, // iwm -> Latn
- {0xCAC80000u, 44u}, // iws -> Latn
- {0x9F280000u, 44u}, // izh -> Latn
- {0xA3280000u, 44u}, // izi -> Latn
- {0x6A610000u, 35u}, // ja -> Jpan
- {0x84090000u, 44u}, // jab -> Latn
- {0xB0090000u, 44u}, // jam -> Latn
- {0xB8290000u, 44u}, // jbo -> Latn
- {0xD0290000u, 44u}, // jbu -> Latn
- {0xB4890000u, 44u}, // jen -> Latn
- {0xA8C90000u, 44u}, // jgk -> Latn
- {0xB8C90000u, 44u}, // jgo -> Latn
- {0x6A690000u, 30u}, // ji -> Hebr
- {0x85090000u, 44u}, // jib -> Latn
- {0x89890000u, 44u}, // jmc -> Latn
- {0xAD890000u, 17u}, // jml -> Deva
- {0x82290000u, 44u}, // jra -> Latn
- {0xCE890000u, 44u}, // jut -> Latn
- {0x6A760000u, 44u}, // jv -> Latn
- {0x6A770000u, 44u}, // jw -> Latn
- {0x6B610000u, 20u}, // ka -> Geor
- {0x800A0000u, 16u}, // kaa -> Cyrl
- {0x840A0000u, 44u}, // kab -> Latn
- {0x880A0000u, 44u}, // kac -> Latn
- {0x8C0A0000u, 44u}, // kad -> Latn
- {0xA00A0000u, 44u}, // kai -> Latn
- {0xA40A0000u, 44u}, // kaj -> Latn
- {0xB00A0000u, 44u}, // kam -> Latn
- {0xB80A0000u, 44u}, // kao -> Latn
- {0x8C2A0000u, 16u}, // kbd -> Cyrl
- {0xB02A0000u, 44u}, // kbm -> Latn
- {0xBC2A0000u, 44u}, // kbp -> Latn
- {0xC02A0000u, 44u}, // kbq -> Latn
- {0xDC2A0000u, 44u}, // kbx -> Latn
+ {0x69770000u, 31u}, // iw -> Hebr
+ {0xB2C80000u, 46u}, // iwm -> Latn
+ {0xCAC80000u, 46u}, // iws -> Latn
+ {0x9F280000u, 46u}, // izh -> Latn
+ {0xA3280000u, 46u}, // izi -> Latn
+ {0x6A610000u, 36u}, // ja -> Jpan
+ {0x84090000u, 46u}, // jab -> Latn
+ {0xB0090000u, 46u}, // jam -> Latn
+ {0xB8290000u, 46u}, // jbo -> Latn
+ {0xD0290000u, 46u}, // jbu -> Latn
+ {0xB4890000u, 46u}, // jen -> Latn
+ {0xA8C90000u, 46u}, // jgk -> Latn
+ {0xB8C90000u, 46u}, // jgo -> Latn
+ {0x6A690000u, 31u}, // ji -> Hebr
+ {0x85090000u, 46u}, // jib -> Latn
+ {0x89890000u, 46u}, // jmc -> Latn
+ {0xAD890000u, 18u}, // jml -> Deva
+ {0x82290000u, 46u}, // jra -> Latn
+ {0xCE890000u, 46u}, // jut -> Latn
+ {0x6A760000u, 46u}, // jv -> Latn
+ {0x6A770000u, 46u}, // jw -> Latn
+ {0x6B610000u, 21u}, // ka -> Geor
+ {0x800A0000u, 17u}, // kaa -> Cyrl
+ {0x840A0000u, 46u}, // kab -> Latn
+ {0x880A0000u, 46u}, // kac -> Latn
+ {0x8C0A0000u, 46u}, // kad -> Latn
+ {0xA00A0000u, 46u}, // kai -> Latn
+ {0xA40A0000u, 46u}, // kaj -> Latn
+ {0xB00A0000u, 46u}, // kam -> Latn
+ {0xB80A0000u, 46u}, // kao -> Latn
+ {0x8C2A0000u, 17u}, // kbd -> Cyrl
+ {0xB02A0000u, 46u}, // kbm -> Latn
+ {0xBC2A0000u, 46u}, // kbp -> Latn
+ {0xC02A0000u, 46u}, // kbq -> Latn
+ {0xDC2A0000u, 46u}, // kbx -> Latn
{0xE02A0000u, 1u}, // kby -> Arab
- {0x984A0000u, 44u}, // kcg -> Latn
- {0xA84A0000u, 44u}, // kck -> Latn
- {0xAC4A0000u, 44u}, // kcl -> Latn
- {0xCC4A0000u, 44u}, // kct -> Latn
- {0x906A0000u, 44u}, // kde -> Latn
+ {0x984A0000u, 46u}, // kcg -> Latn
+ {0xA84A0000u, 46u}, // kck -> Latn
+ {0xAC4A0000u, 46u}, // kcl -> Latn
+ {0xCC4A0000u, 46u}, // kct -> Latn
+ {0x906A0000u, 46u}, // kde -> Latn
{0x9C6A0000u, 1u}, // kdh -> Arab
- {0xAC6A0000u, 44u}, // kdl -> Latn
- {0xCC6A0000u, 87u}, // kdt -> Thai
- {0x808A0000u, 44u}, // kea -> Latn
- {0xB48A0000u, 44u}, // ken -> Latn
- {0xE48A0000u, 44u}, // kez -> Latn
- {0xB8AA0000u, 44u}, // kfo -> Latn
- {0xC4AA0000u, 17u}, // kfr -> Deva
- {0xE0AA0000u, 17u}, // kfy -> Deva
- {0x6B670000u, 44u}, // kg -> Latn
- {0x90CA0000u, 44u}, // kge -> Latn
- {0x94CA0000u, 44u}, // kgf -> Latn
- {0xBCCA0000u, 44u}, // kgp -> Latn
- {0x80EA0000u, 44u}, // kha -> Latn
- {0x84EA0000u, 80u}, // khb -> Talu
- {0xB4EA0000u, 17u}, // khn -> Deva
- {0xC0EA0000u, 44u}, // khq -> Latn
- {0xC8EA0000u, 44u}, // khs -> Latn
- {0xCCEA0000u, 56u}, // kht -> Mymr
+ {0xAC6A0000u, 46u}, // kdl -> Latn
+ {0xCC6A0000u, 89u}, // kdt -> Thai
+ {0x808A0000u, 46u}, // kea -> Latn
+ {0xB48A0000u, 46u}, // ken -> Latn
+ {0xE48A0000u, 46u}, // kez -> Latn
+ {0xB8AA0000u, 46u}, // kfo -> Latn
+ {0xC4AA0000u, 18u}, // kfr -> Deva
+ {0xE0AA0000u, 18u}, // kfy -> Deva
+ {0x6B670000u, 46u}, // kg -> Latn
+ {0x90CA0000u, 46u}, // kge -> Latn
+ {0x94CA0000u, 46u}, // kgf -> Latn
+ {0xBCCA0000u, 46u}, // kgp -> Latn
+ {0x80EA0000u, 46u}, // kha -> Latn
+ {0x84EA0000u, 82u}, // khb -> Talu
+ {0xB4EA0000u, 18u}, // khn -> Deva
+ {0xC0EA0000u, 46u}, // khq -> Latn
+ {0xC8EA0000u, 46u}, // khs -> Latn
+ {0xCCEA0000u, 58u}, // kht -> Mymr
{0xD8EA0000u, 1u}, // khw -> Arab
- {0xE4EA0000u, 44u}, // khz -> Latn
- {0x6B690000u, 44u}, // ki -> Latn
- {0xA50A0000u, 44u}, // kij -> Latn
- {0xD10A0000u, 44u}, // kiu -> Latn
- {0xD90A0000u, 44u}, // kiw -> Latn
- {0x6B6A0000u, 44u}, // kj -> Latn
- {0x8D2A0000u, 44u}, // kjd -> Latn
- {0x992A0000u, 43u}, // kjg -> Laoo
- {0xC92A0000u, 44u}, // kjs -> Latn
- {0xE12A0000u, 44u}, // kjy -> Latn
- {0x6B6B0000u, 16u}, // kk -> Cyrl
+ {0xE4EA0000u, 46u}, // khz -> Latn
+ {0x6B690000u, 46u}, // ki -> Latn
+ {0xA50A0000u, 46u}, // kij -> Latn
+ {0xD10A0000u, 46u}, // kiu -> Latn
+ {0xD90A0000u, 46u}, // kiw -> Latn
+ {0x6B6A0000u, 46u}, // kj -> Latn
+ {0x8D2A0000u, 46u}, // kjd -> Latn
+ {0x992A0000u, 45u}, // kjg -> Laoo
+ {0xC92A0000u, 46u}, // kjs -> Latn
+ {0xE12A0000u, 46u}, // kjy -> Latn
+ {0x6B6B0000u, 17u}, // kk -> Cyrl
{0x6B6B4146u, 1u}, // kk-AF -> Arab
{0x6B6B434Eu, 1u}, // kk-CN -> Arab
{0x6B6B4952u, 1u}, // kk-IR -> Arab
{0x6B6B4D4Eu, 1u}, // kk-MN -> Arab
- {0x894A0000u, 44u}, // kkc -> Latn
- {0xA54A0000u, 44u}, // kkj -> Latn
- {0x6B6C0000u, 44u}, // kl -> Latn
- {0xB56A0000u, 44u}, // kln -> Latn
- {0xC16A0000u, 44u}, // klq -> Latn
- {0xCD6A0000u, 44u}, // klt -> Latn
- {0xDD6A0000u, 44u}, // klx -> Latn
- {0x6B6D0000u, 39u}, // km -> Khmr
- {0x858A0000u, 44u}, // kmb -> Latn
- {0x9D8A0000u, 44u}, // kmh -> Latn
- {0xB98A0000u, 44u}, // kmo -> Latn
- {0xC98A0000u, 44u}, // kms -> Latn
- {0xD18A0000u, 44u}, // kmu -> Latn
- {0xD98A0000u, 44u}, // kmw -> Latn
- {0x6B6E0000u, 40u}, // kn -> Knda
- {0x95AA0000u, 44u}, // knf -> Latn
- {0xBDAA0000u, 44u}, // knp -> Latn
- {0x6B6F0000u, 41u}, // ko -> Kore
- {0xA1CA0000u, 16u}, // koi -> Cyrl
- {0xA9CA0000u, 17u}, // kok -> Deva
- {0xADCA0000u, 44u}, // kol -> Latn
- {0xC9CA0000u, 44u}, // kos -> Latn
- {0xE5CA0000u, 44u}, // koz -> Latn
- {0x91EA0000u, 44u}, // kpe -> Latn
- {0x95EA0000u, 44u}, // kpf -> Latn
- {0xB9EA0000u, 44u}, // kpo -> Latn
- {0xC5EA0000u, 44u}, // kpr -> Latn
- {0xDDEA0000u, 44u}, // kpx -> Latn
- {0x860A0000u, 44u}, // kqb -> Latn
- {0x960A0000u, 44u}, // kqf -> Latn
- {0xCA0A0000u, 44u}, // kqs -> Latn
- {0xE20A0000u, 19u}, // kqy -> Ethi
- {0x6B720000u, 44u}, // kr -> Latn
- {0x8A2A0000u, 16u}, // krc -> Cyrl
- {0xA22A0000u, 44u}, // kri -> Latn
- {0xA62A0000u, 44u}, // krj -> Latn
- {0xAE2A0000u, 44u}, // krl -> Latn
- {0xCA2A0000u, 44u}, // krs -> Latn
- {0xD22A0000u, 17u}, // kru -> Deva
+ {0x894A0000u, 46u}, // kkc -> Latn
+ {0xA54A0000u, 46u}, // kkj -> Latn
+ {0x6B6C0000u, 46u}, // kl -> Latn
+ {0xB56A0000u, 46u}, // kln -> Latn
+ {0xC16A0000u, 46u}, // klq -> Latn
+ {0xCD6A0000u, 46u}, // klt -> Latn
+ {0xDD6A0000u, 46u}, // klx -> Latn
+ {0x6B6D0000u, 40u}, // km -> Khmr
+ {0x858A0000u, 46u}, // kmb -> Latn
+ {0x9D8A0000u, 46u}, // kmh -> Latn
+ {0xB98A0000u, 46u}, // kmo -> Latn
+ {0xC98A0000u, 46u}, // kms -> Latn
+ {0xD18A0000u, 46u}, // kmu -> Latn
+ {0xD98A0000u, 46u}, // kmw -> Latn
+ {0x6B6E0000u, 42u}, // kn -> Knda
+ {0x95AA0000u, 46u}, // knf -> Latn
+ {0xBDAA0000u, 46u}, // knp -> Latn
+ {0x6B6F0000u, 43u}, // ko -> Kore
+ {0xA1CA0000u, 17u}, // koi -> Cyrl
+ {0xA9CA0000u, 18u}, // kok -> Deva
+ {0xADCA0000u, 46u}, // kol -> Latn
+ {0xC9CA0000u, 46u}, // kos -> Latn
+ {0xE5CA0000u, 46u}, // koz -> Latn
+ {0x91EA0000u, 46u}, // kpe -> Latn
+ {0x95EA0000u, 46u}, // kpf -> Latn
+ {0xB9EA0000u, 46u}, // kpo -> Latn
+ {0xC5EA0000u, 46u}, // kpr -> Latn
+ {0xDDEA0000u, 46u}, // kpx -> Latn
+ {0x860A0000u, 46u}, // kqb -> Latn
+ {0x960A0000u, 46u}, // kqf -> Latn
+ {0xCA0A0000u, 46u}, // kqs -> Latn
+ {0xE20A0000u, 20u}, // kqy -> Ethi
+ {0x6B720000u, 46u}, // kr -> Latn
+ {0x8A2A0000u, 17u}, // krc -> Cyrl
+ {0xA22A0000u, 46u}, // kri -> Latn
+ {0xA62A0000u, 46u}, // krj -> Latn
+ {0xAE2A0000u, 46u}, // krl -> Latn
+ {0xCA2A0000u, 46u}, // krs -> Latn
+ {0xD22A0000u, 18u}, // kru -> Deva
{0x6B730000u, 1u}, // ks -> Arab
- {0x864A0000u, 44u}, // ksb -> Latn
- {0x8E4A0000u, 44u}, // ksd -> Latn
- {0x964A0000u, 44u}, // ksf -> Latn
- {0x9E4A0000u, 44u}, // ksh -> Latn
- {0xA64A0000u, 44u}, // ksj -> Latn
- {0xC64A0000u, 44u}, // ksr -> Latn
- {0x866A0000u, 19u}, // ktb -> Ethi
- {0xB26A0000u, 44u}, // ktm -> Latn
- {0xBA6A0000u, 44u}, // kto -> Latn
- {0xC66A0000u, 44u}, // ktr -> Latn
- {0x6B750000u, 44u}, // ku -> Latn
+ {0x864A0000u, 46u}, // ksb -> Latn
+ {0x8E4A0000u, 46u}, // ksd -> Latn
+ {0x964A0000u, 46u}, // ksf -> Latn
+ {0x9E4A0000u, 46u}, // ksh -> Latn
+ {0xA64A0000u, 46u}, // ksj -> Latn
+ {0xC64A0000u, 46u}, // ksr -> Latn
+ {0x866A0000u, 20u}, // ktb -> Ethi
+ {0xB26A0000u, 46u}, // ktm -> Latn
+ {0xBA6A0000u, 46u}, // kto -> Latn
+ {0xC66A0000u, 46u}, // ktr -> Latn
+ {0x6B750000u, 46u}, // ku -> Latn
{0x6B754952u, 1u}, // ku-IR -> Arab
{0x6B754C42u, 1u}, // ku-LB -> Arab
- {0x868A0000u, 44u}, // kub -> Latn
- {0x8E8A0000u, 44u}, // kud -> Latn
- {0x928A0000u, 44u}, // kue -> Latn
- {0xA68A0000u, 44u}, // kuj -> Latn
- {0xB28A0000u, 16u}, // kum -> Cyrl
- {0xB68A0000u, 44u}, // kun -> Latn
- {0xBE8A0000u, 44u}, // kup -> Latn
- {0xCA8A0000u, 44u}, // kus -> Latn
- {0x6B760000u, 16u}, // kv -> Cyrl
- {0x9AAA0000u, 44u}, // kvg -> Latn
- {0xC6AA0000u, 44u}, // kvr -> Latn
+ {0x868A0000u, 46u}, // kub -> Latn
+ {0x8E8A0000u, 46u}, // kud -> Latn
+ {0x928A0000u, 46u}, // kue -> Latn
+ {0xA68A0000u, 46u}, // kuj -> Latn
+ {0xB28A0000u, 17u}, // kum -> Cyrl
+ {0xB68A0000u, 46u}, // kun -> Latn
+ {0xBE8A0000u, 46u}, // kup -> Latn
+ {0xCA8A0000u, 46u}, // kus -> Latn
+ {0x6B760000u, 17u}, // kv -> Cyrl
+ {0x9AAA0000u, 46u}, // kvg -> Latn
+ {0xC6AA0000u, 46u}, // kvr -> Latn
{0xDEAA0000u, 1u}, // kvx -> Arab
- {0x6B770000u, 44u}, // kw -> Latn
- {0xA6CA0000u, 44u}, // kwj -> Latn
- {0xBACA0000u, 44u}, // kwo -> Latn
- {0xC2CA0000u, 44u}, // kwq -> Latn
- {0x82EA0000u, 44u}, // kxa -> Latn
- {0x8AEA0000u, 19u}, // kxc -> Ethi
- {0x92EA0000u, 44u}, // kxe -> Latn
- {0xB2EA0000u, 87u}, // kxm -> Thai
+ {0x6B770000u, 46u}, // kw -> Latn
+ {0xA6CA0000u, 46u}, // kwj -> Latn
+ {0xBACA0000u, 46u}, // kwo -> Latn
+ {0xC2CA0000u, 46u}, // kwq -> Latn
+ {0x82EA0000u, 46u}, // kxa -> Latn
+ {0x8AEA0000u, 20u}, // kxc -> Ethi
+ {0x92EA0000u, 46u}, // kxe -> Latn
+ {0xB2EA0000u, 89u}, // kxm -> Thai
{0xBEEA0000u, 1u}, // kxp -> Arab
- {0xDAEA0000u, 44u}, // kxw -> Latn
- {0xE6EA0000u, 44u}, // kxz -> Latn
- {0x6B790000u, 16u}, // ky -> Cyrl
+ {0xDAEA0000u, 46u}, // kxw -> Latn
+ {0xE6EA0000u, 46u}, // kxz -> Latn
+ {0x6B790000u, 17u}, // ky -> Cyrl
{0x6B79434Eu, 1u}, // ky-CN -> Arab
- {0x6B795452u, 44u}, // ky-TR -> Latn
- {0x930A0000u, 44u}, // kye -> Latn
- {0xDF0A0000u, 44u}, // kyx -> Latn
- {0xA72A0000u, 44u}, // kzj -> Latn
- {0xC72A0000u, 44u}, // kzr -> Latn
- {0xCF2A0000u, 44u}, // kzt -> Latn
- {0x6C610000u, 44u}, // la -> Latn
- {0x840B0000u, 46u}, // lab -> Lina
- {0x8C0B0000u, 30u}, // lad -> Hebr
- {0x980B0000u, 44u}, // lag -> Latn
+ {0x6B795452u, 46u}, // ky-TR -> Latn
+ {0x930A0000u, 46u}, // kye -> Latn
+ {0xDF0A0000u, 46u}, // kyx -> Latn
+ {0xA72A0000u, 46u}, // kzj -> Latn
+ {0xC72A0000u, 46u}, // kzr -> Latn
+ {0xCF2A0000u, 46u}, // kzt -> Latn
+ {0x6C610000u, 46u}, // la -> Latn
+ {0x840B0000u, 48u}, // lab -> Lina
+ {0x8C0B0000u, 31u}, // lad -> Hebr
+ {0x980B0000u, 46u}, // lag -> Latn
{0x9C0B0000u, 1u}, // lah -> Arab
- {0xA40B0000u, 44u}, // laj -> Latn
- {0xC80B0000u, 44u}, // las -> Latn
- {0x6C620000u, 44u}, // lb -> Latn
- {0x902B0000u, 16u}, // lbe -> Cyrl
- {0xD02B0000u, 44u}, // lbu -> Latn
- {0xD82B0000u, 44u}, // lbw -> Latn
- {0xB04B0000u, 44u}, // lcm -> Latn
- {0xBC4B0000u, 87u}, // lcp -> Thai
- {0x846B0000u, 44u}, // ldb -> Latn
- {0x8C8B0000u, 44u}, // led -> Latn
- {0x908B0000u, 44u}, // lee -> Latn
- {0xB08B0000u, 44u}, // lem -> Latn
- {0xBC8B0000u, 45u}, // lep -> Lepc
- {0xC08B0000u, 44u}, // leq -> Latn
- {0xD08B0000u, 44u}, // leu -> Latn
- {0xE48B0000u, 16u}, // lez -> Cyrl
- {0x6C670000u, 44u}, // lg -> Latn
- {0x98CB0000u, 44u}, // lgg -> Latn
- {0x6C690000u, 44u}, // li -> Latn
- {0x810B0000u, 44u}, // lia -> Latn
- {0x8D0B0000u, 44u}, // lid -> Latn
- {0x950B0000u, 17u}, // lif -> Deva
- {0x990B0000u, 44u}, // lig -> Latn
- {0x9D0B0000u, 44u}, // lih -> Latn
- {0xA50B0000u, 44u}, // lij -> Latn
- {0xC90B0000u, 47u}, // lis -> Lisu
- {0xBD2B0000u, 44u}, // ljp -> Latn
+ {0xA40B0000u, 46u}, // laj -> Latn
+ {0xC80B0000u, 46u}, // las -> Latn
+ {0x6C620000u, 46u}, // lb -> Latn
+ {0x902B0000u, 17u}, // lbe -> Cyrl
+ {0xD02B0000u, 46u}, // lbu -> Latn
+ {0xD82B0000u, 46u}, // lbw -> Latn
+ {0xB04B0000u, 46u}, // lcm -> Latn
+ {0xBC4B0000u, 89u}, // lcp -> Thai
+ {0x846B0000u, 46u}, // ldb -> Latn
+ {0x8C8B0000u, 46u}, // led -> Latn
+ {0x908B0000u, 46u}, // lee -> Latn
+ {0xB08B0000u, 46u}, // lem -> Latn
+ {0xBC8B0000u, 47u}, // lep -> Lepc
+ {0xC08B0000u, 46u}, // leq -> Latn
+ {0xD08B0000u, 46u}, // leu -> Latn
+ {0xE48B0000u, 17u}, // lez -> Cyrl
+ {0x6C670000u, 46u}, // lg -> Latn
+ {0x98CB0000u, 46u}, // lgg -> Latn
+ {0x6C690000u, 46u}, // li -> Latn
+ {0x810B0000u, 46u}, // lia -> Latn
+ {0x8D0B0000u, 46u}, // lid -> Latn
+ {0x950B0000u, 18u}, // lif -> Deva
+ {0x990B0000u, 46u}, // lig -> Latn
+ {0x9D0B0000u, 46u}, // lih -> Latn
+ {0xA50B0000u, 46u}, // lij -> Latn
+ {0xC90B0000u, 49u}, // lis -> Lisu
+ {0xBD2B0000u, 46u}, // ljp -> Latn
{0xA14B0000u, 1u}, // lki -> Arab
- {0xCD4B0000u, 44u}, // lkt -> Latn
- {0x916B0000u, 44u}, // lle -> Latn
- {0xB56B0000u, 44u}, // lln -> Latn
- {0xB58B0000u, 84u}, // lmn -> Telu
- {0xB98B0000u, 44u}, // lmo -> Latn
- {0xBD8B0000u, 44u}, // lmp -> Latn
- {0x6C6E0000u, 44u}, // ln -> Latn
- {0xC9AB0000u, 44u}, // lns -> Latn
- {0xD1AB0000u, 44u}, // lnu -> Latn
- {0x6C6F0000u, 43u}, // lo -> Laoo
- {0xA5CB0000u, 44u}, // loj -> Latn
- {0xA9CB0000u, 44u}, // lok -> Latn
- {0xADCB0000u, 44u}, // lol -> Latn
- {0xC5CB0000u, 44u}, // lor -> Latn
- {0xC9CB0000u, 44u}, // los -> Latn
- {0xE5CB0000u, 44u}, // loz -> Latn
+ {0xCD4B0000u, 46u}, // lkt -> Latn
+ {0x916B0000u, 46u}, // lle -> Latn
+ {0xB56B0000u, 46u}, // lln -> Latn
+ {0xB58B0000u, 86u}, // lmn -> Telu
+ {0xB98B0000u, 46u}, // lmo -> Latn
+ {0xBD8B0000u, 46u}, // lmp -> Latn
+ {0x6C6E0000u, 46u}, // ln -> Latn
+ {0xC9AB0000u, 46u}, // lns -> Latn
+ {0xD1AB0000u, 46u}, // lnu -> Latn
+ {0x6C6F0000u, 45u}, // lo -> Laoo
+ {0xA5CB0000u, 46u}, // loj -> Latn
+ {0xA9CB0000u, 46u}, // lok -> Latn
+ {0xADCB0000u, 46u}, // lol -> Latn
+ {0xC5CB0000u, 46u}, // lor -> Latn
+ {0xC9CB0000u, 46u}, // los -> Latn
+ {0xE5CB0000u, 46u}, // loz -> Latn
{0x8A2B0000u, 1u}, // lrc -> Arab
- {0x6C740000u, 44u}, // lt -> Latn
- {0x9A6B0000u, 44u}, // ltg -> Latn
- {0x6C750000u, 44u}, // lu -> Latn
- {0x828B0000u, 44u}, // lua -> Latn
- {0xBA8B0000u, 44u}, // luo -> Latn
- {0xE28B0000u, 44u}, // luy -> Latn
+ {0x6C740000u, 46u}, // lt -> Latn
+ {0x9A6B0000u, 46u}, // ltg -> Latn
+ {0x6C750000u, 46u}, // lu -> Latn
+ {0x828B0000u, 46u}, // lua -> Latn
+ {0xBA8B0000u, 46u}, // luo -> Latn
+ {0xE28B0000u, 46u}, // luy -> Latn
{0xE68B0000u, 1u}, // luz -> Arab
- {0x6C760000u, 44u}, // lv -> Latn
- {0xAECB0000u, 87u}, // lwl -> Thai
- {0x9F2B0000u, 27u}, // lzh -> Hans
- {0xE72B0000u, 44u}, // lzz -> Latn
- {0x8C0C0000u, 44u}, // mad -> Latn
- {0x940C0000u, 44u}, // maf -> Latn
- {0x980C0000u, 17u}, // mag -> Deva
- {0xA00C0000u, 17u}, // mai -> Deva
- {0xA80C0000u, 44u}, // mak -> Latn
- {0xB40C0000u, 44u}, // man -> Latn
- {0xB40C474Eu, 58u}, // man-GN -> Nkoo
- {0xC80C0000u, 44u}, // mas -> Latn
- {0xD80C0000u, 44u}, // maw -> Latn
- {0xE40C0000u, 44u}, // maz -> Latn
- {0x9C2C0000u, 44u}, // mbh -> Latn
- {0xB82C0000u, 44u}, // mbo -> Latn
- {0xC02C0000u, 44u}, // mbq -> Latn
- {0xD02C0000u, 44u}, // mbu -> Latn
- {0xD82C0000u, 44u}, // mbw -> Latn
- {0xA04C0000u, 44u}, // mci -> Latn
- {0xBC4C0000u, 44u}, // mcp -> Latn
- {0xC04C0000u, 44u}, // mcq -> Latn
- {0xC44C0000u, 44u}, // mcr -> Latn
- {0xD04C0000u, 44u}, // mcu -> Latn
- {0x806C0000u, 44u}, // mda -> Latn
+ {0x6C760000u, 46u}, // lv -> Latn
+ {0xAECB0000u, 89u}, // lwl -> Thai
+ {0x9F2B0000u, 28u}, // lzh -> Hans
+ {0xE72B0000u, 46u}, // lzz -> Latn
+ {0x8C0C0000u, 46u}, // mad -> Latn
+ {0x940C0000u, 46u}, // maf -> Latn
+ {0x980C0000u, 18u}, // mag -> Deva
+ {0xA00C0000u, 18u}, // mai -> Deva
+ {0xA80C0000u, 46u}, // mak -> Latn
+ {0xB40C0000u, 46u}, // man -> Latn
+ {0xB40C474Eu, 60u}, // man-GN -> Nkoo
+ {0xC80C0000u, 46u}, // mas -> Latn
+ {0xD80C0000u, 46u}, // maw -> Latn
+ {0xE40C0000u, 46u}, // maz -> Latn
+ {0x9C2C0000u, 46u}, // mbh -> Latn
+ {0xB82C0000u, 46u}, // mbo -> Latn
+ {0xC02C0000u, 46u}, // mbq -> Latn
+ {0xD02C0000u, 46u}, // mbu -> Latn
+ {0xD82C0000u, 46u}, // mbw -> Latn
+ {0xA04C0000u, 46u}, // mci -> Latn
+ {0xBC4C0000u, 46u}, // mcp -> Latn
+ {0xC04C0000u, 46u}, // mcq -> Latn
+ {0xC44C0000u, 46u}, // mcr -> Latn
+ {0xD04C0000u, 46u}, // mcu -> Latn
+ {0x806C0000u, 46u}, // mda -> Latn
{0x906C0000u, 1u}, // mde -> Arab
- {0x946C0000u, 16u}, // mdf -> Cyrl
- {0x9C6C0000u, 44u}, // mdh -> Latn
- {0xA46C0000u, 44u}, // mdj -> Latn
- {0xC46C0000u, 44u}, // mdr -> Latn
- {0xDC6C0000u, 19u}, // mdx -> Ethi
- {0x8C8C0000u, 44u}, // med -> Latn
- {0x908C0000u, 44u}, // mee -> Latn
- {0xA88C0000u, 44u}, // mek -> Latn
- {0xB48C0000u, 44u}, // men -> Latn
- {0xC48C0000u, 44u}, // mer -> Latn
- {0xCC8C0000u, 44u}, // met -> Latn
- {0xD08C0000u, 44u}, // meu -> Latn
+ {0x946C0000u, 17u}, // mdf -> Cyrl
+ {0x9C6C0000u, 46u}, // mdh -> Latn
+ {0xA46C0000u, 46u}, // mdj -> Latn
+ {0xC46C0000u, 46u}, // mdr -> Latn
+ {0xDC6C0000u, 20u}, // mdx -> Ethi
+ {0x8C8C0000u, 46u}, // med -> Latn
+ {0x908C0000u, 46u}, // mee -> Latn
+ {0xA88C0000u, 46u}, // mek -> Latn
+ {0xB48C0000u, 46u}, // men -> Latn
+ {0xC48C0000u, 46u}, // mer -> Latn
+ {0xCC8C0000u, 46u}, // met -> Latn
+ {0xD08C0000u, 46u}, // meu -> Latn
{0x80AC0000u, 1u}, // mfa -> Arab
- {0x90AC0000u, 44u}, // mfe -> Latn
- {0xB4AC0000u, 44u}, // mfn -> Latn
- {0xB8AC0000u, 44u}, // mfo -> Latn
- {0xC0AC0000u, 44u}, // mfq -> Latn
- {0x6D670000u, 44u}, // mg -> Latn
- {0x9CCC0000u, 44u}, // mgh -> Latn
- {0xACCC0000u, 44u}, // mgl -> Latn
- {0xB8CC0000u, 44u}, // mgo -> Latn
- {0xBCCC0000u, 17u}, // mgp -> Deva
- {0xE0CC0000u, 44u}, // mgy -> Latn
- {0x6D680000u, 44u}, // mh -> Latn
- {0xA0EC0000u, 44u}, // mhi -> Latn
- {0xACEC0000u, 44u}, // mhl -> Latn
- {0x6D690000u, 44u}, // mi -> Latn
- {0x950C0000u, 44u}, // mif -> Latn
- {0xB50C0000u, 44u}, // min -> Latn
- {0xC90C0000u, 29u}, // mis -> Hatr
- {0xD90C0000u, 44u}, // miw -> Latn
- {0x6D6B0000u, 16u}, // mk -> Cyrl
+ {0x90AC0000u, 46u}, // mfe -> Latn
+ {0xB4AC0000u, 46u}, // mfn -> Latn
+ {0xB8AC0000u, 46u}, // mfo -> Latn
+ {0xC0AC0000u, 46u}, // mfq -> Latn
+ {0x6D670000u, 46u}, // mg -> Latn
+ {0x9CCC0000u, 46u}, // mgh -> Latn
+ {0xACCC0000u, 46u}, // mgl -> Latn
+ {0xB8CC0000u, 46u}, // mgo -> Latn
+ {0xBCCC0000u, 18u}, // mgp -> Deva
+ {0xE0CC0000u, 46u}, // mgy -> Latn
+ {0x6D680000u, 46u}, // mh -> Latn
+ {0xA0EC0000u, 46u}, // mhi -> Latn
+ {0xACEC0000u, 46u}, // mhl -> Latn
+ {0x6D690000u, 46u}, // mi -> Latn
+ {0x950C0000u, 46u}, // mif -> Latn
+ {0xB50C0000u, 46u}, // min -> Latn
+ {0xC90C0000u, 30u}, // mis -> Hatr
+ {0xD90C0000u, 46u}, // miw -> Latn
+ {0x6D6B0000u, 17u}, // mk -> Cyrl
{0xA14C0000u, 1u}, // mki -> Arab
- {0xAD4C0000u, 44u}, // mkl -> Latn
- {0xBD4C0000u, 44u}, // mkp -> Latn
- {0xD94C0000u, 44u}, // mkw -> Latn
- {0x6D6C0000u, 53u}, // ml -> Mlym
- {0x916C0000u, 44u}, // mle -> Latn
- {0xBD6C0000u, 44u}, // mlp -> Latn
- {0xC96C0000u, 44u}, // mls -> Latn
- {0xB98C0000u, 44u}, // mmo -> Latn
- {0xD18C0000u, 44u}, // mmu -> Latn
- {0xDD8C0000u, 44u}, // mmx -> Latn
- {0x6D6E0000u, 16u}, // mn -> Cyrl
- {0x6D6E434Eu, 54u}, // mn-CN -> Mong
- {0x81AC0000u, 44u}, // mna -> Latn
- {0x95AC0000u, 44u}, // mnf -> Latn
+ {0xAD4C0000u, 46u}, // mkl -> Latn
+ {0xBD4C0000u, 46u}, // mkp -> Latn
+ {0xD94C0000u, 46u}, // mkw -> Latn
+ {0x6D6C0000u, 55u}, // ml -> Mlym
+ {0x916C0000u, 46u}, // mle -> Latn
+ {0xBD6C0000u, 46u}, // mlp -> Latn
+ {0xC96C0000u, 46u}, // mls -> Latn
+ {0xB98C0000u, 46u}, // mmo -> Latn
+ {0xD18C0000u, 46u}, // mmu -> Latn
+ {0xDD8C0000u, 46u}, // mmx -> Latn
+ {0x6D6E0000u, 17u}, // mn -> Cyrl
+ {0x6D6E434Eu, 56u}, // mn-CN -> Mong
+ {0x81AC0000u, 46u}, // mna -> Latn
+ {0x95AC0000u, 46u}, // mnf -> Latn
{0xA1AC0000u, 7u}, // mni -> Beng
- {0xD9AC0000u, 56u}, // mnw -> Mymr
- {0x6D6F0000u, 44u}, // mo -> Latn
- {0x81CC0000u, 44u}, // moa -> Latn
- {0x91CC0000u, 44u}, // moe -> Latn
- {0x9DCC0000u, 44u}, // moh -> Latn
- {0xC9CC0000u, 44u}, // mos -> Latn
- {0xDDCC0000u, 44u}, // mox -> Latn
- {0xBDEC0000u, 44u}, // mpp -> Latn
- {0xC9EC0000u, 44u}, // mps -> Latn
- {0xCDEC0000u, 44u}, // mpt -> Latn
- {0xDDEC0000u, 44u}, // mpx -> Latn
- {0xAE0C0000u, 44u}, // mql -> Latn
- {0x6D720000u, 17u}, // mr -> Deva
- {0x8E2C0000u, 17u}, // mrd -> Deva
- {0xA62C0000u, 16u}, // mrj -> Cyrl
- {0xBA2C0000u, 55u}, // mro -> Mroo
- {0x6D730000u, 44u}, // ms -> Latn
+ {0xD9AC0000u, 58u}, // mnw -> Mymr
+ {0x6D6F0000u, 46u}, // mo -> Latn
+ {0x81CC0000u, 46u}, // moa -> Latn
+ {0x91CC0000u, 46u}, // moe -> Latn
+ {0x9DCC0000u, 46u}, // moh -> Latn
+ {0xC9CC0000u, 46u}, // mos -> Latn
+ {0xDDCC0000u, 46u}, // mox -> Latn
+ {0xBDEC0000u, 46u}, // mpp -> Latn
+ {0xC9EC0000u, 46u}, // mps -> Latn
+ {0xCDEC0000u, 46u}, // mpt -> Latn
+ {0xDDEC0000u, 46u}, // mpx -> Latn
+ {0xAE0C0000u, 46u}, // mql -> Latn
+ {0x6D720000u, 18u}, // mr -> Deva
+ {0x8E2C0000u, 18u}, // mrd -> Deva
+ {0xA62C0000u, 17u}, // mrj -> Cyrl
+ {0xBA2C0000u, 57u}, // mro -> Mroo
+ {0x6D730000u, 46u}, // ms -> Latn
{0x6D734343u, 1u}, // ms-CC -> Arab
{0x6D734944u, 1u}, // ms-ID -> Arab
- {0x6D740000u, 44u}, // mt -> Latn
- {0x8A6C0000u, 44u}, // mtc -> Latn
- {0x966C0000u, 44u}, // mtf -> Latn
- {0xA26C0000u, 44u}, // mti -> Latn
- {0xC66C0000u, 17u}, // mtr -> Deva
- {0x828C0000u, 44u}, // mua -> Latn
- {0xC68C0000u, 44u}, // mur -> Latn
- {0xCA8C0000u, 44u}, // mus -> Latn
- {0x82AC0000u, 44u}, // mva -> Latn
- {0xB6AC0000u, 44u}, // mvn -> Latn
+ {0x6D740000u, 46u}, // mt -> Latn
+ {0x8A6C0000u, 46u}, // mtc -> Latn
+ {0x966C0000u, 46u}, // mtf -> Latn
+ {0xA26C0000u, 46u}, // mti -> Latn
+ {0xC66C0000u, 18u}, // mtr -> Deva
+ {0x828C0000u, 46u}, // mua -> Latn
+ {0xC68C0000u, 46u}, // mur -> Latn
+ {0xCA8C0000u, 46u}, // mus -> Latn
+ {0x82AC0000u, 46u}, // mva -> Latn
+ {0xB6AC0000u, 46u}, // mvn -> Latn
{0xE2AC0000u, 1u}, // mvy -> Arab
- {0xAACC0000u, 44u}, // mwk -> Latn
- {0xC6CC0000u, 17u}, // mwr -> Deva
- {0xD6CC0000u, 44u}, // mwv -> Latn
- {0xDACC0000u, 33u}, // mww -> Hmnp
- {0x8AEC0000u, 44u}, // mxc -> Latn
- {0xB2EC0000u, 44u}, // mxm -> Latn
- {0x6D790000u, 56u}, // my -> Mymr
- {0xAB0C0000u, 44u}, // myk -> Latn
- {0xB30C0000u, 19u}, // mym -> Ethi
- {0xD70C0000u, 16u}, // myv -> Cyrl
- {0xDB0C0000u, 44u}, // myw -> Latn
- {0xDF0C0000u, 44u}, // myx -> Latn
- {0xE70C0000u, 50u}, // myz -> Mand
- {0xAB2C0000u, 44u}, // mzk -> Latn
- {0xB32C0000u, 44u}, // mzm -> Latn
+ {0xAACC0000u, 46u}, // mwk -> Latn
+ {0xC6CC0000u, 18u}, // mwr -> Deva
+ {0xD6CC0000u, 46u}, // mwv -> Latn
+ {0xDACC0000u, 34u}, // mww -> Hmnp
+ {0x8AEC0000u, 46u}, // mxc -> Latn
+ {0xB2EC0000u, 46u}, // mxm -> Latn
+ {0x6D790000u, 58u}, // my -> Mymr
+ {0xAB0C0000u, 46u}, // myk -> Latn
+ {0xB30C0000u, 20u}, // mym -> Ethi
+ {0xD70C0000u, 17u}, // myv -> Cyrl
+ {0xDB0C0000u, 46u}, // myw -> Latn
+ {0xDF0C0000u, 46u}, // myx -> Latn
+ {0xE70C0000u, 52u}, // myz -> Mand
+ {0xAB2C0000u, 46u}, // mzk -> Latn
+ {0xB32C0000u, 46u}, // mzm -> Latn
{0xB72C0000u, 1u}, // mzn -> Arab
- {0xBF2C0000u, 44u}, // mzp -> Latn
- {0xDB2C0000u, 44u}, // mzw -> Latn
- {0xE72C0000u, 44u}, // mzz -> Latn
- {0x6E610000u, 44u}, // na -> Latn
- {0x880D0000u, 44u}, // nac -> Latn
- {0x940D0000u, 44u}, // naf -> Latn
- {0xA80D0000u, 44u}, // nak -> Latn
- {0xB40D0000u, 27u}, // nan -> Hans
- {0xBC0D0000u, 44u}, // nap -> Latn
- {0xC00D0000u, 44u}, // naq -> Latn
- {0xC80D0000u, 44u}, // nas -> Latn
- {0x6E620000u, 44u}, // nb -> Latn
- {0x804D0000u, 44u}, // nca -> Latn
- {0x904D0000u, 44u}, // nce -> Latn
- {0x944D0000u, 44u}, // ncf -> Latn
- {0x9C4D0000u, 44u}, // nch -> Latn
- {0xB84D0000u, 44u}, // nco -> Latn
- {0xD04D0000u, 44u}, // ncu -> Latn
- {0x6E640000u, 44u}, // nd -> Latn
- {0x886D0000u, 44u}, // ndc -> Latn
- {0xC86D0000u, 44u}, // nds -> Latn
- {0x6E650000u, 17u}, // ne -> Deva
- {0x848D0000u, 44u}, // neb -> Latn
- {0xD88D0000u, 17u}, // new -> Deva
- {0xDC8D0000u, 44u}, // nex -> Latn
- {0xC4AD0000u, 44u}, // nfr -> Latn
- {0x6E670000u, 44u}, // ng -> Latn
- {0x80CD0000u, 44u}, // nga -> Latn
- {0x84CD0000u, 44u}, // ngb -> Latn
- {0xACCD0000u, 44u}, // ngl -> Latn
- {0x84ED0000u, 44u}, // nhb -> Latn
- {0x90ED0000u, 44u}, // nhe -> Latn
- {0xD8ED0000u, 44u}, // nhw -> Latn
- {0x950D0000u, 44u}, // nif -> Latn
- {0xA10D0000u, 44u}, // nii -> Latn
- {0xA50D0000u, 44u}, // nij -> Latn
- {0xB50D0000u, 44u}, // nin -> Latn
- {0xD10D0000u, 44u}, // niu -> Latn
- {0xE10D0000u, 44u}, // niy -> Latn
- {0xE50D0000u, 44u}, // niz -> Latn
- {0xB92D0000u, 44u}, // njo -> Latn
- {0x994D0000u, 44u}, // nkg -> Latn
- {0xB94D0000u, 44u}, // nko -> Latn
- {0x6E6C0000u, 44u}, // nl -> Latn
- {0x998D0000u, 44u}, // nmg -> Latn
- {0xE58D0000u, 44u}, // nmz -> Latn
- {0x6E6E0000u, 44u}, // nn -> Latn
- {0x95AD0000u, 44u}, // nnf -> Latn
- {0x9DAD0000u, 44u}, // nnh -> Latn
- {0xA9AD0000u, 44u}, // nnk -> Latn
- {0xB1AD0000u, 44u}, // nnm -> Latn
- {0xBDAD0000u, 91u}, // nnp -> Wcho
- {0x6E6F0000u, 44u}, // no -> Latn
- {0x8DCD0000u, 42u}, // nod -> Lana
- {0x91CD0000u, 17u}, // noe -> Deva
- {0xB5CD0000u, 69u}, // non -> Runr
- {0xBDCD0000u, 44u}, // nop -> Latn
- {0xD1CD0000u, 44u}, // nou -> Latn
- {0xBA0D0000u, 58u}, // nqo -> Nkoo
- {0x6E720000u, 44u}, // nr -> Latn
- {0x862D0000u, 44u}, // nrb -> Latn
+ {0xBF2C0000u, 46u}, // mzp -> Latn
+ {0xDB2C0000u, 46u}, // mzw -> Latn
+ {0xE72C0000u, 46u}, // mzz -> Latn
+ {0x6E610000u, 46u}, // na -> Latn
+ {0x880D0000u, 46u}, // nac -> Latn
+ {0x940D0000u, 46u}, // naf -> Latn
+ {0xA80D0000u, 46u}, // nak -> Latn
+ {0xB40D0000u, 28u}, // nan -> Hans
+ {0xBC0D0000u, 46u}, // nap -> Latn
+ {0xC00D0000u, 46u}, // naq -> Latn
+ {0xC80D0000u, 46u}, // nas -> Latn
+ {0x6E620000u, 46u}, // nb -> Latn
+ {0x804D0000u, 46u}, // nca -> Latn
+ {0x904D0000u, 46u}, // nce -> Latn
+ {0x944D0000u, 46u}, // ncf -> Latn
+ {0x9C4D0000u, 46u}, // nch -> Latn
+ {0xB84D0000u, 46u}, // nco -> Latn
+ {0xD04D0000u, 46u}, // ncu -> Latn
+ {0x6E640000u, 46u}, // nd -> Latn
+ {0x886D0000u, 46u}, // ndc -> Latn
+ {0xC86D0000u, 46u}, // nds -> Latn
+ {0x6E650000u, 18u}, // ne -> Deva
+ {0x848D0000u, 46u}, // neb -> Latn
+ {0xD88D0000u, 18u}, // new -> Deva
+ {0xDC8D0000u, 46u}, // nex -> Latn
+ {0xC4AD0000u, 46u}, // nfr -> Latn
+ {0x6E670000u, 46u}, // ng -> Latn
+ {0x80CD0000u, 46u}, // nga -> Latn
+ {0x84CD0000u, 46u}, // ngb -> Latn
+ {0xACCD0000u, 46u}, // ngl -> Latn
+ {0x84ED0000u, 46u}, // nhb -> Latn
+ {0x90ED0000u, 46u}, // nhe -> Latn
+ {0xD8ED0000u, 46u}, // nhw -> Latn
+ {0x950D0000u, 46u}, // nif -> Latn
+ {0xA10D0000u, 46u}, // nii -> Latn
+ {0xA50D0000u, 46u}, // nij -> Latn
+ {0xB50D0000u, 46u}, // nin -> Latn
+ {0xD10D0000u, 46u}, // niu -> Latn
+ {0xE10D0000u, 46u}, // niy -> Latn
+ {0xE50D0000u, 46u}, // niz -> Latn
+ {0xB92D0000u, 46u}, // njo -> Latn
+ {0x994D0000u, 46u}, // nkg -> Latn
+ {0xB94D0000u, 46u}, // nko -> Latn
+ {0x6E6C0000u, 46u}, // nl -> Latn
+ {0x998D0000u, 46u}, // nmg -> Latn
+ {0xE58D0000u, 46u}, // nmz -> Latn
+ {0x6E6E0000u, 46u}, // nn -> Latn
+ {0x95AD0000u, 46u}, // nnf -> Latn
+ {0x9DAD0000u, 46u}, // nnh -> Latn
+ {0xA9AD0000u, 46u}, // nnk -> Latn
+ {0xB1AD0000u, 46u}, // nnm -> Latn
+ {0xBDAD0000u, 93u}, // nnp -> Wcho
+ {0x6E6F0000u, 46u}, // no -> Latn
+ {0x8DCD0000u, 44u}, // nod -> Lana
+ {0x91CD0000u, 18u}, // noe -> Deva
+ {0xB5CD0000u, 71u}, // non -> Runr
+ {0xBDCD0000u, 46u}, // nop -> Latn
+ {0xD1CD0000u, 46u}, // nou -> Latn
+ {0xBA0D0000u, 60u}, // nqo -> Nkoo
+ {0x6E720000u, 46u}, // nr -> Latn
+ {0x862D0000u, 46u}, // nrb -> Latn
{0xAA4D0000u, 10u}, // nsk -> Cans
- {0xB64D0000u, 44u}, // nsn -> Latn
- {0xBA4D0000u, 44u}, // nso -> Latn
- {0xCA4D0000u, 44u}, // nss -> Latn
- {0xB26D0000u, 44u}, // ntm -> Latn
- {0xC66D0000u, 44u}, // ntr -> Latn
- {0xA28D0000u, 44u}, // nui -> Latn
- {0xBE8D0000u, 44u}, // nup -> Latn
- {0xCA8D0000u, 44u}, // nus -> Latn
- {0xD68D0000u, 44u}, // nuv -> Latn
- {0xDE8D0000u, 44u}, // nux -> Latn
- {0x6E760000u, 44u}, // nv -> Latn
- {0x86CD0000u, 44u}, // nwb -> Latn
- {0xC2ED0000u, 44u}, // nxq -> Latn
- {0xC6ED0000u, 44u}, // nxr -> Latn
- {0x6E790000u, 44u}, // ny -> Latn
- {0xB30D0000u, 44u}, // nym -> Latn
- {0xB70D0000u, 44u}, // nyn -> Latn
- {0xA32D0000u, 44u}, // nzi -> Latn
- {0x6F630000u, 44u}, // oc -> Latn
- {0x88CE0000u, 44u}, // ogc -> Latn
- {0xC54E0000u, 44u}, // okr -> Latn
- {0xD54E0000u, 44u}, // okv -> Latn
- {0x6F6D0000u, 44u}, // om -> Latn
- {0x99AE0000u, 44u}, // ong -> Latn
- {0xB5AE0000u, 44u}, // onn -> Latn
- {0xC9AE0000u, 44u}, // ons -> Latn
- {0xB1EE0000u, 44u}, // opm -> Latn
- {0x6F720000u, 62u}, // or -> Orya
- {0xBA2E0000u, 44u}, // oro -> Latn
+ {0xB64D0000u, 46u}, // nsn -> Latn
+ {0xBA4D0000u, 46u}, // nso -> Latn
+ {0xCA4D0000u, 46u}, // nss -> Latn
+ {0xB26D0000u, 46u}, // ntm -> Latn
+ {0xC66D0000u, 46u}, // ntr -> Latn
+ {0xA28D0000u, 46u}, // nui -> Latn
+ {0xBE8D0000u, 46u}, // nup -> Latn
+ {0xCA8D0000u, 46u}, // nus -> Latn
+ {0xD68D0000u, 46u}, // nuv -> Latn
+ {0xDE8D0000u, 46u}, // nux -> Latn
+ {0x6E760000u, 46u}, // nv -> Latn
+ {0x86CD0000u, 46u}, // nwb -> Latn
+ {0xC2ED0000u, 46u}, // nxq -> Latn
+ {0xC6ED0000u, 46u}, // nxr -> Latn
+ {0x6E790000u, 46u}, // ny -> Latn
+ {0xB30D0000u, 46u}, // nym -> Latn
+ {0xB70D0000u, 46u}, // nyn -> Latn
+ {0xA32D0000u, 46u}, // nzi -> Latn
+ {0x6F630000u, 46u}, // oc -> Latn
+ {0x88CE0000u, 46u}, // ogc -> Latn
+ {0xC54E0000u, 46u}, // okr -> Latn
+ {0xD54E0000u, 46u}, // okv -> Latn
+ {0x6F6D0000u, 46u}, // om -> Latn
+ {0x99AE0000u, 46u}, // ong -> Latn
+ {0xB5AE0000u, 46u}, // onn -> Latn
+ {0xC9AE0000u, 46u}, // ons -> Latn
+ {0xB1EE0000u, 46u}, // opm -> Latn
+ {0x6F720000u, 64u}, // or -> Orya
+ {0xBA2E0000u, 46u}, // oro -> Latn
{0xD22E0000u, 1u}, // oru -> Arab
- {0x6F730000u, 16u}, // os -> Cyrl
- {0x824E0000u, 63u}, // osa -> Osge
+ {0x6F730000u, 17u}, // os -> Cyrl
+ {0x824E0000u, 65u}, // osa -> Osge
{0x826E0000u, 1u}, // ota -> Arab
- {0xAA6E0000u, 61u}, // otk -> Orkh
- {0xB32E0000u, 44u}, // ozm -> Latn
- {0x70610000u, 26u}, // pa -> Guru
+ {0xAA6E0000u, 63u}, // otk -> Orkh
+ {0xB32E0000u, 46u}, // ozm -> Latn
+ {0x70610000u, 27u}, // pa -> Guru
{0x7061504Bu, 1u}, // pa-PK -> Arab
- {0x980F0000u, 44u}, // pag -> Latn
- {0xAC0F0000u, 65u}, // pal -> Phli
- {0xB00F0000u, 44u}, // pam -> Latn
- {0xBC0F0000u, 44u}, // pap -> Latn
- {0xD00F0000u, 44u}, // pau -> Latn
- {0xA02F0000u, 44u}, // pbi -> Latn
- {0x8C4F0000u, 44u}, // pcd -> Latn
- {0xB04F0000u, 44u}, // pcm -> Latn
- {0x886F0000u, 44u}, // pdc -> Latn
- {0xCC6F0000u, 44u}, // pdt -> Latn
- {0x8C8F0000u, 44u}, // ped -> Latn
- {0xB88F0000u, 92u}, // peo -> Xpeo
- {0xDC8F0000u, 44u}, // pex -> Latn
- {0xACAF0000u, 44u}, // pfl -> Latn
+ {0x980F0000u, 46u}, // pag -> Latn
+ {0xAC0F0000u, 67u}, // pal -> Phli
+ {0xB00F0000u, 46u}, // pam -> Latn
+ {0xBC0F0000u, 46u}, // pap -> Latn
+ {0xD00F0000u, 46u}, // pau -> Latn
+ {0xA02F0000u, 46u}, // pbi -> Latn
+ {0x8C4F0000u, 46u}, // pcd -> Latn
+ {0xB04F0000u, 46u}, // pcm -> Latn
+ {0x886F0000u, 46u}, // pdc -> Latn
+ {0xCC6F0000u, 46u}, // pdt -> Latn
+ {0x8C8F0000u, 46u}, // ped -> Latn
+ {0xB88F0000u, 94u}, // peo -> Xpeo
+ {0xDC8F0000u, 46u}, // pex -> Latn
+ {0xACAF0000u, 46u}, // pfl -> Latn
{0xACEF0000u, 1u}, // phl -> Arab
- {0xB4EF0000u, 66u}, // phn -> Phnx
- {0xAD0F0000u, 44u}, // pil -> Latn
- {0xBD0F0000u, 44u}, // pip -> Latn
+ {0xB4EF0000u, 68u}, // phn -> Phnx
+ {0xAD0F0000u, 46u}, // pil -> Latn
+ {0xBD0F0000u, 46u}, // pip -> Latn
{0x814F0000u, 8u}, // pka -> Brah
- {0xB94F0000u, 44u}, // pko -> Latn
- {0x706C0000u, 44u}, // pl -> Latn
- {0x816F0000u, 44u}, // pla -> Latn
- {0xC98F0000u, 44u}, // pms -> Latn
- {0x99AF0000u, 44u}, // png -> Latn
- {0xB5AF0000u, 44u}, // pnn -> Latn
- {0xCDAF0000u, 24u}, // pnt -> Grek
- {0xB5CF0000u, 44u}, // pon -> Latn
- {0x81EF0000u, 17u}, // ppa -> Deva
- {0xB9EF0000u, 44u}, // ppo -> Latn
- {0x822F0000u, 38u}, // pra -> Khar
+ {0xB94F0000u, 46u}, // pko -> Latn
+ {0x706C0000u, 46u}, // pl -> Latn
+ {0x816F0000u, 46u}, // pla -> Latn
+ {0xC98F0000u, 46u}, // pms -> Latn
+ {0x99AF0000u, 46u}, // png -> Latn
+ {0xB5AF0000u, 46u}, // pnn -> Latn
+ {0xCDAF0000u, 25u}, // pnt -> Grek
+ {0xB5CF0000u, 46u}, // pon -> Latn
+ {0x81EF0000u, 18u}, // ppa -> Deva
+ {0xB9EF0000u, 46u}, // ppo -> Latn
+ {0x822F0000u, 39u}, // pra -> Khar
{0x8E2F0000u, 1u}, // prd -> Arab
- {0x9A2F0000u, 44u}, // prg -> Latn
+ {0x9A2F0000u, 46u}, // prg -> Latn
{0x70730000u, 1u}, // ps -> Arab
- {0xCA4F0000u, 44u}, // pss -> Latn
- {0x70740000u, 44u}, // pt -> Latn
- {0xBE6F0000u, 44u}, // ptp -> Latn
- {0xD28F0000u, 44u}, // puu -> Latn
- {0x82CF0000u, 44u}, // pwa -> Latn
- {0x71750000u, 44u}, // qu -> Latn
- {0x8A900000u, 44u}, // quc -> Latn
- {0x9A900000u, 44u}, // qug -> Latn
- {0xA0110000u, 44u}, // rai -> Latn
- {0xA4110000u, 17u}, // raj -> Deva
- {0xB8110000u, 44u}, // rao -> Latn
- {0x94510000u, 44u}, // rcf -> Latn
- {0xA4910000u, 44u}, // rej -> Latn
- {0xAC910000u, 44u}, // rel -> Latn
- {0xC8910000u, 44u}, // res -> Latn
- {0xB4D10000u, 44u}, // rgn -> Latn
+ {0xCA4F0000u, 46u}, // pss -> Latn
+ {0x70740000u, 46u}, // pt -> Latn
+ {0xBE6F0000u, 46u}, // ptp -> Latn
+ {0xD28F0000u, 46u}, // puu -> Latn
+ {0x82CF0000u, 46u}, // pwa -> Latn
+ {0x71750000u, 46u}, // qu -> Latn
+ {0x8A900000u, 46u}, // quc -> Latn
+ {0x9A900000u, 46u}, // qug -> Latn
+ {0xA0110000u, 46u}, // rai -> Latn
+ {0xA4110000u, 18u}, // raj -> Deva
+ {0xB8110000u, 46u}, // rao -> Latn
+ {0x94510000u, 46u}, // rcf -> Latn
+ {0xA4910000u, 46u}, // rej -> Latn
+ {0xAC910000u, 46u}, // rel -> Latn
+ {0xC8910000u, 46u}, // res -> Latn
+ {0xB4D10000u, 46u}, // rgn -> Latn
{0x98F10000u, 1u}, // rhg -> Arab
- {0x81110000u, 44u}, // ria -> Latn
- {0x95110000u, 85u}, // rif -> Tfng
- {0x95114E4Cu, 44u}, // rif-NL -> Latn
- {0xC9310000u, 17u}, // rjs -> Deva
+ {0x81110000u, 46u}, // ria -> Latn
+ {0x95110000u, 87u}, // rif -> Tfng
+ {0x95114E4Cu, 46u}, // rif-NL -> Latn
+ {0xC9310000u, 18u}, // rjs -> Deva
{0xCD510000u, 7u}, // rkt -> Beng
- {0x726D0000u, 44u}, // rm -> Latn
- {0x95910000u, 44u}, // rmf -> Latn
- {0xB9910000u, 44u}, // rmo -> Latn
+ {0x726D0000u, 46u}, // rm -> Latn
+ {0x95910000u, 46u}, // rmf -> Latn
+ {0xB9910000u, 46u}, // rmo -> Latn
{0xCD910000u, 1u}, // rmt -> Arab
- {0xD1910000u, 44u}, // rmu -> Latn
- {0x726E0000u, 44u}, // rn -> Latn
- {0x81B10000u, 44u}, // rna -> Latn
- {0x99B10000u, 44u}, // rng -> Latn
- {0x726F0000u, 44u}, // ro -> Latn
- {0x85D10000u, 44u}, // rob -> Latn
- {0x95D10000u, 44u}, // rof -> Latn
- {0xB9D10000u, 44u}, // roo -> Latn
- {0xBA310000u, 44u}, // rro -> Latn
- {0xB2710000u, 44u}, // rtm -> Latn
- {0x72750000u, 16u}, // ru -> Cyrl
- {0x92910000u, 16u}, // rue -> Cyrl
- {0x9A910000u, 44u}, // rug -> Latn
- {0x72770000u, 44u}, // rw -> Latn
- {0xAAD10000u, 44u}, // rwk -> Latn
- {0xBAD10000u, 44u}, // rwo -> Latn
- {0xD3110000u, 37u}, // ryu -> Kana
- {0x73610000u, 17u}, // sa -> Deva
- {0x94120000u, 44u}, // saf -> Latn
- {0x9C120000u, 16u}, // sah -> Cyrl
- {0xC0120000u, 44u}, // saq -> Latn
- {0xC8120000u, 44u}, // sas -> Latn
- {0xCC120000u, 44u}, // sat -> Latn
- {0xD4120000u, 44u}, // sav -> Latn
- {0xE4120000u, 72u}, // saz -> Saur
- {0x80320000u, 44u}, // sba -> Latn
- {0x90320000u, 44u}, // sbe -> Latn
- {0xBC320000u, 44u}, // sbp -> Latn
- {0x73630000u, 44u}, // sc -> Latn
- {0xA8520000u, 17u}, // sck -> Deva
+ {0xD1910000u, 46u}, // rmu -> Latn
+ {0x726E0000u, 46u}, // rn -> Latn
+ {0x81B10000u, 46u}, // rna -> Latn
+ {0x99B10000u, 46u}, // rng -> Latn
+ {0x726F0000u, 46u}, // ro -> Latn
+ {0x85D10000u, 46u}, // rob -> Latn
+ {0x95D10000u, 46u}, // rof -> Latn
+ {0xB9D10000u, 46u}, // roo -> Latn
+ {0xBA310000u, 46u}, // rro -> Latn
+ {0xB2710000u, 46u}, // rtm -> Latn
+ {0x72750000u, 17u}, // ru -> Cyrl
+ {0x92910000u, 17u}, // rue -> Cyrl
+ {0x9A910000u, 46u}, // rug -> Latn
+ {0x72770000u, 46u}, // rw -> Latn
+ {0xAAD10000u, 46u}, // rwk -> Latn
+ {0xBAD10000u, 46u}, // rwo -> Latn
+ {0xD3110000u, 38u}, // ryu -> Kana
+ {0x73610000u, 18u}, // sa -> Deva
+ {0x94120000u, 46u}, // saf -> Latn
+ {0x9C120000u, 17u}, // sah -> Cyrl
+ {0xC0120000u, 46u}, // saq -> Latn
+ {0xC8120000u, 46u}, // sas -> Latn
+ {0xCC120000u, 46u}, // sat -> Latn
+ {0xD4120000u, 46u}, // sav -> Latn
+ {0xE4120000u, 74u}, // saz -> Saur
+ {0x80320000u, 46u}, // sba -> Latn
+ {0x90320000u, 46u}, // sbe -> Latn
+ {0xBC320000u, 46u}, // sbp -> Latn
+ {0x73630000u, 46u}, // sc -> Latn
+ {0xA8520000u, 18u}, // sck -> Deva
{0xAC520000u, 1u}, // scl -> Arab
- {0xB4520000u, 44u}, // scn -> Latn
- {0xB8520000u, 44u}, // sco -> Latn
- {0xC8520000u, 44u}, // scs -> Latn
+ {0xB4520000u, 46u}, // scn -> Latn
+ {0xB8520000u, 46u}, // sco -> Latn
+ {0xC8520000u, 46u}, // scs -> Latn
{0x73640000u, 1u}, // sd -> Arab
- {0x88720000u, 44u}, // sdc -> Latn
+ {0x88720000u, 46u}, // sdc -> Latn
{0x9C720000u, 1u}, // sdh -> Arab
- {0x73650000u, 44u}, // se -> Latn
- {0x94920000u, 44u}, // sef -> Latn
- {0x9C920000u, 44u}, // seh -> Latn
- {0xA0920000u, 44u}, // sei -> Latn
- {0xC8920000u, 44u}, // ses -> Latn
- {0x73670000u, 44u}, // sg -> Latn
- {0x80D20000u, 60u}, // sga -> Ogam
- {0xC8D20000u, 44u}, // sgs -> Latn
- {0xD8D20000u, 19u}, // sgw -> Ethi
- {0xE4D20000u, 44u}, // sgz -> Latn
- {0x73680000u, 44u}, // sh -> Latn
- {0xA0F20000u, 85u}, // shi -> Tfng
- {0xA8F20000u, 44u}, // shk -> Latn
- {0xB4F20000u, 56u}, // shn -> Mymr
+ {0x73650000u, 46u}, // se -> Latn
+ {0x94920000u, 46u}, // sef -> Latn
+ {0x9C920000u, 46u}, // seh -> Latn
+ {0xA0920000u, 46u}, // sei -> Latn
+ {0xC8920000u, 46u}, // ses -> Latn
+ {0x73670000u, 46u}, // sg -> Latn
+ {0x80D20000u, 62u}, // sga -> Ogam
+ {0xC8D20000u, 46u}, // sgs -> Latn
+ {0xD8D20000u, 20u}, // sgw -> Ethi
+ {0xE4D20000u, 46u}, // sgz -> Latn
+ {0x73680000u, 46u}, // sh -> Latn
+ {0xA0F20000u, 87u}, // shi -> Tfng
+ {0xA8F20000u, 46u}, // shk -> Latn
+ {0xB4F20000u, 58u}, // shn -> Mymr
{0xD0F20000u, 1u}, // shu -> Arab
- {0x73690000u, 74u}, // si -> Sinh
- {0x8D120000u, 44u}, // sid -> Latn
- {0x99120000u, 44u}, // sig -> Latn
- {0xAD120000u, 44u}, // sil -> Latn
- {0xB1120000u, 44u}, // sim -> Latn
- {0xC5320000u, 44u}, // sjr -> Latn
- {0x736B0000u, 44u}, // sk -> Latn
- {0x89520000u, 44u}, // skc -> Latn
+ {0x73690000u, 76u}, // si -> Sinh
+ {0x8D120000u, 46u}, // sid -> Latn
+ {0x99120000u, 46u}, // sig -> Latn
+ {0xAD120000u, 46u}, // sil -> Latn
+ {0xB1120000u, 46u}, // sim -> Latn
+ {0xC5320000u, 46u}, // sjr -> Latn
+ {0x736B0000u, 46u}, // sk -> Latn
+ {0x89520000u, 46u}, // skc -> Latn
{0xC5520000u, 1u}, // skr -> Arab
- {0xC9520000u, 44u}, // sks -> Latn
- {0x736C0000u, 44u}, // sl -> Latn
- {0x8D720000u, 44u}, // sld -> Latn
- {0xA1720000u, 44u}, // sli -> Latn
- {0xAD720000u, 44u}, // sll -> Latn
- {0xE1720000u, 44u}, // sly -> Latn
- {0x736D0000u, 44u}, // sm -> Latn
- {0x81920000u, 44u}, // sma -> Latn
- {0xA5920000u, 44u}, // smj -> Latn
- {0xB5920000u, 44u}, // smn -> Latn
- {0xBD920000u, 70u}, // smp -> Samr
- {0xC1920000u, 44u}, // smq -> Latn
- {0xC9920000u, 44u}, // sms -> Latn
- {0x736E0000u, 44u}, // sn -> Latn
- {0x89B20000u, 44u}, // snc -> Latn
- {0xA9B20000u, 44u}, // snk -> Latn
- {0xBDB20000u, 44u}, // snp -> Latn
- {0xDDB20000u, 44u}, // snx -> Latn
- {0xE1B20000u, 44u}, // sny -> Latn
- {0x736F0000u, 44u}, // so -> Latn
- {0x99D20000u, 75u}, // sog -> Sogd
- {0xA9D20000u, 44u}, // sok -> Latn
- {0xC1D20000u, 44u}, // soq -> Latn
- {0xD1D20000u, 87u}, // sou -> Thai
- {0xE1D20000u, 44u}, // soy -> Latn
- {0x8DF20000u, 44u}, // spd -> Latn
- {0xADF20000u, 44u}, // spl -> Latn
- {0xC9F20000u, 44u}, // sps -> Latn
- {0x73710000u, 44u}, // sq -> Latn
- {0x73720000u, 16u}, // sr -> Cyrl
- {0x73724D45u, 44u}, // sr-ME -> Latn
- {0x7372524Fu, 44u}, // sr-RO -> Latn
- {0x73725255u, 44u}, // sr-RU -> Latn
- {0x73725452u, 44u}, // sr-TR -> Latn
- {0x86320000u, 76u}, // srb -> Sora
- {0xB6320000u, 44u}, // srn -> Latn
- {0xC6320000u, 44u}, // srr -> Latn
- {0xDE320000u, 17u}, // srx -> Deva
- {0x73730000u, 44u}, // ss -> Latn
- {0x8E520000u, 44u}, // ssd -> Latn
- {0x9A520000u, 44u}, // ssg -> Latn
- {0xE2520000u, 44u}, // ssy -> Latn
- {0x73740000u, 44u}, // st -> Latn
- {0xAA720000u, 44u}, // stk -> Latn
- {0xC2720000u, 44u}, // stq -> Latn
- {0x73750000u, 44u}, // su -> Latn
- {0x82920000u, 44u}, // sua -> Latn
- {0x92920000u, 44u}, // sue -> Latn
- {0xAA920000u, 44u}, // suk -> Latn
- {0xC6920000u, 44u}, // sur -> Latn
- {0xCA920000u, 44u}, // sus -> Latn
- {0x73760000u, 44u}, // sv -> Latn
- {0x73770000u, 44u}, // sw -> Latn
+ {0xC9520000u, 46u}, // sks -> Latn
+ {0x736C0000u, 46u}, // sl -> Latn
+ {0x8D720000u, 46u}, // sld -> Latn
+ {0xA1720000u, 46u}, // sli -> Latn
+ {0xAD720000u, 46u}, // sll -> Latn
+ {0xE1720000u, 46u}, // sly -> Latn
+ {0x736D0000u, 46u}, // sm -> Latn
+ {0x81920000u, 46u}, // sma -> Latn
+ {0xA5920000u, 46u}, // smj -> Latn
+ {0xB5920000u, 46u}, // smn -> Latn
+ {0xBD920000u, 72u}, // smp -> Samr
+ {0xC1920000u, 46u}, // smq -> Latn
+ {0xC9920000u, 46u}, // sms -> Latn
+ {0x736E0000u, 46u}, // sn -> Latn
+ {0x89B20000u, 46u}, // snc -> Latn
+ {0xA9B20000u, 46u}, // snk -> Latn
+ {0xBDB20000u, 46u}, // snp -> Latn
+ {0xDDB20000u, 46u}, // snx -> Latn
+ {0xE1B20000u, 46u}, // sny -> Latn
+ {0x736F0000u, 46u}, // so -> Latn
+ {0x99D20000u, 77u}, // sog -> Sogd
+ {0xA9D20000u, 46u}, // sok -> Latn
+ {0xC1D20000u, 46u}, // soq -> Latn
+ {0xD1D20000u, 89u}, // sou -> Thai
+ {0xE1D20000u, 46u}, // soy -> Latn
+ {0x8DF20000u, 46u}, // spd -> Latn
+ {0xADF20000u, 46u}, // spl -> Latn
+ {0xC9F20000u, 46u}, // sps -> Latn
+ {0x73710000u, 46u}, // sq -> Latn
+ {0x73720000u, 17u}, // sr -> Cyrl
+ {0x73724D45u, 46u}, // sr-ME -> Latn
+ {0x7372524Fu, 46u}, // sr-RO -> Latn
+ {0x73725255u, 46u}, // sr-RU -> Latn
+ {0x73725452u, 46u}, // sr-TR -> Latn
+ {0x86320000u, 78u}, // srb -> Sora
+ {0xB6320000u, 46u}, // srn -> Latn
+ {0xC6320000u, 46u}, // srr -> Latn
+ {0xDE320000u, 18u}, // srx -> Deva
+ {0x73730000u, 46u}, // ss -> Latn
+ {0x8E520000u, 46u}, // ssd -> Latn
+ {0x9A520000u, 46u}, // ssg -> Latn
+ {0xE2520000u, 46u}, // ssy -> Latn
+ {0x73740000u, 46u}, // st -> Latn
+ {0xAA720000u, 46u}, // stk -> Latn
+ {0xC2720000u, 46u}, // stq -> Latn
+ {0x73750000u, 46u}, // su -> Latn
+ {0x82920000u, 46u}, // sua -> Latn
+ {0x92920000u, 46u}, // sue -> Latn
+ {0xAA920000u, 46u}, // suk -> Latn
+ {0xC6920000u, 46u}, // sur -> Latn
+ {0xCA920000u, 46u}, // sus -> Latn
+ {0x73760000u, 46u}, // sv -> Latn
+ {0x73770000u, 46u}, // sw -> Latn
{0x86D20000u, 1u}, // swb -> Arab
- {0x8AD20000u, 44u}, // swc -> Latn
- {0x9AD20000u, 44u}, // swg -> Latn
- {0xBED20000u, 44u}, // swp -> Latn
- {0xD6D20000u, 17u}, // swv -> Deva
- {0xB6F20000u, 44u}, // sxn -> Latn
- {0xDAF20000u, 44u}, // sxw -> Latn
+ {0x8AD20000u, 46u}, // swc -> Latn
+ {0x9AD20000u, 46u}, // swg -> Latn
+ {0xBED20000u, 46u}, // swp -> Latn
+ {0xD6D20000u, 18u}, // swv -> Deva
+ {0xB6F20000u, 46u}, // sxn -> Latn
+ {0xDAF20000u, 46u}, // sxw -> Latn
{0xAF120000u, 7u}, // syl -> Beng
- {0xC7120000u, 78u}, // syr -> Syrc
- {0xAF320000u, 44u}, // szl -> Latn
- {0x74610000u, 81u}, // ta -> Taml
- {0xA4130000u, 17u}, // taj -> Deva
- {0xAC130000u, 44u}, // tal -> Latn
- {0xB4130000u, 44u}, // tan -> Latn
- {0xC0130000u, 44u}, // taq -> Latn
- {0x88330000u, 44u}, // tbc -> Latn
- {0x8C330000u, 44u}, // tbd -> Latn
- {0x94330000u, 44u}, // tbf -> Latn
- {0x98330000u, 44u}, // tbg -> Latn
- {0xB8330000u, 44u}, // tbo -> Latn
- {0xD8330000u, 44u}, // tbw -> Latn
- {0xE4330000u, 44u}, // tbz -> Latn
- {0xA0530000u, 44u}, // tci -> Latn
- {0xE0530000u, 40u}, // tcy -> Knda
- {0x8C730000u, 79u}, // tdd -> Tale
- {0x98730000u, 17u}, // tdg -> Deva
- {0x9C730000u, 17u}, // tdh -> Deva
- {0xD0730000u, 44u}, // tdu -> Latn
- {0x74650000u, 84u}, // te -> Telu
- {0x8C930000u, 44u}, // ted -> Latn
- {0xB0930000u, 44u}, // tem -> Latn
- {0xB8930000u, 44u}, // teo -> Latn
- {0xCC930000u, 44u}, // tet -> Latn
- {0xA0B30000u, 44u}, // tfi -> Latn
- {0x74670000u, 16u}, // tg -> Cyrl
+ {0xC7120000u, 80u}, // syr -> Syrc
+ {0xAF320000u, 46u}, // szl -> Latn
+ {0x74610000u, 83u}, // ta -> Taml
+ {0xA4130000u, 18u}, // taj -> Deva
+ {0xAC130000u, 46u}, // tal -> Latn
+ {0xB4130000u, 46u}, // tan -> Latn
+ {0xC0130000u, 46u}, // taq -> Latn
+ {0x88330000u, 46u}, // tbc -> Latn
+ {0x8C330000u, 46u}, // tbd -> Latn
+ {0x94330000u, 46u}, // tbf -> Latn
+ {0x98330000u, 46u}, // tbg -> Latn
+ {0xB8330000u, 46u}, // tbo -> Latn
+ {0xD8330000u, 46u}, // tbw -> Latn
+ {0xE4330000u, 46u}, // tbz -> Latn
+ {0xA0530000u, 46u}, // tci -> Latn
+ {0xE0530000u, 42u}, // tcy -> Knda
+ {0x8C730000u, 81u}, // tdd -> Tale
+ {0x98730000u, 18u}, // tdg -> Deva
+ {0x9C730000u, 18u}, // tdh -> Deva
+ {0xD0730000u, 46u}, // tdu -> Latn
+ {0x74650000u, 86u}, // te -> Telu
+ {0x8C930000u, 46u}, // ted -> Latn
+ {0xB0930000u, 46u}, // tem -> Latn
+ {0xB8930000u, 46u}, // teo -> Latn
+ {0xCC930000u, 46u}, // tet -> Latn
+ {0xA0B30000u, 46u}, // tfi -> Latn
+ {0x74670000u, 17u}, // tg -> Cyrl
{0x7467504Bu, 1u}, // tg-PK -> Arab
- {0x88D30000u, 44u}, // tgc -> Latn
- {0xB8D30000u, 44u}, // tgo -> Latn
- {0xD0D30000u, 44u}, // tgu -> Latn
- {0x74680000u, 87u}, // th -> Thai
- {0xACF30000u, 17u}, // thl -> Deva
- {0xC0F30000u, 17u}, // thq -> Deva
- {0xC4F30000u, 17u}, // thr -> Deva
- {0x74690000u, 19u}, // ti -> Ethi
- {0x95130000u, 44u}, // tif -> Latn
- {0x99130000u, 19u}, // tig -> Ethi
- {0xA9130000u, 44u}, // tik -> Latn
- {0xB1130000u, 44u}, // tim -> Latn
- {0xB9130000u, 44u}, // tio -> Latn
- {0xD5130000u, 44u}, // tiv -> Latn
- {0x746B0000u, 44u}, // tk -> Latn
- {0xAD530000u, 44u}, // tkl -> Latn
- {0xC5530000u, 44u}, // tkr -> Latn
- {0xCD530000u, 17u}, // tkt -> Deva
- {0x746C0000u, 44u}, // tl -> Latn
- {0x95730000u, 44u}, // tlf -> Latn
- {0xDD730000u, 44u}, // tlx -> Latn
- {0xE1730000u, 44u}, // tly -> Latn
- {0x9D930000u, 44u}, // tmh -> Latn
- {0xE1930000u, 44u}, // tmy -> Latn
- {0x746E0000u, 44u}, // tn -> Latn
- {0x9DB30000u, 44u}, // tnh -> Latn
- {0x746F0000u, 44u}, // to -> Latn
- {0x95D30000u, 44u}, // tof -> Latn
- {0x99D30000u, 44u}, // tog -> Latn
- {0xC1D30000u, 44u}, // toq -> Latn
- {0xA1F30000u, 44u}, // tpi -> Latn
- {0xB1F30000u, 44u}, // tpm -> Latn
- {0xE5F30000u, 44u}, // tpz -> Latn
- {0xBA130000u, 44u}, // tqo -> Latn
- {0x74720000u, 44u}, // tr -> Latn
- {0xD2330000u, 44u}, // tru -> Latn
- {0xD6330000u, 44u}, // trv -> Latn
+ {0x88D30000u, 46u}, // tgc -> Latn
+ {0xB8D30000u, 46u}, // tgo -> Latn
+ {0xD0D30000u, 46u}, // tgu -> Latn
+ {0x74680000u, 89u}, // th -> Thai
+ {0xACF30000u, 18u}, // thl -> Deva
+ {0xC0F30000u, 18u}, // thq -> Deva
+ {0xC4F30000u, 18u}, // thr -> Deva
+ {0x74690000u, 20u}, // ti -> Ethi
+ {0x95130000u, 46u}, // tif -> Latn
+ {0x99130000u, 20u}, // tig -> Ethi
+ {0xA9130000u, 46u}, // tik -> Latn
+ {0xB1130000u, 46u}, // tim -> Latn
+ {0xB9130000u, 46u}, // tio -> Latn
+ {0xD5130000u, 46u}, // tiv -> Latn
+ {0x746B0000u, 46u}, // tk -> Latn
+ {0xAD530000u, 46u}, // tkl -> Latn
+ {0xC5530000u, 46u}, // tkr -> Latn
+ {0xCD530000u, 18u}, // tkt -> Deva
+ {0x746C0000u, 46u}, // tl -> Latn
+ {0x95730000u, 46u}, // tlf -> Latn
+ {0xDD730000u, 46u}, // tlx -> Latn
+ {0xE1730000u, 46u}, // tly -> Latn
+ {0x9D930000u, 46u}, // tmh -> Latn
+ {0xE1930000u, 46u}, // tmy -> Latn
+ {0x746E0000u, 46u}, // tn -> Latn
+ {0x9DB30000u, 46u}, // tnh -> Latn
+ {0x746F0000u, 46u}, // to -> Latn
+ {0x95D30000u, 46u}, // tof -> Latn
+ {0x99D30000u, 46u}, // tog -> Latn
+ {0xC1D30000u, 46u}, // toq -> Latn
+ {0xA1F30000u, 46u}, // tpi -> Latn
+ {0xB1F30000u, 46u}, // tpm -> Latn
+ {0xE5F30000u, 46u}, // tpz -> Latn
+ {0xBA130000u, 46u}, // tqo -> Latn
+ {0x74720000u, 46u}, // tr -> Latn
+ {0xD2330000u, 46u}, // tru -> Latn
+ {0xD6330000u, 46u}, // trv -> Latn
{0xDA330000u, 1u}, // trw -> Arab
- {0x74730000u, 44u}, // ts -> Latn
- {0x8E530000u, 24u}, // tsd -> Grek
- {0x96530000u, 17u}, // tsf -> Deva
- {0x9A530000u, 44u}, // tsg -> Latn
- {0xA6530000u, 88u}, // tsj -> Tibt
- {0xDA530000u, 44u}, // tsw -> Latn
- {0x74740000u, 16u}, // tt -> Cyrl
- {0x8E730000u, 44u}, // ttd -> Latn
- {0x92730000u, 44u}, // tte -> Latn
- {0xA6730000u, 44u}, // ttj -> Latn
- {0xC6730000u, 44u}, // ttr -> Latn
- {0xCA730000u, 87u}, // tts -> Thai
- {0xCE730000u, 44u}, // ttt -> Latn
- {0x9E930000u, 44u}, // tuh -> Latn
- {0xAE930000u, 44u}, // tul -> Latn
- {0xB2930000u, 44u}, // tum -> Latn
- {0xC2930000u, 44u}, // tuq -> Latn
- {0x8EB30000u, 44u}, // tvd -> Latn
- {0xAEB30000u, 44u}, // tvl -> Latn
- {0xD2B30000u, 44u}, // tvu -> Latn
- {0x9ED30000u, 44u}, // twh -> Latn
- {0xC2D30000u, 44u}, // twq -> Latn
- {0x9AF30000u, 82u}, // txg -> Tang
- {0x74790000u, 44u}, // ty -> Latn
- {0x83130000u, 44u}, // tya -> Latn
- {0xD7130000u, 16u}, // tyv -> Cyrl
- {0xB3330000u, 44u}, // tzm -> Latn
- {0xD0340000u, 44u}, // ubu -> Latn
- {0xB0740000u, 16u}, // udm -> Cyrl
+ {0x74730000u, 46u}, // ts -> Latn
+ {0x8E530000u, 25u}, // tsd -> Grek
+ {0x96530000u, 18u}, // tsf -> Deva
+ {0x9A530000u, 46u}, // tsg -> Latn
+ {0xA6530000u, 90u}, // tsj -> Tibt
+ {0xDA530000u, 46u}, // tsw -> Latn
+ {0x74740000u, 17u}, // tt -> Cyrl
+ {0x8E730000u, 46u}, // ttd -> Latn
+ {0x92730000u, 46u}, // tte -> Latn
+ {0xA6730000u, 46u}, // ttj -> Latn
+ {0xC6730000u, 46u}, // ttr -> Latn
+ {0xCA730000u, 89u}, // tts -> Thai
+ {0xCE730000u, 46u}, // ttt -> Latn
+ {0x9E930000u, 46u}, // tuh -> Latn
+ {0xAE930000u, 46u}, // tul -> Latn
+ {0xB2930000u, 46u}, // tum -> Latn
+ {0xC2930000u, 46u}, // tuq -> Latn
+ {0x8EB30000u, 46u}, // tvd -> Latn
+ {0xAEB30000u, 46u}, // tvl -> Latn
+ {0xD2B30000u, 46u}, // tvu -> Latn
+ {0x9ED30000u, 46u}, // twh -> Latn
+ {0xC2D30000u, 46u}, // twq -> Latn
+ {0x9AF30000u, 84u}, // txg -> Tang
+ {0x74790000u, 46u}, // ty -> Latn
+ {0x83130000u, 46u}, // tya -> Latn
+ {0xD7130000u, 17u}, // tyv -> Cyrl
+ {0xB3330000u, 46u}, // tzm -> Latn
+ {0xD0340000u, 46u}, // ubu -> Latn
+ {0xB0740000u, 17u}, // udm -> Cyrl
{0x75670000u, 1u}, // ug -> Arab
- {0x75674B5Au, 16u}, // ug-KZ -> Cyrl
- {0x75674D4Eu, 16u}, // ug-MN -> Cyrl
- {0x80D40000u, 89u}, // uga -> Ugar
- {0x756B0000u, 16u}, // uk -> Cyrl
- {0xA1740000u, 44u}, // uli -> Latn
- {0x85940000u, 44u}, // umb -> Latn
+ {0x75674B5Au, 17u}, // ug-KZ -> Cyrl
+ {0x75674D4Eu, 17u}, // ug-MN -> Cyrl
+ {0x80D40000u, 91u}, // uga -> Ugar
+ {0x756B0000u, 17u}, // uk -> Cyrl
+ {0xA1740000u, 46u}, // uli -> Latn
+ {0x85940000u, 46u}, // umb -> Latn
{0xC5B40000u, 7u}, // unr -> Beng
- {0xC5B44E50u, 17u}, // unr-NP -> Deva
+ {0xC5B44E50u, 18u}, // unr-NP -> Deva
{0xDDB40000u, 7u}, // unx -> Beng
- {0xA9D40000u, 44u}, // uok -> Latn
+ {0xA9D40000u, 46u}, // uok -> Latn
{0x75720000u, 1u}, // ur -> Arab
- {0xA2340000u, 44u}, // uri -> Latn
- {0xCE340000u, 44u}, // urt -> Latn
- {0xDA340000u, 44u}, // urw -> Latn
- {0x82540000u, 44u}, // usa -> Latn
- {0xC6740000u, 44u}, // utr -> Latn
- {0x9EB40000u, 44u}, // uvh -> Latn
- {0xAEB40000u, 44u}, // uvl -> Latn
- {0x757A0000u, 44u}, // uz -> Latn
+ {0xA2340000u, 46u}, // uri -> Latn
+ {0xCE340000u, 46u}, // urt -> Latn
+ {0xDA340000u, 46u}, // urw -> Latn
+ {0x82540000u, 46u}, // usa -> Latn
+ {0xC6740000u, 46u}, // utr -> Latn
+ {0x9EB40000u, 46u}, // uvh -> Latn
+ {0xAEB40000u, 46u}, // uvl -> Latn
+ {0x757A0000u, 46u}, // uz -> Latn
{0x757A4146u, 1u}, // uz-AF -> Arab
- {0x757A434Eu, 16u}, // uz-CN -> Cyrl
- {0x98150000u, 44u}, // vag -> Latn
- {0xA0150000u, 90u}, // vai -> Vaii
- {0xB4150000u, 44u}, // van -> Latn
- {0x76650000u, 44u}, // ve -> Latn
- {0x88950000u, 44u}, // vec -> Latn
- {0xBC950000u, 44u}, // vep -> Latn
- {0x76690000u, 44u}, // vi -> Latn
- {0x89150000u, 44u}, // vic -> Latn
- {0xD5150000u, 44u}, // viv -> Latn
- {0xC9750000u, 44u}, // vls -> Latn
- {0x95950000u, 44u}, // vmf -> Latn
- {0xD9950000u, 44u}, // vmw -> Latn
- {0x766F0000u, 44u}, // vo -> Latn
- {0xCDD50000u, 44u}, // vot -> Latn
- {0xBA350000u, 44u}, // vro -> Latn
- {0xB6950000u, 44u}, // vun -> Latn
- {0xCE950000u, 44u}, // vut -> Latn
- {0x77610000u, 44u}, // wa -> Latn
- {0x90160000u, 44u}, // wae -> Latn
- {0xA4160000u, 44u}, // waj -> Latn
- {0xAC160000u, 19u}, // wal -> Ethi
- {0xB4160000u, 44u}, // wan -> Latn
- {0xC4160000u, 44u}, // war -> Latn
- {0xBC360000u, 44u}, // wbp -> Latn
- {0xC0360000u, 84u}, // wbq -> Telu
- {0xC4360000u, 17u}, // wbr -> Deva
- {0xA0560000u, 44u}, // wci -> Latn
- {0xC4960000u, 44u}, // wer -> Latn
- {0xA0D60000u, 44u}, // wgi -> Latn
- {0x98F60000u, 44u}, // whg -> Latn
- {0x85160000u, 44u}, // wib -> Latn
- {0xD1160000u, 44u}, // wiu -> Latn
- {0xD5160000u, 44u}, // wiv -> Latn
- {0x81360000u, 44u}, // wja -> Latn
- {0xA1360000u, 44u}, // wji -> Latn
- {0xC9760000u, 44u}, // wls -> Latn
- {0xB9960000u, 44u}, // wmo -> Latn
- {0x89B60000u, 44u}, // wnc -> Latn
+ {0x757A434Eu, 17u}, // uz-CN -> Cyrl
+ {0x98150000u, 46u}, // vag -> Latn
+ {0xA0150000u, 92u}, // vai -> Vaii
+ {0xB4150000u, 46u}, // van -> Latn
+ {0x76650000u, 46u}, // ve -> Latn
+ {0x88950000u, 46u}, // vec -> Latn
+ {0xBC950000u, 46u}, // vep -> Latn
+ {0x76690000u, 46u}, // vi -> Latn
+ {0x89150000u, 46u}, // vic -> Latn
+ {0xD5150000u, 46u}, // viv -> Latn
+ {0xC9750000u, 46u}, // vls -> Latn
+ {0x95950000u, 46u}, // vmf -> Latn
+ {0xD9950000u, 46u}, // vmw -> Latn
+ {0x766F0000u, 46u}, // vo -> Latn
+ {0xCDD50000u, 46u}, // vot -> Latn
+ {0xBA350000u, 46u}, // vro -> Latn
+ {0xB6950000u, 46u}, // vun -> Latn
+ {0xCE950000u, 46u}, // vut -> Latn
+ {0x77610000u, 46u}, // wa -> Latn
+ {0x90160000u, 46u}, // wae -> Latn
+ {0xA4160000u, 46u}, // waj -> Latn
+ {0xAC160000u, 20u}, // wal -> Ethi
+ {0xB4160000u, 46u}, // wan -> Latn
+ {0xC4160000u, 46u}, // war -> Latn
+ {0xBC360000u, 46u}, // wbp -> Latn
+ {0xC0360000u, 86u}, // wbq -> Telu
+ {0xC4360000u, 18u}, // wbr -> Deva
+ {0xA0560000u, 46u}, // wci -> Latn
+ {0xC4960000u, 46u}, // wer -> Latn
+ {0xA0D60000u, 46u}, // wgi -> Latn
+ {0x98F60000u, 46u}, // whg -> Latn
+ {0x85160000u, 46u}, // wib -> Latn
+ {0xD1160000u, 46u}, // wiu -> Latn
+ {0xD5160000u, 46u}, // wiv -> Latn
+ {0x81360000u, 46u}, // wja -> Latn
+ {0xA1360000u, 46u}, // wji -> Latn
+ {0xC9760000u, 46u}, // wls -> Latn
+ {0xB9960000u, 46u}, // wmo -> Latn
+ {0x89B60000u, 46u}, // wnc -> Latn
{0xA1B60000u, 1u}, // wni -> Arab
- {0xD1B60000u, 44u}, // wnu -> Latn
- {0x776F0000u, 44u}, // wo -> Latn
- {0x85D60000u, 44u}, // wob -> Latn
- {0xC9D60000u, 44u}, // wos -> Latn
- {0xCA360000u, 44u}, // wrs -> Latn
- {0x9A560000u, 21u}, // wsg -> Gong
- {0xAA560000u, 44u}, // wsk -> Latn
- {0xB2760000u, 17u}, // wtm -> Deva
- {0xD2960000u, 27u}, // wuu -> Hans
- {0xD6960000u, 44u}, // wuv -> Latn
- {0x82D60000u, 44u}, // wwa -> Latn
- {0xD4170000u, 44u}, // xav -> Latn
- {0xA0370000u, 44u}, // xbi -> Latn
+ {0xD1B60000u, 46u}, // wnu -> Latn
+ {0x776F0000u, 46u}, // wo -> Latn
+ {0x85D60000u, 46u}, // wob -> Latn
+ {0xC9D60000u, 46u}, // wos -> Latn
+ {0xCA360000u, 46u}, // wrs -> Latn
+ {0x9A560000u, 22u}, // wsg -> Gong
+ {0xAA560000u, 46u}, // wsk -> Latn
+ {0xB2760000u, 18u}, // wtm -> Deva
+ {0xD2960000u, 28u}, // wuu -> Hans
+ {0xD6960000u, 46u}, // wuv -> Latn
+ {0x82D60000u, 46u}, // wwa -> Latn
+ {0xD4170000u, 46u}, // xav -> Latn
+ {0xA0370000u, 46u}, // xbi -> Latn
+ {0xB8570000u, 14u}, // xco -> Chrs
{0xC4570000u, 11u}, // xcr -> Cari
- {0xC8970000u, 44u}, // xes -> Latn
- {0x78680000u, 44u}, // xh -> Latn
- {0x81770000u, 44u}, // xla -> Latn
- {0x89770000u, 48u}, // xlc -> Lyci
- {0x8D770000u, 49u}, // xld -> Lydi
- {0x95970000u, 20u}, // xmf -> Geor
- {0xB5970000u, 51u}, // xmn -> Mani
- {0xC5970000u, 52u}, // xmr -> Merc
- {0x81B70000u, 57u}, // xna -> Narb
- {0xC5B70000u, 17u}, // xnr -> Deva
- {0x99D70000u, 44u}, // xog -> Latn
- {0xB5D70000u, 44u}, // xon -> Latn
- {0xC5F70000u, 68u}, // xpr -> Prti
- {0x86370000u, 44u}, // xrb -> Latn
- {0x82570000u, 71u}, // xsa -> Sarb
- {0xA2570000u, 44u}, // xsi -> Latn
- {0xB2570000u, 44u}, // xsm -> Latn
- {0xC6570000u, 17u}, // xsr -> Deva
- {0x92D70000u, 44u}, // xwe -> Latn
- {0xB0180000u, 44u}, // yam -> Latn
- {0xB8180000u, 44u}, // yao -> Latn
- {0xBC180000u, 44u}, // yap -> Latn
- {0xC8180000u, 44u}, // yas -> Latn
- {0xCC180000u, 44u}, // yat -> Latn
- {0xD4180000u, 44u}, // yav -> Latn
- {0xE0180000u, 44u}, // yay -> Latn
- {0xE4180000u, 44u}, // yaz -> Latn
- {0x80380000u, 44u}, // yba -> Latn
- {0x84380000u, 44u}, // ybb -> Latn
- {0xE0380000u, 44u}, // yby -> Latn
- {0xC4980000u, 44u}, // yer -> Latn
- {0xC4D80000u, 44u}, // ygr -> Latn
- {0xD8D80000u, 44u}, // ygw -> Latn
- {0x79690000u, 30u}, // yi -> Hebr
- {0xB9580000u, 44u}, // yko -> Latn
- {0x91780000u, 44u}, // yle -> Latn
- {0x99780000u, 44u}, // ylg -> Latn
- {0xAD780000u, 44u}, // yll -> Latn
- {0xAD980000u, 44u}, // yml -> Latn
- {0x796F0000u, 44u}, // yo -> Latn
- {0xB5D80000u, 44u}, // yon -> Latn
- {0x86380000u, 44u}, // yrb -> Latn
- {0x92380000u, 44u}, // yre -> Latn
- {0xAE380000u, 44u}, // yrl -> Latn
- {0xCA580000u, 44u}, // yss -> Latn
- {0x82980000u, 44u}, // yua -> Latn
- {0x92980000u, 28u}, // yue -> Hant
- {0x9298434Eu, 27u}, // yue-CN -> Hans
- {0xA6980000u, 44u}, // yuj -> Latn
- {0xCE980000u, 44u}, // yut -> Latn
- {0xDA980000u, 44u}, // yuw -> Latn
- {0x7A610000u, 44u}, // za -> Latn
- {0x98190000u, 44u}, // zag -> Latn
+ {0xC8970000u, 46u}, // xes -> Latn
+ {0x78680000u, 46u}, // xh -> Latn
+ {0x81770000u, 46u}, // xla -> Latn
+ {0x89770000u, 50u}, // xlc -> Lyci
+ {0x8D770000u, 51u}, // xld -> Lydi
+ {0x95970000u, 21u}, // xmf -> Geor
+ {0xB5970000u, 53u}, // xmn -> Mani
+ {0xC5970000u, 54u}, // xmr -> Merc
+ {0x81B70000u, 59u}, // xna -> Narb
+ {0xC5B70000u, 18u}, // xnr -> Deva
+ {0x99D70000u, 46u}, // xog -> Latn
+ {0xB5D70000u, 46u}, // xon -> Latn
+ {0xC5F70000u, 70u}, // xpr -> Prti
+ {0x86370000u, 46u}, // xrb -> Latn
+ {0x82570000u, 73u}, // xsa -> Sarb
+ {0xA2570000u, 46u}, // xsi -> Latn
+ {0xB2570000u, 46u}, // xsm -> Latn
+ {0xC6570000u, 18u}, // xsr -> Deva
+ {0x92D70000u, 46u}, // xwe -> Latn
+ {0xB0180000u, 46u}, // yam -> Latn
+ {0xB8180000u, 46u}, // yao -> Latn
+ {0xBC180000u, 46u}, // yap -> Latn
+ {0xC8180000u, 46u}, // yas -> Latn
+ {0xCC180000u, 46u}, // yat -> Latn
+ {0xD4180000u, 46u}, // yav -> Latn
+ {0xE0180000u, 46u}, // yay -> Latn
+ {0xE4180000u, 46u}, // yaz -> Latn
+ {0x80380000u, 46u}, // yba -> Latn
+ {0x84380000u, 46u}, // ybb -> Latn
+ {0xE0380000u, 46u}, // yby -> Latn
+ {0xC4980000u, 46u}, // yer -> Latn
+ {0xC4D80000u, 46u}, // ygr -> Latn
+ {0xD8D80000u, 46u}, // ygw -> Latn
+ {0x79690000u, 31u}, // yi -> Hebr
+ {0xB9580000u, 46u}, // yko -> Latn
+ {0x91780000u, 46u}, // yle -> Latn
+ {0x99780000u, 46u}, // ylg -> Latn
+ {0xAD780000u, 46u}, // yll -> Latn
+ {0xAD980000u, 46u}, // yml -> Latn
+ {0x796F0000u, 46u}, // yo -> Latn
+ {0xB5D80000u, 46u}, // yon -> Latn
+ {0x86380000u, 46u}, // yrb -> Latn
+ {0x92380000u, 46u}, // yre -> Latn
+ {0xAE380000u, 46u}, // yrl -> Latn
+ {0xCA580000u, 46u}, // yss -> Latn
+ {0x82980000u, 46u}, // yua -> Latn
+ {0x92980000u, 29u}, // yue -> Hant
+ {0x9298434Eu, 28u}, // yue-CN -> Hans
+ {0xA6980000u, 46u}, // yuj -> Latn
+ {0xCE980000u, 46u}, // yut -> Latn
+ {0xDA980000u, 46u}, // yuw -> Latn
+ {0x7A610000u, 46u}, // za -> Latn
+ {0x98190000u, 46u}, // zag -> Latn
{0xA4790000u, 1u}, // zdj -> Arab
- {0x80990000u, 44u}, // zea -> Latn
- {0x9CD90000u, 85u}, // zgh -> Tfng
- {0x7A680000u, 27u}, // zh -> Hans
- {0x7A684155u, 28u}, // zh-AU -> Hant
- {0x7A68424Eu, 28u}, // zh-BN -> Hant
- {0x7A684742u, 28u}, // zh-GB -> Hant
- {0x7A684746u, 28u}, // zh-GF -> Hant
- {0x7A68484Bu, 28u}, // zh-HK -> Hant
- {0x7A684944u, 28u}, // zh-ID -> Hant
- {0x7A684D4Fu, 28u}, // zh-MO -> Hant
- {0x7A684D59u, 28u}, // zh-MY -> Hant
- {0x7A685041u, 28u}, // zh-PA -> Hant
- {0x7A685046u, 28u}, // zh-PF -> Hant
- {0x7A685048u, 28u}, // zh-PH -> Hant
- {0x7A685352u, 28u}, // zh-SR -> Hant
- {0x7A685448u, 28u}, // zh-TH -> Hant
- {0x7A685457u, 28u}, // zh-TW -> Hant
- {0x7A685553u, 28u}, // zh-US -> Hant
- {0x7A68564Eu, 28u}, // zh-VN -> Hant
- {0xDCF90000u, 59u}, // zhx -> Nshu
- {0x81190000u, 44u}, // zia -> Latn
- {0xB1790000u, 44u}, // zlm -> Latn
- {0xA1990000u, 44u}, // zmi -> Latn
- {0x91B90000u, 44u}, // zne -> Latn
- {0x7A750000u, 44u}, // zu -> Latn
- {0x83390000u, 44u}, // zza -> Latn
+ {0x80990000u, 46u}, // zea -> Latn
+ {0x9CD90000u, 87u}, // zgh -> Tfng
+ {0x7A680000u, 28u}, // zh -> Hans
+ {0x7A684155u, 29u}, // zh-AU -> Hant
+ {0x7A68424Eu, 29u}, // zh-BN -> Hant
+ {0x7A684742u, 29u}, // zh-GB -> Hant
+ {0x7A684746u, 29u}, // zh-GF -> Hant
+ {0x7A68484Bu, 29u}, // zh-HK -> Hant
+ {0x7A684944u, 29u}, // zh-ID -> Hant
+ {0x7A684D4Fu, 29u}, // zh-MO -> Hant
+ {0x7A684D59u, 29u}, // zh-MY -> Hant
+ {0x7A685041u, 29u}, // zh-PA -> Hant
+ {0x7A685046u, 29u}, // zh-PF -> Hant
+ {0x7A685048u, 29u}, // zh-PH -> Hant
+ {0x7A685352u, 29u}, // zh-SR -> Hant
+ {0x7A685448u, 29u}, // zh-TH -> Hant
+ {0x7A685457u, 29u}, // zh-TW -> Hant
+ {0x7A685553u, 29u}, // zh-US -> Hant
+ {0x7A68564Eu, 29u}, // zh-VN -> Hant
+ {0xDCF90000u, 61u}, // zhx -> Nshu
+ {0x81190000u, 46u}, // zia -> Latn
+ {0xCD590000u, 41u}, // zkt -> Kits
+ {0xB1790000u, 46u}, // zlm -> Latn
+ {0xA1990000u, 46u}, // zmi -> Latn
+ {0x91B90000u, 46u}, // zne -> Latn
+ {0x7A750000u, 46u}, // zu -> Latn
+ {0x83390000u, 46u}, // zza -> Latn
});
std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
@@ -1829,6 +1833,7 @@
0xC66A4D594C61746ELLU, // ktr_Latn_MY
0x6B75495141726162LLU, // ku_Arab_IQ
0x6B7554524C61746ELLU, // ku_Latn_TR
+ 0x6B75474559657A69LLU, // ku_Yezi_GE
0xB28A52554379726CLLU, // kum_Cyrl_RU
0x6B7652554379726CLLU, // kv_Cyrl_RU
0xC6AA49444C61746ELLU, // kvr_Latn_ID
@@ -2199,6 +2204,7 @@
0xB276494E44657661LLU, // wtm_Deva_IN
0xD296434E48616E73LLU, // wuu_Hans_CN
0xD41742524C61746ELLU, // xav_Latn_BR
+ 0xB857555A43687273LLU, // xco_Chrs_UZ
0xC457545243617269LLU, // xcr_Cari_TR
0x78685A414C61746ELLU, // xh_Latn_ZA
0x897754524C796369LLU, // xlc_Lyci_TR
@@ -2231,6 +2237,7 @@
0x7A68434E48616E73LLU, // zh_Hans_CN
0x7A68545748616E74LLU, // zh_Hant_TW
0xDCF9434E4E736875LLU, // zhx_Nshu_CN
+ 0xCD59434E4B697473LLU, // zkt_Kits_CN
0xB17954474C61746ELLU, // zlm_Latn_TG
0xA1994D594C61746ELLU, // zmi_Latn_MY
0x7A755A414C61746ELLU, // zu_Latn_ZA
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 44b481d..9ae9b4a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -95,6 +95,15 @@
mCallbacks.remove(callback);
}
+ /**
+ * Creates a LocalMediaManager with references to given managers.
+ *
+ * It will obtain a {@link LocalBluetoothManager} by calling
+ * {@link LocalBluetoothManager#getInstance} and create an {@link InfoMediaManager} passing
+ * that bluetooth manager.
+ *
+ * It will use {@link BluetoothAdapter#getDefaultAdapter()] for setting the bluetooth adapter.
+ */
public LocalMediaManager(Context context, String packageName, Notification notification) {
mContext = context;
mPackageName = packageName;
@@ -110,12 +119,18 @@
new InfoMediaManager(context, packageName, notification, mLocalBluetoothManager);
}
+ /**
+ * Creates a LocalMediaManager with references to given managers.
+ *
+ * It will use {@link BluetoothAdapter#getDefaultAdapter()] for setting the bluetooth adapter.
+ */
public LocalMediaManager(Context context, LocalBluetoothManager localBluetoothManager,
InfoMediaManager infoMediaManager, String packageName) {
mContext = context;
mLocalBluetoothManager = localBluetoothManager;
mInfoMediaManager = infoMediaManager;
mPackageName = packageName;
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
/**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index f825ec5..559187d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -113,7 +113,6 @@
TEST_PACKAGE_NAME);
mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
mInfoMediaManager, "com.test.packagename");
- mLocalMediaManager.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index b63ba6f..7ee162e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -89,6 +89,9 @@
private static final int SPRING_AFTER_FLING_STIFFNESS = 750;
private static final float SPRING_AFTER_FLING_DAMPING_RATIO = 0.85f;
+ /** Sentinel value for unset position value. */
+ private static final float UNSET = -Float.MIN_VALUE;
+
/**
* Minimum fling velocity required to trigger moving the stack from one side of the screen to
* the other.
@@ -133,7 +136,7 @@
* The Y position of the stack before the IME became visible, or {@link Float#MIN_VALUE} if the
* IME is not visible or the user moved the stack since the IME became visible.
*/
- private float mPreImeY = Float.MIN_VALUE;
+ private float mPreImeY = UNSET;
/**
* Animations on the stack position itself, which would have been started in
@@ -263,7 +266,7 @@
// If we manually move the bubbles with the IME open, clear the return point since we don't
// want the stack to snap away from the new position.
- mPreImeY = Float.MIN_VALUE;
+ mPreImeY = UNSET;
moveFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_X, x);
moveFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_Y, y);
@@ -512,26 +515,27 @@
* Animates the stack either away from the newly visible IME, or back to its original position
* due to the IME going away.
*
- * @return The destination Y value of the stack due to the IME movement.
+ * @return The destination Y value of the stack due to the IME movement (or the current position
+ * of the stack if it's not moving).
*/
public float animateForImeVisibility(boolean imeVisible) {
final float maxBubbleY = getAllowableStackPositionRegion().bottom;
- float destinationY = Float.MIN_VALUE;
+ float destinationY = UNSET;
if (imeVisible) {
// Stack is lower than it should be and overlaps the now-visible IME.
- if (mStackPosition.y > maxBubbleY && mPreImeY == Float.MIN_VALUE) {
+ if (mStackPosition.y > maxBubbleY && mPreImeY == UNSET) {
mPreImeY = mStackPosition.y;
destinationY = maxBubbleY;
}
} else {
- if (mPreImeY > Float.MIN_VALUE) {
+ if (mPreImeY != UNSET) {
destinationY = mPreImeY;
- mPreImeY = Float.MIN_VALUE;
+ mPreImeY = UNSET;
}
}
- if (destinationY > Float.MIN_VALUE) {
+ if (destinationY != UNSET) {
springFirstBubbleWithStackFollowing(
DynamicAnimation.TRANSLATION_Y,
getSpringForce(DynamicAnimation.TRANSLATION_Y, /* view */ null)
@@ -542,7 +546,7 @@
notifyFloatingCoordinatorStackAnimatingTo(mStackPosition.x, destinationY);
}
- return destinationY;
+ return destinationY != UNSET ? destinationY : mStackPosition.y;
}
/**
@@ -595,7 +599,7 @@
mLayout.getHeight()
- mBubbleSize
- mBubblePaddingTop
- - (mImeHeight > Float.MIN_VALUE ? mImeHeight + mBubblePaddingTop : 0f)
+ - (mImeHeight != UNSET ? mImeHeight + mBubblePaddingTop : 0f)
- Math.max(
insets.getStableInsetBottom(),
insets.getDisplayCutout() != null
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 7c770f4..1780fb1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -347,6 +347,7 @@
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
// TODO use taskId and visibleInsets
+ clearScreenshot("new screenshot requested");
takeScreenshot(screenshot, finisher, screenshotScreenBounds);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4af31b0..4504704 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -23,6 +23,7 @@
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkStack.checkNetworkStackPermission;
@@ -1793,6 +1794,24 @@
}
}
+ // TODO: It is copied from ConnectivityService, consider refactor these check permission
+ // functions to a proper util.
+ private boolean checkAnyPermissionOf(String... permissions) {
+ for (String permission : permissions) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void enforceAnyPermissionOf(String... permissions) {
+ if (!checkAnyPermissionOf(permissions)) {
+ throw new SecurityException("Requires one of the following permissions: "
+ + String.join(", ", permissions) + ".");
+ }
+ }
+
/**
* Registers a custom provider of {@link android.net.NetworkStats} to combine the network
* statistics that cannot be seen by the kernel to system. To unregister, invoke the
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index d12e03d..c37ea8b 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -301,6 +301,14 @@
public abstract boolean destroyDeSnapshots(int rollbackId);
/**
+ * Deletes snapshots of the credential encrypted apex data directories for the specified user,
+ * where the rollback id is not included in {@code retainRollbackIds}.
+ *
+ * @return boolean true if the delete was successful
+ */
+ public abstract boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds);
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -745,6 +753,17 @@
}
}
+ @Override
+ public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
+ try {
+ mApexService.destroyCeSnapshotsNotSpecified(userId, retainRollbackIds);
+ return true;
+ } catch (Exception e) {
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
+ }
+ }
+
/**
* Dump information about the packages contained in a particular cache
* @param packagesCache the cache to print information about.
@@ -963,6 +982,11 @@
}
@Override
+ public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
+ return true;
+ }
+
+ @Override
void dump(PrintWriter pw, String packageName) {
// No-op
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 42fada1..b50c22e 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -63,6 +63,7 @@
import com.android.server.PackageWatchdog;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
+import com.android.server.pm.ApexManager;
import com.android.server.pm.Installer;
import java.io.File;
@@ -485,6 +486,8 @@
}
latch.countDown();
+
+ destroyCeSnapshotsForExpiredRollbacks(userId);
});
try {
@@ -495,6 +498,15 @@
}
@WorkerThread
+ private void destroyCeSnapshotsForExpiredRollbacks(int userId) {
+ int[] rollbackIds = new int[mRollbacks.size()];
+ for (int i = 0; i < rollbackIds.length; i++) {
+ rollbackIds[i] = mRollbacks.get(i).info.getRollbackId();
+ }
+ ApexManager.getInstance().destroyCeSnapshotsNotSpecified(userId, rollbackIds);
+ }
+
+ @WorkerThread
private void updateRollbackLifetimeDurationInMillis() {
mRollbackLifetimeDurationInMillis = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f5d2c6a..fc9044a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -393,6 +393,7 @@
private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
+ private static final long MANAGED_PROFILE_MAXIMUM_TIME_OFF_THRESHOLD = 3 * MS_PER_DAY;
private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION =
"com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
@@ -15849,6 +15850,12 @@
// DO shouldn't be able to use this method.
enforceProfileOwnerOfOrganizationOwnedDevice(admin);
enforceHandlesCheckPolicyComplianceIntent(userId, admin.info.getPackageName());
+ Preconditions.checkArgument(timeoutMillis >= 0, "Timeout must be non-negative.");
+ // Ensure the timeout is long enough to avoid having bad user experience.
+ if (timeoutMillis > 0 && timeoutMillis < MANAGED_PROFILE_MAXIMUM_TIME_OFF_THRESHOLD
+ && !isAdminTestOnlyLocked(who, userId)) {
+ timeoutMillis = MANAGED_PROFILE_MAXIMUM_TIME_OFF_THRESHOLD;
+ }
if (admin.mProfileMaximumTimeOffMillis == timeoutMillis) {
return;
}