diff options
4 files changed, 409 insertions, 249 deletions
diff --git a/core/java/android/view/textclassifier/SmartSelection.java b/core/java/android/view/textclassifier/SmartSelection.java deleted file mode 100644 index 69c38ee4db4f..000000000000 --- a/core/java/android/view/textclassifier/SmartSelection.java +++ /dev/null @@ -1,194 +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.content.res.AssetFileDescriptor; - -/** - * Java wrapper for SmartSelection native library interface. - * This library is used for detecting entities in text. - */ -final class SmartSelection { - - static { - System.loadLibrary("textclassifier"); - } - - /** Hints the classifier that this may be a url. */ - static final int HINT_FLAG_URL = 0x01; - /** Hints the classifier that this may be an email. */ - static final int HINT_FLAG_EMAIL = 0x02; - - private final long mCtx; - - /** - * Creates a new instance of SmartSelect predictor, using the provided model image, - * given as a file descriptor. - */ - SmartSelection(int fd) { - mCtx = nativeNew(fd); - } - - /** - * Creates a new instance of SmartSelect predictor, using the provided model image, given as a - * file path. - */ - SmartSelection(String path) { - mCtx = nativeNewFromPath(path); - } - - /** - * Creates a new instance of SmartSelect predictor, using the provided model image, given as an - * AssetFileDescriptor. - */ - SmartSelection(AssetFileDescriptor afd) { - mCtx = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength()); - if (mCtx == 0L) { - throw new IllegalArgumentException( - "Couldn't initialize TC from given AssetFileDescriptor"); - } - } - - /** - * Given a string context and current selection, computes the SmartSelection suggestion. - * - * The begin and end are character indices into the context UTF8 string. selectionBegin is the - * character index where the selection begins, and selectionEnd is the index of one character - * past the selection span. - * - * The return value is an array of two ints: suggested selection beginning and end, with the - * same semantics as the input selectionBeginning and selectionEnd. - */ - public int[] suggest(String context, int selectionBegin, int selectionEnd) { - return nativeSuggest(mCtx, context, selectionBegin, selectionEnd); - } - - /** - * Given a string context and current selection, classifies the type of the selected text. - * - * The begin and end params are character indices in the context string. - * - * Returns an array of ClassificationResult objects with the probability - * scores for different collections. - */ - public ClassificationResult[] classifyText( - String context, int selectionBegin, int selectionEnd, int hintFlags) { - return nativeClassifyText(mCtx, context, selectionBegin, selectionEnd, hintFlags); - } - - /** - * Annotates given input text. Every word of the input is a part of some annotation. - * The annotations are sorted by their position in the context string. - * The annotations do not overlap. - */ - public AnnotatedSpan[] annotate(String text) { - return nativeAnnotate(mCtx, text); - } - - /** - * Frees up the allocated memory. - */ - public void close() { - nativeClose(mCtx); - } - - /** - * Returns a comma separated list of locales supported by the model as BCP 47 tags. - */ - public static String getLanguages(int fd) { - return nativeGetLanguage(fd); - } - - /** - * Returns the version of the model. - */ - public static int getVersion(int fd) { - return nativeGetVersion(fd); - } - - private static native long nativeNew(int fd); - - private static native long nativeNewFromPath(String path); - - private static native long nativeNewFromAssetFileDescriptor(AssetFileDescriptor afd, - long offset, long size); - - private static native int[] nativeSuggest( - long context, String text, int selectionBegin, int selectionEnd); - - private static native ClassificationResult[] nativeClassifyText( - long context, String text, int selectionBegin, int selectionEnd, int hintFlags); - - private static native AnnotatedSpan[] nativeAnnotate(long context, String text); - - private static native void nativeClose(long context); - - private static native String nativeGetLanguage(int fd); - - private static native int nativeGetVersion(int fd); - - /** Classification result for classifyText method. */ - static final class ClassificationResult { - final String mCollection; - /** float range: 0 - 1 */ - final float mScore; - @Nullable final DatetimeParseResult mDatetime; - - ClassificationResult(String collection, float score) { - mCollection = collection; - mScore = score; - mDatetime = null; - } - - ClassificationResult(String collection, float score, DatetimeParseResult datetime) { - mCollection = collection; - mScore = score; - mDatetime = datetime; - } - } - - /** Parsed date information for the classification result. */ - static final class DatetimeParseResult { - long mMsSinceEpoch; - } - - /** Represents a result of Annotate call. */ - public static final class AnnotatedSpan { - final int mStartIndex; - final int mEndIndex; - final ClassificationResult[] mClassification; - - AnnotatedSpan(int startIndex, int endIndex, ClassificationResult[] classification) { - mStartIndex = startIndex; - mEndIndex = endIndex; - mClassification = classification; - } - - public int getStartIndex() { - return mStartIndex; - } - - public int getEndIndex() { - return mEndIndex; - } - - public ClassificationResult[] getClassification() { - return mClassification; - } - } -} diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 20467acb493d..8f6f600cfc72 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -35,8 +35,6 @@ import android.provider.Browser; import android.provider.CalendarContract; import android.provider.ContactsContract; import android.provider.Settings; -import android.text.util.Linkify; -import android.util.Patterns; import android.view.textclassifier.logging.DefaultLogger; import android.view.textclassifier.logging.Logger; @@ -102,7 +100,7 @@ public final class TextClassifierImpl implements TextClassifier { @GuardedBy("mLock") // Do not access outside this lock. private ModelFile mModel; @GuardedBy("mLock") // Do not access outside this lock. - private SmartSelection mSmartSelection; + private TextClassifierImplNative mNative; private final Object mLoggerLock = new Object(); @GuardedBy("mLoggerLock") // Do not access outside this lock. @@ -128,8 +126,10 @@ public final class TextClassifierImpl implements TextClassifier { if (text.length() > 0 && rangeLength <= getSettings().getSuggestSelectionMaxRangeLength()) { final LocaleList locales = (options == null) ? null : options.getDefaultLocales(); + final String localesString = concatenateLocales(locales); + final Calendar refTime = Calendar.getInstance(); final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed(); - final SmartSelection smartSelection = getSmartSelection(locales); + final TextClassifierImplNative nativeImpl = getNative(locales); final String string = text.toString(); final int start; final int end; @@ -137,8 +137,9 @@ public final class TextClassifierImpl implements TextClassifier { start = selectionStartIndex; end = selectionEndIndex; } else { - final int[] startEnd = smartSelection.suggest( - string, selectionStartIndex, selectionEndIndex); + final int[] startEnd = nativeImpl.suggestSelection( + string, selectionStartIndex, selectionEndIndex, + new TextClassifierImplNative.SelectionOptions(localesString)); start = startEnd[0]; end = startEnd[1]; } @@ -146,13 +147,16 @@ public final class TextClassifierImpl implements TextClassifier { && start >= 0 && end <= string.length() && start <= selectionStartIndex && end >= selectionEndIndex) { final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end); - final SmartSelection.ClassificationResult[] results = - smartSelection.classifyText( + final TextClassifierImplNative.ClassificationResult[] results = + nativeImpl.classifyText( string, start, end, - getHintFlags(string, start, end)); + new TextClassifierImplNative.ClassificationOptions( + refTime.getTimeInMillis(), + refTime.getTimeZone().getID(), + localesString)); final int size = results.length; for (int i = 0; i < size; i++) { - tsBuilder.setEntityType(results[i].mCollection, results[i].mScore); + tsBuilder.setEntityType(results[i].getCollection(), results[i].getScore()); } return tsBuilder .setSignature( @@ -185,10 +189,17 @@ public final class TextClassifierImpl implements TextClassifier { if (text.length() > 0 && rangeLength <= getSettings().getClassifyTextMaxRangeLength()) { final String string = text.toString(); final LocaleList locales = (options == null) ? null : options.getDefaultLocales(); - final Calendar refTime = (options == null) ? null : options.getReferenceTime(); - final SmartSelection.ClassificationResult[] results = getSmartSelection(locales) - .classifyText(string, startIndex, endIndex, - getHintFlags(string, startIndex, endIndex)); + final String localesString = concatenateLocales(locales); + final Calendar refTime = (options != null && options.getReferenceTime() != null) + ? options.getReferenceTime() : Calendar.getInstance(); + + final TextClassifierImplNative.ClassificationResult[] results = + getNative(locales) + .classifyText(string, startIndex, endIndex, + new TextClassifierImplNative.ClassificationOptions( + refTime.getTimeInMillis(), + refTime.getTimeZone().getID(), + localesString)); if (results.length > 0) { return createClassificationResult( results, string, startIndex, endIndex, refTime); @@ -216,21 +227,31 @@ public final class TextClassifierImpl implements TextClassifier { try { final LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null; + final Calendar refTime = Calendar.getInstance(); final Collection<String> entitiesToIdentify = options != null && options.getEntityConfig() != null ? options.getEntityConfig().resolveEntityListModifications( getEntitiesForHints(options.getEntityConfig().getHints())) : ENTITY_TYPES_ALL; - final SmartSelection smartSelection = getSmartSelection(defaultLocales); - final SmartSelection.AnnotatedSpan[] annotations = smartSelection.annotate(textString); - for (SmartSelection.AnnotatedSpan span : annotations) { - final SmartSelection.ClassificationResult[] results = span.getClassification(); - if (results.length == 0 || !entitiesToIdentify.contains(results[0].mCollection)) { + final TextClassifierImplNative nativeImpl = + getNative(defaultLocales); + final TextClassifierImplNative.AnnotatedSpan[] annotations = + nativeImpl.annotate( + textString, + new TextClassifierImplNative.AnnotationOptions( + refTime.getTimeInMillis(), + refTime.getTimeZone().getID(), + concatenateLocales(defaultLocales))); + for (TextClassifierImplNative.AnnotatedSpan span : annotations) { + final TextClassifierImplNative.ClassificationResult[] results = + span.getClassification(); + if (results.length == 0 + || !entitiesToIdentify.contains(results[0].getCollection())) { continue; } final Map<String, Float> entityScores = new HashMap<>(); for (int i = 0; i < results.length; i++) { - entityScores.put(results[i].mCollection, results[i].mScore); + entityScores.put(results[i].getCollection(), results[i].getScore()); } builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores); } @@ -274,23 +295,24 @@ public final class TextClassifierImpl implements TextClassifier { return mSettings; } - private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException { + private TextClassifierImplNative getNative(LocaleList localeList) + throws FileNotFoundException { synchronized (mLock) { localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList; final ModelFile bestModel = findBestModelLocked(localeList); if (bestModel == null) { throw new FileNotFoundException("No model for " + localeList.toLanguageTags()); } - if (mSmartSelection == null || !Objects.equals(mModel, bestModel)) { + if (mNative == null || !Objects.equals(mModel, bestModel)) { Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel); - destroySmartSelectionIfExistsLocked(); + destroyNativeIfExistsLocked(); final ParcelFileDescriptor fd = ParcelFileDescriptor.open( new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY); - mSmartSelection = new SmartSelection(fd.getFd()); + mNative = new TextClassifierImplNative(fd.getFd()); closeAndLogError(fd); mModel = bestModel; } - return mSmartSelection; + return mNative; } } @@ -302,13 +324,17 @@ public final class TextClassifierImpl implements TextClassifier { } @GuardedBy("mLock") // Do not call outside this lock. - private void destroySmartSelectionIfExistsLocked() { - if (mSmartSelection != null) { - mSmartSelection.close(); - mSmartSelection = null; + private void destroyNativeIfExistsLocked() { + if (mNative != null) { + mNative.close(); + mNative = null; } } + private static String concatenateLocales(@Nullable LocaleList locales) { + return (locales == null) ? "" : locales.toLanguageTags(); + } + /** * Finds the most appropriate model to use for the given target locale list. * @@ -372,20 +398,21 @@ public final class TextClassifierImpl implements TextClassifier { } private TextClassification createClassificationResult( - SmartSelection.ClassificationResult[] classifications, + TextClassifierImplNative.ClassificationResult[] classifications, String text, int start, int end, @Nullable Calendar referenceTime) { final String classifiedText = text.substring(start, end); final TextClassification.Builder builder = new TextClassification.Builder() .setText(classifiedText); final int size = classifications.length; - SmartSelection.ClassificationResult highestScoringResult = null; + TextClassifierImplNative.ClassificationResult highestScoringResult = null; float highestScore = Float.MIN_VALUE; for (int i = 0; i < size; i++) { - builder.setEntityType(classifications[i].mCollection, classifications[i].mScore); - if (classifications[i].mScore > highestScore) { + builder.setEntityType(classifications[i].getCollection(), + classifications[i].getScore()); + if (classifications[i].getScore() > highestScore) { highestScoringResult = classifications[i]; - highestScore = classifications[i].mScore; + highestScore = classifications[i].getScore(); } } @@ -433,19 +460,6 @@ public final class TextClassifierImpl implements TextClassifier { } } - private static int getHintFlags(CharSequence text, int start, int end) { - int flag = 0; - final CharSequence subText = text.subSequence(start, end); - if (Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(subText).matches()) { - flag |= SmartSelection.HINT_FLAG_EMAIL; - } - if (Patterns.AUTOLINK_WEB_URL.matcher(subText).matches() - && Linkify.sUrlMatchFilter.acceptMatch(text, start, end)) { - flag |= SmartSelection.HINT_FLAG_URL; - } - return flag; - } - /** * Closes the ParcelFileDescriptor and logs any errors that occur. */ @@ -473,8 +487,9 @@ public final class TextClassifierImpl implements TextClassifier { try { final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open( file, ParcelFileDescriptor.MODE_READ_ONLY); - final int version = SmartSelection.getVersion(modelFd.getFd()); - final String supportedLocalesStr = SmartSelection.getLanguages(modelFd.getFd()); + final int version = TextClassifierImplNative.getVersion(modelFd.getFd()); + final String supportedLocalesStr = + TextClassifierImplNative.getLocales(modelFd.getFd()); if (supportedLocalesStr.isEmpty()) { Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath()); return null; @@ -560,9 +575,9 @@ public final class TextClassifierImpl implements TextClassifier { public static List<Intent> create( Context context, @Nullable Calendar referenceTime, - SmartSelection.ClassificationResult classification, + TextClassifierImplNative.ClassificationResult classification, String text) { - final String type = classification.mCollection.trim().toLowerCase(Locale.ENGLISH); + final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH); text = text.trim(); switch (type) { case TextClassifier.TYPE_EMAIL: @@ -575,9 +590,10 @@ public final class TextClassifierImpl implements TextClassifier { return createForUrl(context, text); case TextClassifier.TYPE_DATE: case TextClassifier.TYPE_DATE_TIME: - if (classification.mDatetime != null) { + if (classification.getDatetimeResult() != null) { Calendar eventTime = Calendar.getInstance(); - eventTime.setTimeInMillis(classification.mDatetime.mMsSinceEpoch); + eventTime.setTimeInMillis( + classification.getDatetimeResult().getTimeMsUtc()); return createForDatetime(type, referenceTime, eventTime); } else { return new ArrayList<>(); diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java new file mode 100644 index 000000000000..3d4c8f2863ea --- /dev/null +++ b/core/java/android/view/textclassifier/TextClassifierImplNative.java @@ -0,0 +1,301 @@ +/* + * 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.content.res.AssetFileDescriptor; + +/** + * Java wrapper for TextClassifier native library interface. This library is used for detecting + * entities in text. + */ +final class TextClassifierImplNative { + + static { + System.loadLibrary("textclassifier"); + } + + private final long mModelPtr; + + /** + * Creates a new instance of TextClassifierImplNative, using the provided model image, given as + * a file descriptor. + */ + TextClassifierImplNative(int fd) { + mModelPtr = nativeNew(fd); + if (mModelPtr == 0L) { + throw new IllegalArgumentException("Couldn't initialize TC from file descriptor."); + } + } + + /** + * Creates a new instance of TextClassifierImplNative, using the provided model image, given as + * a file path. + */ + TextClassifierImplNative(String path) { + mModelPtr = nativeNewFromPath(path); + if (mModelPtr == 0L) { + throw new IllegalArgumentException("Couldn't initialize TC from given file."); + } + } + + /** + * Creates a new instance of TextClassifierImplNative, using the provided model image, given as + * an AssetFileDescriptor. + */ + TextClassifierImplNative(AssetFileDescriptor afd) { + mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength()); + if (mModelPtr == 0L) { + throw new IllegalArgumentException( + "Couldn't initialize TC from given AssetFileDescriptor"); + } + } + + /** + * Given a string context and current selection, computes the SmartSelection suggestion. + * + * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is + * the character index where the selection begins, and selectionEnd is the index of one + * character past the selection span. + * + * <p>The return value is an array of two ints: suggested selection beginning and end, with the + * same semantics as the input selectionBeginning and selectionEnd. + */ + public int[] suggestSelection( + String context, int selectionBegin, int selectionEnd, SelectionOptions options) { + return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options); + } + + /** + * Given a string context and current selection, classifies the type of the selected text. + * + * <p>The begin and end params are character indices in the context string. + * + * <p>Returns an array of ClassificationResult objects with the probability scores for different + * collections. + */ + public ClassificationResult[] classifyText( + String context, int selectionBegin, int selectionEnd, ClassificationOptions options) { + return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options); + } + + /** + * Annotates given input text. The annotations should cover the whole input context except for + * whitespaces, and are sorted by their position in the context string. + */ + public AnnotatedSpan[] annotate(String text, AnnotationOptions options) { + return nativeAnnotate(mModelPtr, text, options); + } + + /** Frees up the allocated memory. */ + public void close() { + nativeClose(mModelPtr); + } + + /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */ + public static String getLocales(int fd) { + return nativeGetLocales(fd); + } + + /** Returns the version of the model. */ + public static int getVersion(int fd) { + return nativeGetVersion(fd); + } + + /** Represents a datetime parsing result from classifyText calls. */ + public static final class DatetimeResult { + static final int GRANULARITY_YEAR = 0; + static final int GRANULARITY_MONTH = 1; + static final int GRANULARITY_WEEK = 2; + static final int GRANULARITY_DAY = 3; + static final int GRANULARITY_HOUR = 4; + static final int GRANULARITY_MINUTE = 5; + static final int GRANULARITY_SECOND = 6; + + private final long mTimeMsUtc; + private final int mGranularity; + + DatetimeResult(long timeMsUtc, int granularity) { + mGranularity = granularity; + mTimeMsUtc = timeMsUtc; + } + + public long getTimeMsUtc() { + return mTimeMsUtc; + } + + public int getGranularity() { + return mGranularity; + } + } + + /** Represents a result of classifyText method call. */ + public static final class ClassificationResult { + private final String mCollection; + private final float mScore; + private final DatetimeResult mDatetimeResult; + + ClassificationResult( + String collection, float score, DatetimeResult datetimeResult) { + mCollection = collection; + mScore = score; + mDatetimeResult = datetimeResult; + } + + public String getCollection() { + if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) { + switch (mDatetimeResult.getGranularity()) { + case DatetimeResult.GRANULARITY_HOUR: + // fall through + case DatetimeResult.GRANULARITY_MINUTE: + // fall through + case DatetimeResult.GRANULARITY_SECOND: + return TextClassifier.TYPE_DATE_TIME; + default: + return TextClassifier.TYPE_DATE; + } + } + return mCollection; + } + + public float getScore() { + return mScore; + } + + public DatetimeResult getDatetimeResult() { + return mDatetimeResult; + } + } + + /** Represents a result of Annotate call. */ + public static final class AnnotatedSpan { + private final int mStartIndex; + private final int mEndIndex; + private final ClassificationResult[] mClassification; + + AnnotatedSpan( + int startIndex, int endIndex, ClassificationResult[] classification) { + mStartIndex = startIndex; + mEndIndex = endIndex; + mClassification = classification; + } + + public int getStartIndex() { + return mStartIndex; + } + + public int getEndIndex() { + return mEndIndex; + } + + public ClassificationResult[] getClassification() { + return mClassification; + } + } + + /** Represents options for the suggestSelection call. */ + public static final class SelectionOptions { + private final String mLocales; + + SelectionOptions(String locales) { + mLocales = locales; + } + + public String getLocales() { + return mLocales; + } + } + + /** Represents options for the classifyText call. */ + public static final class ClassificationOptions { + private final long mReferenceTimeMsUtc; + private final String mReferenceTimezone; + private final String mLocales; + + ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) { + mReferenceTimeMsUtc = referenceTimeMsUtc; + mReferenceTimezone = referenceTimezone; + mLocales = locale; + } + + public long getReferenceTimeMsUtc() { + return mReferenceTimeMsUtc; + } + + public String getReferenceTimezone() { + return mReferenceTimezone; + } + + public String getLocale() { + return mLocales; + } + } + + /** Represents options for the Annotate call. */ + public static final class AnnotationOptions { + private final long mReferenceTimeMsUtc; + private final String mReferenceTimezone; + private final String mLocales; + + AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) { + mReferenceTimeMsUtc = referenceTimeMsUtc; + mReferenceTimezone = referenceTimezone; + mLocales = locale; + } + + public long getReferenceTimeMsUtc() { + return mReferenceTimeMsUtc; + } + + public String getReferenceTimezone() { + return mReferenceTimezone; + } + + public String getLocale() { + return mLocales; + } + } + + private static native long nativeNew(int fd); + + private static native long nativeNewFromPath(String path); + + private static native long nativeNewFromAssetFileDescriptor( + AssetFileDescriptor afd, long offset, long size); + + private static native int[] nativeSuggestSelection( + long context, + String text, + int selectionBegin, + int selectionEnd, + SelectionOptions options); + + private static native ClassificationResult[] nativeClassifyText( + long context, + String text, + int selectionBegin, + int selectionEnd, + ClassificationOptions options); + + private static native AnnotatedSpan[] nativeAnnotate( + long context, String text, AnnotationOptions options); + + private static native void nativeClose(long context); + + private static native String nativeGetLocales(int fd); + + private static native int nativeGetVersion(int fd); +} diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java index b7869d03c898..5407ce69abcf 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -41,7 +41,7 @@ import java.util.Collections; @RunWith(AndroidJUnit4.class) public class TextClassificationManagerTest { - private static final LocaleList LOCALES = LocaleList.forLanguageTags("en"); + private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US"); private static final String NO_TYPE = null; private TextClassificationManager mTcm; @@ -181,6 +181,42 @@ public class TextClassificationManagerTest { } @Test + public void testTextClassifyText_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 classification = mClassifier.classifyText( + text, startIndex, endIndex, mClassificationOptions); + assertThat(classification, + isTextClassification( + classifiedText, + TextClassifier.TYPE_DATE, + null)); + } + + @Test + public void testTextClassifyText_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 classification = mClassifier.classifyText( + text, startIndex, endIndex, mClassificationOptions); + assertThat(classification, + isTextClassification( + classifiedText, + TextClassifier.TYPE_DATE_TIME, + null)); + } + + @Test public void testGenerateLinks_phone() { if (isTextClassifierDisabled()) return; String text = "The number is +12122537077. See you tonight!"; @@ -334,7 +370,8 @@ public class TextClassificationManagerTest { && text.equals(result.getText()) && result.getEntityCount() > 0 && type.equals(result.getEntity(0)) - && intentUri.equals(result.getIntent().getDataString()); + && (intentUri == null + || intentUri.equals(result.getIntent().getDataString())); // TODO: Include other properties. } return false; |