diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index 0657067d992f0..783891838fe09 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -18,6 +18,7 @@ package android.view.textclassifier; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -157,18 +158,29 @@ final class TextClassifierImpl implements TextClassifier { .setEntityType(type, 1.0f /* confidence */) .setIntent(intent) .setOnClickListener(TextClassificationResult.createStartActivityOnClick( - mContext, intent)) - .setLabel(IntentFactory.getLabel(mContext, type)); + mContext, intent)); final PackageManager pm = mContext.getPackageManager(); final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); - // TODO: If the resolveInfo is the "chooser", do not set the package name and use a default - // icon for this classification type. - intent.setPackage(resolveInfo.activityInfo.packageName); - Drawable icon = resolveInfo.activityInfo.loadIcon(pm); - if (icon == null) { - icon = resolveInfo.loadIcon(pm); + if (resolveInfo != null && resolveInfo.activityInfo != null) { + final String packageName = resolveInfo.activityInfo.packageName; + if ("android".equals(packageName)) { + // Requires the chooser to find an activity to handle the intent. + builder.setLabel(IntentFactory.getLabel(mContext, type)); + } else { + // A default activity will handle the intent. + intent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name)); + Drawable icon = resolveInfo.activityInfo.loadIcon(pm); + if (icon == null) { + icon = resolveInfo.loadIcon(pm); + } + builder.setIcon(icon); + CharSequence label = resolveInfo.activityInfo.loadLabel(pm); + if (label == null) { + label = resolveInfo.loadLabel(pm); + } + builder.setLabel(label != null ? label.toString() : null); + } } - builder.setIcon(icon); return builder.build(); } @@ -211,9 +223,12 @@ final class TextClassifierImpl implements TextClassifier { final String type = smartSelection.classifyText(text, selectionStart, selectionEnd); if (matches(type, linkMask)) { - final ClickableSpan span = createSpan( - context, type, text.substring(selectionStart, selectionEnd)); - spans.add(new SpanSpec(selectionStart, selectionEnd, span)); + final Intent intent = IntentFactory.create( + type, text.substring(selectionStart, selectionEnd)); + if (hasActivityHandler(context, intent)) { + final ClickableSpan span = createSpan(context, intent); + spans.add(new SpanSpec(selectionStart, selectionEnd, span)); + } } } start = end; @@ -279,17 +294,24 @@ final class TextClassifierImpl implements TextClassifier { return result; } - private static ClickableSpan createSpan( - final Context context, final String type, final String text) { + private static ClickableSpan createSpan(final Context context, final Intent intent) { return new ClickableSpan() { // TODO: Style this span. @Override public void onClick(View widget) { - context.startActivity(IntentFactory.create(type, text)); + context.startActivity(intent); } }; } + private static boolean hasActivityHandler(Context context, @Nullable Intent intent) { + if (intent == null) { + return false; + } + final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0); + return resolveInfo != null && resolveInfo.activityInfo != null; + } + /** * Implementation of LinksInfo that adds ClickableSpans to the specified text. */ diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index c1834f1b79ff0..a2cb491bbb7ad 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3917,12 +3917,18 @@ public class Editor { private void updateAssistMenuItem( Menu menu, TextClassificationResult textClassificationResult) { menu.removeItem(TextView.ID_ASSIST); - if (textClassificationResult != null - && textClassificationResult.getIcon() != null - && textClassificationResult.getOnClickListener() != null) { - menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, null) - .setIcon(textClassificationResult.getIcon()) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + if (textClassificationResult != null) { + final Drawable icon = textClassificationResult.getIcon(); + final CharSequence label = textClassificationResult.getLabel(); + final OnClickListener onClickListener = + textClassificationResult.getOnClickListener(); + final Intent intent = textClassificationResult.getIntent(); + if ((icon != null || !TextUtils.isEmpty(label)) + && (onClickListener != null || intent != null)) { + menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, label) + .setIcon(icon) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } } } @@ -3935,9 +3941,22 @@ public class Editor { if (customCallback != null && customCallback.onActionItemClicked(mode, item)) { return true; } - if (TextView.ID_ASSIST == item.getItemId() && mTextClassificationResult != null) { - mTextClassificationResult.getOnClickListener().onClick(mTextView); + final TextClassificationResult textClassificationResult = mTextClassificationResult; + if (TextView.ID_ASSIST == item.getItemId() && textClassificationResult != null) { + final OnClickListener onClickListener = + textClassificationResult.getOnClickListener(); + if (onClickListener != null) { + onClickListener.onClick(mTextView); + } else { + final Intent intent = textClassificationResult.getIntent(); + if (intent != null) { + TextClassificationResult.createStartActivityOnClick( + mTextView.getContext(), intent) + .onClick(mTextView); + } + } stopTextActionMode(); + return true; } return mTextView.onTextContextMenuItem(item.getItemId()); }