Merge "Support seralization of bitmap and adaptive icons" into androidx-main
diff --git a/wear/watchface/watchface-complications-data/proguard-rules.pro b/wear/watchface/watchface-complications-data/proguard-rules.pro
index de1e0af..187c816 100644
--- a/wear/watchface/watchface-complications-data/proguard-rules.pro
+++ b/wear/watchface/watchface-complications-data/proguard-rules.pro
@@ -22,6 +22,7 @@
-keep public class android.support.wearable.complications.TimeDependentText { *; }
-keep public class android.support.wearable.complications.TimeDifferenceText { *; }
-keep public class android.support.wearable.complications.TimeFormatText { *; }
+-keep public class android.graphics.drawable.Icon { *; }
# Ensure our sanitizing of EditorSession.usr_style doesn't break due to renames.
-keep public class kotlinx.coroutines.flow.MutableStateFlow { *; }
diff --git a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java
index ec2444f..e584635 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java
+++ b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/ComplicationData.java
@@ -536,7 +536,7 @@
@RequiresApi(api = Build.VERSION_CODES.P)
private static class SerializedForm implements Serializable {
- private static final int VERSION_NUMBER = 15;
+ private static final int VERSION_NUMBER = 16;
@NonNull
ComplicationData mComplicationData;
diff --git a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/IconSerializableHelper.java b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/IconSerializableHelper.java
index 9b0bfa4..4dea811 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/IconSerializableHelper.java
+++ b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/IconSerializableHelper.java
@@ -16,16 +16,22 @@
package android.support.wearable.complications;
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.os.Build;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
+import java.lang.reflect.Method;
@RequiresApi(api = Build.VERSION_CODES.P)
class IconSerializableHelper implements Serializable {
@@ -33,6 +39,9 @@
String mResourcePackage;
int mResourceId;
String mUri;
+ byte[] mBitmap;
+
+ private static final String TAG = "IconSerializableHelper";
@Nullable
static IconSerializableHelper create(@Nullable Icon icon) {
@@ -61,22 +70,44 @@
break;
case Icon.TYPE_URI:
+ case Icon.TYPE_URI_ADAPTIVE_BITMAP:
mUri = icon.getUri().toString();
break;
- }
- // We currently don't attempt to serialize any other type of icon. We could render to a
- // bitmap, but the above covers the majority of complication icons.
+ case Icon.TYPE_BITMAP:
+ case Icon.TYPE_ADAPTIVE_BITMAP:
+ try {
+ Method getBitmap = icon.getClass().getDeclaredMethod("getBitmap");
+ @SuppressLint("BanUncheckedReflection")
+ Bitmap bitmap = (Bitmap) getBitmap.invoke(icon);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
+ mBitmap = baos.toByteArray();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to serialize bitmap", e);
+ }
+ break;
+
+ default:
+ Log.e(TAG, "Failed to serialize icon of type " + mType);
+ }
}
- @Nullable Icon toIcon() {
+ @Nullable
+ Icon toIcon() {
switch (mType) {
case Icon.TYPE_RESOURCE:
return Icon.createWithResource(mResourcePackage, mResourceId);
case Icon.TYPE_URI:
+ case Icon.TYPE_URI_ADAPTIVE_BITMAP:
return Icon.createWithContentUri(mUri);
+ case Icon.TYPE_BITMAP:
+ case Icon.TYPE_ADAPTIVE_BITMAP:
+ return Icon.createWithBitmap(BitmapFactory.decodeByteArray(mBitmap, 0,
+ mBitmap.length));
+
default:
return null;
}
diff --git a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
index 37edec2..73c4f3b 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/DataTest.kt
@@ -16,10 +16,12 @@
package androidx.wear.watchface.complications.data
+import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Icon
import android.os.Build
@@ -1146,6 +1148,36 @@
@RequiresApi(Build.VERSION_CODES.P)
@Test
+ public fun smallImageComplicationData_with_BitmapIcon() {
+ val bitmapIcon =
+ Icon.createWithBitmap(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888))
+ val image = SmallImage.Builder(bitmapIcon, SmallImageType.PHOTO).build()
+ val data = SmallImageComplicationData.Builder(
+ image, "content description".complicationText
+ ).setDataSource(dataSourceA).build()
+ ParcelableSubject.assertThat(data.asWireComplicationData())
+ .hasSameSerializationAs(
+ WireComplicationDataBuilder(WireComplicationData.TYPE_SMALL_IMAGE)
+ .setSmallImage(bitmapIcon)
+ .setSmallImageStyle(WireComplicationData.IMAGE_STYLE_PHOTO)
+ .setContentDescription(WireComplicationText.plainText("content description"))
+ .setDataSource(dataSourceA)
+ .build()
+ )
+ testRoundTripConversions(data)
+ val deserialized = serializeAndDeserialize(data) as SmallImageComplicationData
+
+ assertThat(deserialized.smallImage.image.type).isEqualTo(Icon.TYPE_BITMAP)
+ val getBitmap = deserialized.smallImage.image.javaClass.getDeclaredMethod("getBitmap")
+ @SuppressLint("BanUncheckedReflection")
+ val bitmap = getBitmap.invoke(deserialized.smallImage.image) as Bitmap
+
+ assertThat(bitmap.width).isEqualTo(100)
+ assertThat(bitmap.height).isEqualTo(100)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.P)
+ @Test
public fun backgroundImageComplicationData() {
val photoImage = Icon.createWithContentUri("someuri")
val data = PhotoImageComplicationData.Builder(