summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/textclassifier/TextClassification.java127
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java57
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