TextClassifier: Support service intents.
Previously, the TextClassifier only supported Activity intents. Test: bit FrameworksCoreTests:android.view.textclassifier.TextClassificationManagerTest Test: bit FrameworksCoreTests:android.widget.TextViewActivityTest Change-Id: Ic488e2f6241eb91a6cd6e16d9f84a49a679164dc
This commit is contained in:
@@ -17,11 +17,14 @@
|
||||
package android.view.textclassifier;
|
||||
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@@ -36,6 +39,8 @@ import android.view.textclassifier.TextClassifier.EntityType;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
@@ -81,7 +86,7 @@ import java.util.Map;
|
||||
* // Add the "secondary" actions.
|
||||
* for (int i = 0; i < classification.getSecondaryActionsCount(); i++) {
|
||||
* if (thisAppHasPermissionToInvokeIntent(classification.getSecondaryIntent(i))) {
|
||||
* menu.add(Menu.NONE, i + 1, 20, classification.getSecondaryLabel(i))
|
||||
* menu.add(Menu.NONE, i + 1, 20, classification.getSecondaryLabel(i))
|
||||
* .setIcon(classification.getSecondaryIcon(i))
|
||||
* .setIntent(classification.getSecondaryIntent(i));
|
||||
* }
|
||||
@@ -109,6 +114,14 @@ public final class TextClassification implements Parcelable {
|
||||
private static final int MAX_PRIMARY_ICON_SIZE = 192;
|
||||
private static final int MAX_SECONDARY_ICON_SIZE = 144;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {IntentType.UNSUPPORTED, IntentType.ACTIVITY, IntentType.SERVICE})
|
||||
private @interface IntentType {
|
||||
int UNSUPPORTED = -1;
|
||||
int ACTIVITY = 0;
|
||||
int SERVICE = 1;
|
||||
}
|
||||
|
||||
@NonNull private final String mText;
|
||||
@Nullable private final Drawable mPrimaryIcon;
|
||||
@Nullable private final String mPrimaryLabel;
|
||||
@@ -312,17 +325,58 @@ public final class TextClassification implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an OnClickListener that starts an activity with the specified intent.
|
||||
* Creates an OnClickListener that triggers the specified intent.
|
||||
* Returns null if the intent is not supported for the specified context.
|
||||
*
|
||||
* @throws IllegalArgumentException if context or intent is null
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public static OnClickListener createStartActivityOnClickListener(
|
||||
@Nullable
|
||||
public static OnClickListener createIntentOnClickListener(
|
||||
@NonNull final Context context, @NonNull final Intent intent) {
|
||||
switch (getIntentType(intent, context)) {
|
||||
case IntentType.ACTIVITY:
|
||||
return v -> context.startActivity(intent);
|
||||
case IntentType.SERVICE:
|
||||
return v -> context.startService(intent);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@IntentType
|
||||
private static int getIntentType(@NonNull Intent intent, @NonNull Context context) {
|
||||
Preconditions.checkArgument(context != null);
|
||||
Preconditions.checkArgument(intent != null);
|
||||
return v -> context.startActivity(intent);
|
||||
|
||||
final ResolveInfo activityRI = context.getPackageManager().resolveActivity(intent, 0);
|
||||
if (activityRI != null) {
|
||||
if (context.getPackageName().equals(activityRI.activityInfo.packageName)) {
|
||||
return IntentType.ACTIVITY;
|
||||
}
|
||||
final boolean exported = activityRI.activityInfo.exported;
|
||||
if (exported && hasPermission(context, activityRI.activityInfo.permission)) {
|
||||
return IntentType.ACTIVITY;
|
||||
}
|
||||
}
|
||||
|
||||
final ResolveInfo serviceRI = context.getPackageManager().resolveService(intent, 0);
|
||||
if (serviceRI != null) {
|
||||
if (context.getPackageName().equals(serviceRI.serviceInfo.packageName)) {
|
||||
return IntentType.SERVICE;
|
||||
}
|
||||
final boolean exported = serviceRI.serviceInfo.exported;
|
||||
if (exported && hasPermission(context, serviceRI.serviceInfo.permission)) {
|
||||
return IntentType.SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
return IntentType.UNSUPPORTED;
|
||||
}
|
||||
|
||||
private static boolean hasPermission(@NonNull Context context, @NonNull String permission) {
|
||||
return permission == null
|
||||
|| context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4020,10 +4020,11 @@ public class Editor {
|
||||
if (textClassification == null) {
|
||||
return;
|
||||
}
|
||||
if (isValidAssistMenuItem(
|
||||
final OnClickListener onClick = getSupportedOnClickListener(
|
||||
textClassification.getIcon(),
|
||||
textClassification.getLabel(),
|
||||
textClassification.getIntent())) {
|
||||
textClassification.getIntent());
|
||||
if (onClick != null) {
|
||||
final MenuItem item = menu.add(
|
||||
TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST,
|
||||
textClassification.getLabel())
|
||||
@@ -4031,15 +4032,16 @@ public class Editor {
|
||||
.setIntent(textClassification.getIntent());
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
mAssistClickHandlers.put(
|
||||
item, TextClassification.createStartActivityOnClickListener(
|
||||
item, TextClassification.createIntentOnClickListener(
|
||||
mTextView.getContext(), textClassification.getIntent()));
|
||||
}
|
||||
final int count = textClassification.getSecondaryActionsCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!isValidAssistMenuItem(
|
||||
final OnClickListener onClick1 = getSupportedOnClickListener(
|
||||
textClassification.getSecondaryIcon(i),
|
||||
textClassification.getSecondaryLabel(i),
|
||||
textClassification.getSecondaryIntent(i))) {
|
||||
textClassification.getSecondaryIntent(i));
|
||||
if (onClick1 == null) {
|
||||
continue;
|
||||
}
|
||||
final int order = MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START + i;
|
||||
@@ -4050,7 +4052,7 @@ public class Editor {
|
||||
.setIntent(textClassification.getSecondaryIntent(i));
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
mAssistClickHandlers.put(item,
|
||||
TextClassification.createStartActivityOnClickListener(
|
||||
TextClassification.createIntentOnClickListener(
|
||||
mTextView.getContext(), textClassification.getSecondaryIntent(i)));
|
||||
}
|
||||
}
|
||||
@@ -4067,30 +4069,15 @@ public class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidAssistMenuItem(Drawable icon, CharSequence label, Intent intent) {
|
||||
@Nullable
|
||||
private OnClickListener getSupportedOnClickListener(
|
||||
Drawable icon, CharSequence label, Intent intent) {
|
||||
final boolean hasUi = icon != null || !TextUtils.isEmpty(label);
|
||||
final boolean hasAction = isSupportedIntent(intent);
|
||||
return hasUi && hasAction;
|
||||
}
|
||||
|
||||
private boolean isSupportedIntent(Intent intent) {
|
||||
if (intent == null) {
|
||||
return false;
|
||||
if (hasUi) {
|
||||
return TextClassification.createIntentOnClickListener(
|
||||
mTextView.getContext(), intent);
|
||||
}
|
||||
final Context context = mTextView.getContext();
|
||||
final ResolveInfo info = context.getPackageManager().resolveActivity(intent, 0);
|
||||
final boolean samePackage = context.getPackageName().equals(
|
||||
info.activityInfo.packageName);
|
||||
if (samePackage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final boolean exported = info.activityInfo.exported;
|
||||
final boolean requiresPermission = info.activityInfo.permission != null;
|
||||
final boolean hasPermission = !requiresPermission
|
||||
|| context.checkSelfPermission(info.activityInfo.permission)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
return exported && hasPermission;
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean onAssistMenuItemClicked(MenuItem assistMenuItem) {
|
||||
@@ -4107,7 +4094,7 @@ public class Editor {
|
||||
if (onClickListener == null) {
|
||||
final Intent intent = assistMenuItem.getIntent();
|
||||
if (intent != null) {
|
||||
onClickListener = TextClassification.createStartActivityOnClickListener(
|
||||
onClickListener = TextClassification.createIntentOnClickListener(
|
||||
mTextView.getContext(), intent);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user