Unverified Commit 3c039d73 authored by Simon Xu's avatar Simon Xu Committed by GitHub
Browse files

Support animated stickers on Android (#737)



* support animated stickers on Android

* [Android] Add WHO pack as animated pack

* [Android] add animated pack indicator in sticker pack list

* [Android] set sticker animation indicator on details view

* [Android] add tap to preview

* [Android] add animated sticker file validation

* [Android] Add existing file dimension and size when showing error

* [Android]improve format of error message.
Co-authored-by: default avatarSimon Xu <simonxuzhe@fb.com>
parent 4257cfdb
...@@ -7,112 +7,370 @@ ...@@ -7,112 +7,370 @@
"name": "Cuppy", "name": "Cuppy",
"publisher": "Jane Doe", "publisher": "Jane Doe",
"tray_image_file": "tray_Cuppy.png", "tray_image_file": "tray_Cuppy.png",
"image_data_version":"1", "image_data_version": "1",
"avoid_cache":false, "avoid_cache": false,
"publisher_email":"", "publisher_email": "",
"publisher_website": "", "publisher_website": "",
"privacy_policy_website": "", "privacy_policy_website": "",
"license_agreement_website": "", "license_agreement_website": "",
"stickers": [ "stickers": [
{ {
"image_file": "01_Cuppy_smile.webp", "image_file": "01_Cuppy_smile.webp",
"emojis": ["☕","🙂"] "emojis": [
"☕",
"🙂"
]
}, },
{ {
"image_file": "02_Cuppy_lol.webp", "image_file": "02_Cuppy_lol.webp",
"emojis": ["😄","😀"] "emojis": [
"😄",
"😀"
]
}, },
{ {
"image_file": "03_Cuppy_rofl.webp", "image_file": "03_Cuppy_rofl.webp",
"emojis": ["😆","😂"] "emojis": [
"😆",
"😂"
]
}, },
{ {
"image_file": "04_Cuppy_sad.webp", "image_file": "04_Cuppy_sad.webp",
"emojis": ["😩","😰"] "emojis": [
"😩",
"😰"
]
}, },
{ {
"image_file": "05_Cuppy_cry.webp", "image_file": "05_Cuppy_cry.webp",
"emojis": ["😭","💧"] "emojis": [
"😭",
"💧"
]
}, },
{ {
"image_file": "06_Cuppy_love.webp", "image_file": "06_Cuppy_love.webp",
"emojis": ["😍","♥"] "emojis": [
"😍",
"♥"
]
}, },
{ {
"image_file": "07_Cuppy_hate.webp", "image_file": "07_Cuppy_hate.webp",
"emojis": ["💔","👎"] "emojis": [
"💔",
"👎"
]
}, },
{ {
"image_file": "08_Cuppy_lovewithmug.webp", "image_file": "08_Cuppy_lovewithmug.webp",
"emojis": ["😍","💑"] "emojis": [
"😍",
"💑"
]
}, },
{ {
"image_file": "09_Cuppy_lovewithcookie.webp", "image_file": "09_Cuppy_lovewithcookie.webp",
"emojis": ["😘","🍪"] "emojis": [
"😘",
"🍪"
]
}, },
{ {
"image_file": "10_Cuppy_hmm.webp", "image_file": "10_Cuppy_hmm.webp",
"emojis": ["🤔","😐"] "emojis": [
"🤔",
"😐"
]
}, },
{ {
"image_file": "11_Cuppy_upset.webp", "image_file": "11_Cuppy_upset.webp",
"emojis": ["😱","😵"] "emojis": [
"😱",
"😵"
]
}, },
{ {
"image_file": "12_Cuppy_angry.webp", "image_file": "12_Cuppy_angry.webp",
"emojis": ["😡","😠"] "emojis": [
"😡",
"😠"
]
}, },
{ {
"image_file": "13_Cuppy_curious.webp", "image_file": "13_Cuppy_curious.webp",
"emojis": ["❓","🤔"] "emojis": [
"❓",
"🤔"
]
}, },
{ {
"image_file": "14_Cuppy_weird.webp", "image_file": "14_Cuppy_weird.webp",
"emojis": ["🌈","😜"] "emojis": [
"🌈",
"😜"
]
}, },
{ {
"image_file": "15_Cuppy_bluescreen.webp", "image_file": "15_Cuppy_bluescreen.webp",
"emojis": ["💻","😩"] "emojis": [
"💻",
"😩"
]
}, },
{ {
"image_file": "16_Cuppy_angry.webp", "image_file": "16_Cuppy_angry.webp",
"emojis": ["😡","😤"] "emojis": [
"😡",
"😤"
]
}, },
{ {
"image_file": "17_Cuppy_tired.webp", "image_file": "17_Cuppy_tired.webp",
"emojis": ["😩","😨"] "emojis": [
"😩",
"😨"
]
}, },
{ {
"image_file": "18_Cuppy_workhard.webp", "image_file": "18_Cuppy_workhard.webp",
"emojis": ["💻","🌃"] "emojis": [
"💻",
"🌃"
]
}, },
{ {
"image_file": "19_Cuppy_shine.webp", "image_file": "19_Cuppy_shine.webp",
"emojis": ["🎉","✨"] "emojis": [
"🎉",
"✨"
]
}, },
{ {
"image_file": "20_Cuppy_disgusting.webp", "image_file": "20_Cuppy_disgusting.webp",
"emojis": ["🤮","👎"] "emojis": [
"🤮",
"👎"
]
}, },
{ {
"image_file": "21_Cuppy_hi.webp", "image_file": "21_Cuppy_hi.webp",
"emojis": ["🖐","🙋"] "emojis": [
"🖐",
"🙋"
]
}, },
{ {
"image_file": "22_Cuppy_bye.webp", "image_file": "22_Cuppy_bye.webp",
"emojis": ["🖐","👋"] "emojis": [
"🖐",
"👋"
]
}, },
{ {
"image_file": "23_Cuppy_greentea.webp", "image_file": "23_Cuppy_greentea.webp",
"emojis": ["🍵","😌"] "emojis": [
"🍵",
"😌"
]
}, },
{ {
"image_file": "24_Cuppy_phone.webp", "image_file": "24_Cuppy_phone.webp",
"emojis": ["📱","😦"] "emojis": [
"📱",
"😦"
]
}, },
{ {
"image_file": "25_Cuppy_battery.webp", "image_file": "25_Cuppy_battery.webp",
"emojis": ["🔋","😵"] "emojis": [
"🔋",
"😵"
]
}
]
},
{
"identifier": "2",
"name": "Together While Apart",
"publisher": "World Health Organization",
"tray_image_file": "01.png",
"image_data_version": "1",
"avoid_cache": false,
"publisher_email": "",
"publisher_website": "",
"privacy_policy_website": "",
"license_agreement_website": "",
"animated_sticker_pack": true,
"stickers": [
{
"image_file": "01_SendingLove.webp",
"emojis": [
"🥰",
"😘",
"❤️"
]
},
{
"image_file": "02_WellDoThisTogether.webp",
"emojis": [
"✊",
"💪",
"🙏"
]
},
{
"image_file": "03_Heart.webp",
"emojis": [
"❤️",
"🥰",
"💕"
]
},
{
"image_file": "04_AirHighFive.webp",
"emojis": [
"🖐",
"🙌",
"✋"
]
},
{
"image_file": "05_GroupVideoCalling.webp",
"emojis": [
"📱",
"👯",
"👋"
]
},
{
"image_file": "06_StayConnected.webp",
"emojis": [
"📱",
"🙋‍♀",
"🙋‍♂"
]
},
{
"image_file": "07_OK.webp",
"emojis": [
"👍",
"👌",
"🙂"
]
},
{
"image_file": "08_AreYouOK.webp",
"emojis": [
"👋",
"❓",
"📱"
]
},
{
"image_file": "09_StayingHomeMug.webp",
"emojis": [
"☕",
"🍵",
"🏠"
]
},
{
"image_file": "10_WorkingFromBed.webp",
"emojis": [
"👩‍💻",
"👨‍💻",
"🛏"
]
},
{
"image_file": "11_StayCalm.webp",
"emojis": [
"🧘♀",
"🧘♂",
"🤙"
]
},
{
"image_file": "12_Gymnastics.webp",
"emojis": [
"🤸",
"🐩",
"💪"
]
},
{
"image_file": "13_DoubleChecking.webp",
"emojis": [
"📰",
"🔎",
"🔍"
]
},
{
"image_file": "14_CatOnTheLaptop.webp",
"emojis": [
"🐈",
"🐱",
"💻"
]
},
{
"image_file": "15_WorkingFromHomeF.webp",
"emojis": [
"👩‍💻",
"🏠",
"💻"
]
},
{
"image_file": "16_WorkingFromHomeM.webp",
"emojis": [
"👨‍💻",
"🏠",
"💻"
]
},
{
"image_file": "17_WashingHands.webp",
"emojis": [
"✋",
"💦",
"🧼"
]
},
{
"image_file": "18_DontTouchYourFace.webp",
"emojis": [
"😷",
"🤒",
"🤧"
]
},
{
"image_file": "19_SocialDistancing.webp",
"emojis": [
"😷",
"🤒",
"🏠"
]
},
{
"image_file": "20_SuperheroNurse.webp",
"emojis": [
"👩‍⚕",
"👨‍⚕️",
"🩺"
]
},
{
"image_file": "21_YouAreMyHero.webp",
"emojis": [
"🙏",
"🦸‍♀️",
"🦸"
]
} }
] ]
} }
......
...@@ -75,6 +75,7 @@ class ContentFileParser { ...@@ -75,6 +75,7 @@ class ContentFileParser {
String licenseAgreementWebsite = null; String licenseAgreementWebsite = null;
String imageDataVersion = ""; String imageDataVersion = "";
boolean avoidCache = false; boolean avoidCache = false;
boolean animatedStickerPack = false;
List<Sticker> stickerList = null; List<Sticker> stickerList = null;
while (reader.hasNext()) { while (reader.hasNext()) {
String key = reader.nextName(); String key = reader.nextName();
...@@ -112,6 +113,9 @@ class ContentFileParser { ...@@ -112,6 +113,9 @@ class ContentFileParser {
case "avoid_cache": case "avoid_cache":
avoidCache = reader.nextBoolean(); avoidCache = reader.nextBoolean();
break; break;
case "animated_sticker_pack":
animatedStickerPack = reader.nextBoolean();
break;
default: default:
reader.skipValue(); reader.skipValue();
} }
...@@ -138,7 +142,7 @@ class ContentFileParser { ...@@ -138,7 +142,7 @@ class ContentFileParser {
throw new IllegalStateException("image_data_version should not be empty"); throw new IllegalStateException("image_data_version should not be empty");
} }
reader.endObject(); reader.endObject();
final StickerPack stickerPack = new StickerPack(identifier, name, publisher, trayImageFile, publisherEmail, publisherWebsite, privacyPolicyWebsite, licenseAgreementWebsite, imageDataVersion, avoidCache); final StickerPack stickerPack = new StickerPack(identifier, name, publisher, trayImageFile, publisherEmail, publisherWebsite, privacyPolicyWebsite, licenseAgreementWebsite, imageDataVersion, avoidCache, animatedStickerPack);
stickerPack.setStickers(stickerList); stickerPack.setStickers(stickerList);
return stickerPack; return stickerPack;
} }
...@@ -165,6 +169,7 @@ class ContentFileParser { ...@@ -165,6 +169,7 @@ class ContentFileParser {
} }
} }
reader.endArray(); reader.endArray();
} else { } else {
throw new IllegalStateException("unknown field in json: " + key); throw new IllegalStateException("unknown field in json: " + key);
} }
......
...@@ -48,6 +48,7 @@ public class StickerContentProvider extends ContentProvider { ...@@ -48,6 +48,7 @@ public class StickerContentProvider extends ContentProvider {
public static final String LICENSE_AGREENMENT_WEBSITE = "sticker_pack_license_agreement_website"; public static final String LICENSE_AGREENMENT_WEBSITE = "sticker_pack_license_agreement_website";
public static final String IMAGE_DATA_VERSION = "image_data_version"; public static final String IMAGE_DATA_VERSION = "image_data_version";
public static final String AVOID_CACHE = "whatsapp_will_not_cache_stickers"; public static final String AVOID_CACHE = "whatsapp_will_not_cache_stickers";
public static final String ANIMATED_STICKER_PACK = "animated_sticker_pack";
public static final String STICKER_FILE_NAME_IN_QUERY = "sticker_file_name"; public static final String STICKER_FILE_NAME_IN_QUERY = "sticker_file_name";
public static final String STICKER_FILE_EMOJI_IN_QUERY = "sticker_emoji"; public static final String STICKER_FILE_EMOJI_IN_QUERY = "sticker_emoji";
...@@ -191,6 +192,7 @@ public class StickerContentProvider extends ContentProvider { ...@@ -191,6 +192,7 @@ public class StickerContentProvider extends ContentProvider {
LICENSE_AGREENMENT_WEBSITE, LICENSE_AGREENMENT_WEBSITE,
IMAGE_DATA_VERSION, IMAGE_DATA_VERSION,
AVOID_CACHE, AVOID_CACHE,
ANIMATED_STICKER_PACK,
}); });
for (StickerPack stickerPack : stickerPackList) { for (StickerPack stickerPack : stickerPackList) {
MatrixCursor.RowBuilder builder = cursor.newRow(); MatrixCursor.RowBuilder builder = cursor.newRow();
...@@ -206,6 +208,7 @@ public class StickerContentProvider extends ContentProvider { ...@@ -206,6 +208,7 @@ public class StickerContentProvider extends ContentProvider {
builder.add(stickerPack.licenseAgreementWebsite); builder.add(stickerPack.licenseAgreementWebsite);
builder.add(stickerPack.imageDataVersion); builder.add(stickerPack.imageDataVersion);
builder.add(stickerPack.avoidCache ? 1 : 0); builder.add(stickerPack.avoidCache ? 1 : 0);
builder.add(stickerPack.animatedStickerPack ? 1 : 0);
} }
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri); cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor; return cursor;
......
...@@ -24,6 +24,7 @@ class StickerPack implements Parcelable { ...@@ -24,6 +24,7 @@ class StickerPack implements Parcelable {
final String licenseAgreementWebsite; final String licenseAgreementWebsite;
final String imageDataVersion; final String imageDataVersion;
final boolean avoidCache; final boolean avoidCache;
final boolean animatedStickerPack;
String iosAppStoreLink; String iosAppStoreLink;
private List<Sticker> stickers; private List<Sticker> stickers;
...@@ -31,7 +32,7 @@ class StickerPack implements Parcelable { ...@@ -31,7 +32,7 @@ class StickerPack implements Parcelable {
String androidPlayStoreLink; String androidPlayStoreLink;
private boolean isWhitelisted; private boolean isWhitelisted;
StickerPack(String identifier, String name, String publisher, String trayImageFile, String publisherEmail, String publisherWebsite, String privacyPolicyWebsite, String licenseAgreementWebsite, String imageDataVersion, boolean avoidCache) { StickerPack(String identifier, String name, String publisher, String trayImageFile, String publisherEmail, String publisherWebsite, String privacyPolicyWebsite, String licenseAgreementWebsite, String imageDataVersion, boolean avoidCache, boolean animatedStickerPack) {
this.identifier = identifier; this.identifier = identifier;
this.name = name; this.name = name;
this.publisher = publisher; this.publisher = publisher;
...@@ -42,6 +43,7 @@ class StickerPack implements Parcelable { ...@@ -42,6 +43,7 @@ class StickerPack implements Parcelable {
this.licenseAgreementWebsite = licenseAgreementWebsite; this.licenseAgreementWebsite = licenseAgreementWebsite;
this.imageDataVersion = imageDataVersion; this.imageDataVersion = imageDataVersion;
this.avoidCache = avoidCache; this.avoidCache = avoidCache;
this.animatedStickerPack = animatedStickerPack;
} }
void setIsWhitelisted(boolean isWhitelisted) { void setIsWhitelisted(boolean isWhitelisted) {
...@@ -68,6 +70,7 @@ class StickerPack implements Parcelable { ...@@ -68,6 +70,7 @@ class StickerPack implements Parcelable {
</