Merge "TC: Fix null PendingIntent being passed to RemoteAction" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1290226564
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -305,7 +317,6 @@ public class TextClassificationManagerTest {
|
||||
public void testGetLocalTextClassifier() {
|
||||
assertTrue(mTcm.getTextClassifier(TextClassifier.LOCAL) instanceof TextClassifierImpl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSystemTextClassifier() {
|
||||
assertTrue(
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user