Loading core/java/android/view/textclassifier/SystemTextClassifier.java +2 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ public final class SystemTextClassifier implements TextClassifier { mManagerService = ITextClassifierService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE)); mSettings = Preconditions.checkNotNull(settings); mFallback = new TextClassifierImpl(context, settings); mFallback = context.getSystemService(TextClassificationManager.class) .getTextClassifier(TextClassifier.LOCAL); mPackageName = Preconditions.checkNotNull(context.getPackageName()); } Loading core/java/android/view/textclassifier/TextClassificationManager.java +3 −2 Original line number Diff line number Diff line Loading @@ -191,10 +191,11 @@ public final class TextClassificationManager { synchronized (mLock) { if (mLocalTextClassifier == null) { if (mSettings.isLocalTextClassifierEnabled()) { mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings); mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings, TextClassifier.NO_OP); } else { Log.d(LOG_TAG, "Local TextClassifier disabled"); mLocalTextClassifier = TextClassifierImpl.NO_OP; mLocalTextClassifier = TextClassifier.NO_OP; } } return mLocalTextClassifier; Loading core/java/android/view/textclassifier/TextClassifierImpl.java +18 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static java.time.temporal.ChronoUnit.MILLIS; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.PendingIntent; import android.app.RemoteAction; import android.app.SearchManager; import android.content.ComponentName; Loading Loading @@ -98,13 +99,18 @@ public final class TextClassifierImpl implements TextClassifier { private final TextClassificationConstants mSettings; public TextClassifierImpl(Context context, TextClassificationConstants settings) { public TextClassifierImpl( Context context, TextClassificationConstants settings, TextClassifier fallback) { mContext = Preconditions.checkNotNull(context); mFallback = TextClassifier.NO_OP; mFallback = Preconditions.checkNotNull(fallback); mSettings = Preconditions.checkNotNull(settings); mGenerateLinksLogger = new GenerateLinksLogger(mSettings.getGenerateLinksLogSampleRate()); } public TextClassifierImpl(Context context, TextClassificationConstants settings) { this(context, settings, TextClassifier.NO_OP); } /** @inheritDoc */ @Override @WorkerThread Loading Loading @@ -413,6 +419,9 @@ public final class TextClassifierImpl implements TextClassifier { for (LabeledIntent labeledIntent : IntentFactory.create( mContext, referenceTime, highestScoringResult, classifiedText)) { final RemoteAction action = labeledIntent.asRemoteAction(mContext); if (action == null) { continue; } if (isPrimaryAction) { // For O backwards compatibility, the first RemoteAction is also written to the // legacy API fields. Loading Loading @@ -601,6 +610,7 @@ public final class TextClassifierImpl implements TextClassifier { return mRequestCode; } @Nullable RemoteAction asRemoteAction(Context context) { final PackageManager pm = context.getPackageManager(); final ResolveInfo resolveInfo = pm.resolveActivity(mIntent, 0); Loading @@ -622,8 +632,12 @@ public final class TextClassifierImpl implements TextClassifier { icon = Icon.createWithResource("android", com.android.internal.R.drawable.ic_more_items); } final RemoteAction action = new RemoteAction(icon, mTitle, mDescription, TextClassification.createPendingIntent(context, mIntent, mRequestCode)); final PendingIntent pendingIntent = TextClassification.createPendingIntent(context, mIntent, mRequestCode); if (pendingIntent == null) { return null; } final RemoteAction action = new RemoteAction(icon, mTitle, mDescription, pendingIntent); action.setShouldShowIcon(shouldShowIcon); return action; } Loading core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +54 −1 Original line number Diff line number Diff line Loading @@ -18,11 +18,22 @@ package android.view.textclassifier; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.LocaleList; import android.service.textclassifier.TextClassifierService; import android.support.test.InstrumentationRegistry; Loading @@ -35,6 +46,7 @@ import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -305,7 +317,6 @@ public class TextClassificationManagerTest { public void testGetLocalTextClassifier() { assertTrue(mTcm.getTextClassifier(TextClassifier.LOCAL) instanceof TextClassifierImpl); } @Test public void testGetSystemTextClassifier() { assertTrue( Loading @@ -313,6 +324,48 @@ public class TextClassificationManagerTest { || mTcm.getTextClassifier(TextClassifier.SYSTEM) instanceof SystemTextClassifier); } @Test public void testCannotResolveIntent() { final PackageManager fakePackageMgr = mock(PackageManager.class); ResolveInfo validInfo = mContext.getPackageManager().resolveActivity( new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:+12122537077")), 0); // Make packageManager fail when it gets the following intent: ArgumentMatcher<Intent> toFailIntent = intent -> intent.getAction().equals(Intent.ACTION_INSERT_OR_EDIT); when(fakePackageMgr.resolveActivity(any(Intent.class), anyInt())).thenReturn(validInfo); when(fakePackageMgr.resolveActivity(argThat(toFailIntent), anyInt())).thenReturn(null); ContextWrapper fakeContext = new ContextWrapper(mContext) { @Override public PackageManager getPackageManager() { return fakePackageMgr; } }; TextClassifier fallback = TextClassifier.NO_OP; TextClassifier classifier = new TextClassifierImpl( fakeContext, TextClassificationConstants.loadFromString(null), 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); } private boolean isTextClassifierDisabled() { return mClassifier == TextClassifier.NO_OP; } Loading Loading
core/java/android/view/textclassifier/SystemTextClassifier.java +2 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ public final class SystemTextClassifier implements TextClassifier { mManagerService = ITextClassifierService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE)); mSettings = Preconditions.checkNotNull(settings); mFallback = new TextClassifierImpl(context, settings); mFallback = context.getSystemService(TextClassificationManager.class) .getTextClassifier(TextClassifier.LOCAL); mPackageName = Preconditions.checkNotNull(context.getPackageName()); } Loading
core/java/android/view/textclassifier/TextClassificationManager.java +3 −2 Original line number Diff line number Diff line Loading @@ -191,10 +191,11 @@ public final class TextClassificationManager { synchronized (mLock) { if (mLocalTextClassifier == null) { if (mSettings.isLocalTextClassifierEnabled()) { mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings); mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings, TextClassifier.NO_OP); } else { Log.d(LOG_TAG, "Local TextClassifier disabled"); mLocalTextClassifier = TextClassifierImpl.NO_OP; mLocalTextClassifier = TextClassifier.NO_OP; } } return mLocalTextClassifier; Loading
core/java/android/view/textclassifier/TextClassifierImpl.java +18 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static java.time.temporal.ChronoUnit.MILLIS; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.PendingIntent; import android.app.RemoteAction; import android.app.SearchManager; import android.content.ComponentName; Loading Loading @@ -98,13 +99,18 @@ public final class TextClassifierImpl implements TextClassifier { private final TextClassificationConstants mSettings; public TextClassifierImpl(Context context, TextClassificationConstants settings) { public TextClassifierImpl( Context context, TextClassificationConstants settings, TextClassifier fallback) { mContext = Preconditions.checkNotNull(context); mFallback = TextClassifier.NO_OP; mFallback = Preconditions.checkNotNull(fallback); mSettings = Preconditions.checkNotNull(settings); mGenerateLinksLogger = new GenerateLinksLogger(mSettings.getGenerateLinksLogSampleRate()); } public TextClassifierImpl(Context context, TextClassificationConstants settings) { this(context, settings, TextClassifier.NO_OP); } /** @inheritDoc */ @Override @WorkerThread Loading Loading @@ -413,6 +419,9 @@ public final class TextClassifierImpl implements TextClassifier { for (LabeledIntent labeledIntent : IntentFactory.create( mContext, referenceTime, highestScoringResult, classifiedText)) { final RemoteAction action = labeledIntent.asRemoteAction(mContext); if (action == null) { continue; } if (isPrimaryAction) { // For O backwards compatibility, the first RemoteAction is also written to the // legacy API fields. Loading Loading @@ -601,6 +610,7 @@ public final class TextClassifierImpl implements TextClassifier { return mRequestCode; } @Nullable RemoteAction asRemoteAction(Context context) { final PackageManager pm = context.getPackageManager(); final ResolveInfo resolveInfo = pm.resolveActivity(mIntent, 0); Loading @@ -622,8 +632,12 @@ public final class TextClassifierImpl implements TextClassifier { icon = Icon.createWithResource("android", com.android.internal.R.drawable.ic_more_items); } final RemoteAction action = new RemoteAction(icon, mTitle, mDescription, TextClassification.createPendingIntent(context, mIntent, mRequestCode)); final PendingIntent pendingIntent = TextClassification.createPendingIntent(context, mIntent, mRequestCode); if (pendingIntent == null) { return null; } final RemoteAction action = new RemoteAction(icon, mTitle, mDescription, pendingIntent); action.setShouldShowIcon(shouldShowIcon); return action; } Loading
core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +54 −1 Original line number Diff line number Diff line Loading @@ -18,11 +18,22 @@ package android.view.textclassifier; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.LocaleList; import android.service.textclassifier.TextClassifierService; import android.support.test.InstrumentationRegistry; Loading @@ -35,6 +46,7 @@ import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import java.util.Arrays; import java.util.Collections; Loading Loading @@ -305,7 +317,6 @@ public class TextClassificationManagerTest { public void testGetLocalTextClassifier() { assertTrue(mTcm.getTextClassifier(TextClassifier.LOCAL) instanceof TextClassifierImpl); } @Test public void testGetSystemTextClassifier() { assertTrue( Loading @@ -313,6 +324,48 @@ public class TextClassificationManagerTest { || mTcm.getTextClassifier(TextClassifier.SYSTEM) instanceof SystemTextClassifier); } @Test public void testCannotResolveIntent() { final PackageManager fakePackageMgr = mock(PackageManager.class); ResolveInfo validInfo = mContext.getPackageManager().resolveActivity( new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:+12122537077")), 0); // Make packageManager fail when it gets the following intent: ArgumentMatcher<Intent> toFailIntent = intent -> intent.getAction().equals(Intent.ACTION_INSERT_OR_EDIT); when(fakePackageMgr.resolveActivity(any(Intent.class), anyInt())).thenReturn(validInfo); when(fakePackageMgr.resolveActivity(argThat(toFailIntent), anyInt())).thenReturn(null); ContextWrapper fakeContext = new ContextWrapper(mContext) { @Override public PackageManager getPackageManager() { return fakePackageMgr; } }; TextClassifier fallback = TextClassifier.NO_OP; TextClassifier classifier = new TextClassifierImpl( fakeContext, TextClassificationConstants.loadFromString(null), 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); } private boolean isTextClassifierDisabled() { return mClassifier == TextClassifier.NO_OP; } Loading