diff options
| -rw-r--r-- | core/java/android/view/textclassifier/TextClassification.java | 127 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java | 57 |
2 files changed, 94 insertions, 90 deletions
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index ad50dc027279..f2643d770684 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -28,10 +28,11 @@ 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; +import android.graphics.BitmapFactory; +import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; @@ -68,7 +69,7 @@ import java.util.Map; * Button button = new Button(context); * button.setCompoundDrawablesWithIntrinsicBounds(classification.getIcon(), null, null, null); * button.setText(classification.getLabel()); - * button.setOnClickListener(v -> context.startActivity(classification.getIntent())); + * button.setOnClickListener(v -> classification.getActions().get(0).getActionIntent().send()); * }</pre> * * <p>e.g. starting an action mode with menu items that can handle the classified text: @@ -194,6 +195,9 @@ public final class TextClassification implements Parcelable { /** * Returns an icon that may be rendered on a widget used to act on the classified text. * + * <p><strong>NOTE: </strong>This field is not parcelable and only represents the icon of the + * first {@link RemoteAction} (if one exists) when this object is read from a parcel. + * * @deprecated Use {@link #getActions()} instead. */ @Deprecated @@ -205,6 +209,9 @@ public final class TextClassification implements Parcelable { /** * Returns a label that may be rendered on a widget used to act on the classified text. * + * <p><strong>NOTE: </strong>This field is not parcelable and only represents the label of the + * first {@link RemoteAction} (if one exists) when this object is read from a parcel. + * * @deprecated Use {@link #getActions()} instead. */ @Deprecated @@ -216,6 +223,9 @@ public final class TextClassification implements Parcelable { /** * Returns an intent that may be fired to act on the classified text. * + * <p><strong>NOTE: </strong>This field is not parcelled and will always return null when this + * object is read from a parcel. + * * @deprecated Use {@link #getActions()} instead. */ @Deprecated @@ -225,10 +235,10 @@ public final class TextClassification implements Parcelable { } /** - * Returns the OnClickListener that may be triggered to act on the classified text. This field - * is not parcelable and will be null for all objects read from a parcel. Instead, call - * Context#startActivity(Intent) with the result of #getSecondaryIntent(int). Note that this may - * fail if the activity doesn't have permission to send the intent. + * Returns the OnClickListener that may be triggered to act on the classified text. + * + * <p><strong>NOTE: </strong>This field is not parcelable and only represents the first + * {@link RemoteAction} (if one exists) when this object is read from a parcel. * * @deprecated Use {@link #getActions()} instead. */ @@ -324,41 +334,6 @@ public final class TextClassification implements Parcelable { } /** - * Returns a Bitmap representation of the Drawable - * - * @param drawable The drawable to convert. - * @param maxDims The maximum edge length of the resulting bitmap (in pixels). - */ - @Nullable - private static Bitmap drawableToBitmap(@Nullable Drawable drawable, int maxDims) { - if (drawable == null) { - return null; - } - final int actualWidth = Math.max(1, drawable.getIntrinsicWidth()); - final int actualHeight = Math.max(1, drawable.getIntrinsicHeight()); - final double scaleWidth = ((double) maxDims) / actualWidth; - final double scaleHeight = ((double) maxDims) / actualHeight; - final double scale = Math.min(1.0, Math.min(scaleWidth, scaleHeight)); - final int width = (int) (actualWidth * scale); - final int height = (int) (actualHeight * scale); - if (drawable instanceof BitmapDrawable) { - final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; - if (actualWidth != width || actualHeight != height) { - return Bitmap.createScaledBitmap( - bitmapDrawable.getBitmap(), width, height, /*filter=*/false); - } else { - return bitmapDrawable.getBitmap(); - } - } else { - final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - return bitmap; - } - } - - /** * Builder for building {@link TextClassification} objects. * * <p>e.g. @@ -426,6 +401,9 @@ public final class TextClassification implements Parcelable { * Sets the icon for the <i>primary</i> action that may be rendered on a widget used to act * on the classified text. * + * <p><strong>NOTE: </strong>This field is not parcelled. If read from a parcel, the + * returned icon represents the icon of the first {@link RemoteAction} (if one exists). + * * @deprecated Use {@link #addAction(RemoteAction)} instead. */ @Deprecated @@ -439,6 +417,9 @@ public final class TextClassification implements Parcelable { * Sets the label for the <i>primary</i> action that may be rendered on a widget used to * act on the classified text. * + * <p><strong>NOTE: </strong>This field is not parcelled. If read from a parcel, the + * returned label represents the label of the first {@link RemoteAction} (if one exists). + * * @deprecated Use {@link #addAction(RemoteAction)} instead. */ @Deprecated @@ -452,6 +433,8 @@ public final class TextClassification implements Parcelable { * Sets the intent for the <i>primary</i> action that may be fired to act on the classified * text. * + * <p><strong>NOTE: </strong>This field is not parcelled. + * * @deprecated Use {@link #addAction(RemoteAction)} instead. */ @Deprecated @@ -463,8 +446,10 @@ public final class TextClassification implements Parcelable { /** * Sets the OnClickListener for the <i>primary</i> action that may be triggered to act on - * the classified text. This field is not parcelable and will always be null when the - * object is read from a parcel. + * the classified text. + * + * <p><strong>NOTE: </strong>This field is not parcelable. If read from a parcel, the + * returned OnClickListener represents the first {@link RemoteAction} (if one exists). * * @deprecated Use {@link #addAction(RemoteAction)} instead. */ @@ -674,17 +659,7 @@ public final class TextClassification implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mText); - final Bitmap legacyIconBitmap = drawableToBitmap(mLegacyIcon, MAX_LEGACY_ICON_SIZE); - dest.writeInt(legacyIconBitmap != null ? 1 : 0); - if (legacyIconBitmap != null) { - legacyIconBitmap.writeToParcel(dest, flags); - } - dest.writeString(mLegacyLabel); - dest.writeInt(mLegacyIntent != null ? 1 : 0); - if (mLegacyIntent != null) { - mLegacyIntent.writeToParcel(dest, flags); - } - // mOnClickListener is not parcelable. + // NOTE: legacy fields are not parcelled. dest.writeTypedList(mActions); mEntityConfidence.writeToParcel(dest, flags); dest.writeString(mId); @@ -705,23 +680,43 @@ public final class TextClassification implements Parcelable { private TextClassification(Parcel in) { mText = in.readString(); - mLegacyIcon = in.readInt() == 0 - ? null - : new BitmapDrawable(Resources.getSystem(), Bitmap.CREATOR.createFromParcel(in)); - mLegacyLabel = in.readString(); - if (in.readInt() == 0) { - mLegacyIntent = null; + mActions = in.createTypedArrayList(RemoteAction.CREATOR); + if (!mActions.isEmpty()) { + final RemoteAction action = mActions.get(0); + mLegacyIcon = maybeLoadDrawable(action.getIcon()); + mLegacyLabel = action.getTitle().toString(); + mLegacyOnClickListener = createIntentOnClickListener(mActions.get(0).getActionIntent()); } else { - mLegacyIntent = Intent.CREATOR.createFromParcel(in); - mLegacyIntent.removeFlags( - Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + mLegacyIcon = null; + mLegacyLabel = null; + mLegacyOnClickListener = null; } - mLegacyOnClickListener = null; // not parcelable - mActions = in.createTypedArrayList(RemoteAction.CREATOR); + mLegacyIntent = null; // mLegacyIntent is not parcelled. mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in); mId = in.readString(); } + // Best effort attempt to try to load a drawable from the provided icon. + @Nullable + private static Drawable maybeLoadDrawable(Icon icon) { + if (icon == null) { + return null; + } + switch (icon.getType()) { + case Icon.TYPE_BITMAP: + return new BitmapDrawable(Resources.getSystem(), icon.getBitmap()); + case Icon.TYPE_ADAPTIVE_BITMAP: + return new AdaptiveIconDrawable(null, + new BitmapDrawable(Resources.getSystem(), icon.getBitmap())); + case Icon.TYPE_DATA: + return new BitmapDrawable( + Resources.getSystem(), + BitmapFactory.decodeByteArray( + icon.getDataBytes(), icon.getDataOffset(), icon.getDataLength())); + } + return null; + } + // TODO: Remove once apps can build against the latest sdk. /** * Optional input parameters for generating TextClassification. diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java index 09ace4c1509a..de863d743442 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java @@ -17,6 +17,7 @@ package android.view.textclassifier; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import android.app.PendingIntent; @@ -26,6 +27,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.LocaleList; import android.os.Parcel; @@ -99,12 +101,6 @@ public class TextClassificationTest { assertEquals(id, result.getId()); assertEquals(2, result.getActions().size()); - // Legacy API. - assertNull(result.getIcon()); - assertNull(result.getLabel()); - assertNull(result.getIntent()); - assertNull(result.getOnClickListener()); - // Primary action. final RemoteAction primaryAction = result.getActions().get(0); assertEquals(primaryLabel, primaryAction.getTitle()); @@ -128,23 +124,35 @@ public class TextClassificationTest { @Test public void testParcelLegacy() { final Context context = InstrumentationRegistry.getInstrumentation().getContext(); - final String text = "text"; - final Icon icon = generateTestIcon(384, 192, Color.BLUE); + final int legacyIconWidth = 192; + final int legacyIconHeight = 96; + final int legacyIconColor = Color.BLUE; + final Drawable legacyIcon = generateTestIcon( + legacyIconWidth, legacyIconHeight, legacyIconColor) + .loadDrawable(context); + final String legacyLabel = "legacyLabel"; + final Intent legacyIntent = new Intent("ACTION_LEGACY"); + final View.OnClickListener legacyOnClick = null; + + final int width = 384; + final int height = 192; + final int iconColor = Color.RED; final String label = "label"; - final Intent intent = new Intent("intent"); - final View.OnClickListener onClickListener = v -> { }; + final PendingIntent pendingIntent = PendingIntent.getActivity( + context, 0, new Intent("ACTION_0"), 0); + final RemoteAction remoteAction = new RemoteAction( + generateTestIcon(width, height, iconColor), + label, + "description", + pendingIntent); - final String id = "id"; final TextClassification reference = new TextClassification.Builder() - .setText(text) - .setIcon(icon.loadDrawable(context)) - .setLabel(label) - .setIntent(intent) - .setOnClickListener(onClickListener) - .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f) - .setEntityType(TextClassifier.TYPE_PHONE, 0.7f) - .setId(id) + .setIcon(legacyIcon) + .setLabel(legacyLabel) + .setIntent(legacyIntent) + .setOnClickListener(legacyOnClick) + .addAction(remoteAction) .build(); // Parcel and unparcel @@ -153,13 +161,14 @@ public class TextClassificationTest { parcel.setDataPosition(0); final TextClassification result = TextClassification.CREATOR.createFromParcel(parcel); + // Legacy fields excluding legacyIntent are replaced by first remoteAction. + assertNull(result.getIntent()); final Bitmap resultIcon = ((BitmapDrawable) result.getIcon()).getBitmap(); - assertEquals(icon.getBitmap().getPixel(0, 0), resultIcon.getPixel(0, 0)); - assertEquals(192, resultIcon.getWidth()); - assertEquals(96, resultIcon.getHeight()); + assertEquals(iconColor, resultIcon.getPixel(0, 0)); + assertEquals(width, resultIcon.getWidth()); + assertEquals(height, resultIcon.getHeight()); assertEquals(label, result.getLabel()); - assertEquals(intent.getAction(), result.getIntent().getAction()); - assertNull(result.getOnClickListener()); + assertNotNull(result.getOnClickListener()); } @Test |