Add support for animated stickers.

This commit is contained in:
Greyson Parrelli 2020-09-02 12:46:58 -04:00 committed by Cody Henthorne
parent bb708e0aa3
commit f4a199f621
26 changed files with 146 additions and 72 deletions

View File

@ -1425,7 +1425,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
if (stickerLocator != null && draftMedia != null) { if (stickerLocator != null && draftMedia != null) {
Log.d(TAG, "Handling shared sticker."); Log.d(TAG, "Handling shared sticker.");
sendSticker(stickerLocator, draftMedia, 0, true); sendSticker(stickerLocator, Objects.requireNonNull(draftContentType), draftMedia, 0, true);
return new SettableFuture<>(false); return new SettableFuture<>(false);
} }
@ -2876,7 +2876,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
} }
private void sendSticker(@NonNull StickerRecord stickerRecord, boolean clearCompose) { private void sendSticker(@NonNull StickerRecord stickerRecord, boolean clearCompose) {
sendSticker(new StickerLocator(stickerRecord.getPackId(), stickerRecord.getPackKey(), stickerRecord.getStickerId()), stickerRecord.getUri(), stickerRecord.getSize(), clearCompose); sendSticker(new StickerLocator(stickerRecord.getPackId(), stickerRecord.getPackKey(), stickerRecord.getStickerId()), stickerRecord.getContentType(), stickerRecord.getUri(), stickerRecord.getSize(), clearCompose);
SignalExecutors.BOUNDED.execute(() -> SignalExecutors.BOUNDED.execute(() ->
DatabaseFactory.getStickerDatabase(getApplicationContext()) DatabaseFactory.getStickerDatabase(getApplicationContext())
@ -2884,9 +2884,9 @@ public class ConversationActivity extends PassphraseRequiredActivity
); );
} }
private void sendSticker(@NonNull StickerLocator stickerLocator, @NonNull Uri uri, long size, boolean clearCompose) { private void sendSticker(@NonNull StickerLocator stickerLocator, @NonNull String contentType, @NonNull Uri uri, long size, boolean clearCompose) {
if (sendButton.getSelectedTransport().isSms()) { if (sendButton.getSelectedTransport().isSms()) {
Media media = new Media(uri, MediaUtil.IMAGE_WEBP, System.currentTimeMillis(), StickerSlide.WIDTH, StickerSlide.HEIGHT, size, 0, false, Optional.absent(), Optional.absent(), Optional.absent()); Media media = new Media(uri, contentType, System.currentTimeMillis(), StickerSlide.WIDTH, StickerSlide.HEIGHT, size, 0, false, Optional.absent(), Optional.absent(), Optional.absent());
Intent intent = MediaSendActivity.buildEditorIntent(this, Collections.singletonList(media), recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport()); Intent intent = MediaSendActivity.buildEditorIntent(this, Collections.singletonList(media), recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport());
startActivityForResult(intent, MEDIA_SENDER); startActivityForResult(intent, MEDIA_SENDER);
return; return;
@ -2897,7 +2897,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
boolean initiating = threadId == -1; boolean initiating = threadId == -1;
TransportOption transport = sendButton.getSelectedTransport(); TransportOption transport = sendButton.getSelectedTransport();
SlideDeck slideDeck = new SlideDeck(); SlideDeck slideDeck = new SlideDeck();
Slide stickerSlide = new StickerSlide(this, uri, size, stickerLocator); Slide stickerSlide = new StickerSlide(this, uri, size, stickerLocator, contentType);
slideDeck.addSlide(stickerSlide); slideDeck.addSlide(stickerSlide);

View File

@ -838,6 +838,7 @@ public class ConversationFragment extends LoggingFragment {
if (slide.hasSticker()) { if (slide.hasSticker()) {
composeIntent.putExtra(ConversationActivity.STICKER_EXTRA, slide.asAttachment().getSticker()); composeIntent.putExtra(ConversationActivity.STICKER_EXTRA, slide.asAttachment().getSticker());
composeIntent.setType(slide.asAttachment().getContentType());
} }
} }

View File

@ -46,6 +46,7 @@ public class StickerDatabase extends Database {
private static final String PACK_AUTHOR = "pack_author"; private static final String PACK_AUTHOR = "pack_author";
private static final String STICKER_ID = "sticker_id"; private static final String STICKER_ID = "sticker_id";
private static final String EMOJI = "emoji"; private static final String EMOJI = "emoji";
public static final String CONTENT_TYPE = "content_type";
private static final String COVER = "cover"; private static final String COVER = "cover";
private static final String PACK_ORDER = "pack_order"; private static final String PACK_ORDER = "pack_order";
private static final String INSTALLED = "installed"; private static final String INSTALLED = "installed";
@ -63,6 +64,7 @@ public class StickerDatabase extends Database {
COVER + " INTEGER, " + COVER + " INTEGER, " +
PACK_ORDER + " INTEGER, " + PACK_ORDER + " INTEGER, " +
EMOJI + " TEXT NOT NULL, " + EMOJI + " TEXT NOT NULL, " +
CONTENT_TYPE + " TEXT DEFAULT NULL, " +
LAST_USED + " INTEGER, " + LAST_USED + " INTEGER, " +
INSTALLED + " INTEGER," + INSTALLED + " INTEGER," +
FILE_PATH + " TEXT NOT NULL, " + FILE_PATH + " TEXT NOT NULL, " +
@ -94,6 +96,7 @@ public class StickerDatabase extends Database {
contentValues.put(PACK_AUTHOR, sticker.getPackAuthor()); contentValues.put(PACK_AUTHOR, sticker.getPackAuthor());
contentValues.put(STICKER_ID, sticker.getStickerId()); contentValues.put(STICKER_ID, sticker.getStickerId());
contentValues.put(EMOJI, sticker.getEmoji()); contentValues.put(EMOJI, sticker.getEmoji());
contentValues.put(CONTENT_TYPE, sticker.getContentType());
contentValues.put(COVER, sticker.isCover() ? 1 : 0); contentValues.put(COVER, sticker.isCover() ? 1 : 0);
contentValues.put(INSTALLED, sticker.isInstalled() ? 1 : 0); contentValues.put(INSTALLED, sticker.isInstalled() ? 1 : 0);
contentValues.put(FILE_PATH, fileInfo.getFile().getAbsolutePath()); contentValues.put(FILE_PATH, fileInfo.getFile().getAbsolutePath());
@ -460,6 +463,7 @@ public class StickerDatabase extends Database {
cursor.getString(cursor.getColumnIndexOrThrow(PACK_KEY)), cursor.getString(cursor.getColumnIndexOrThrow(PACK_KEY)),
cursor.getInt(cursor.getColumnIndexOrThrow(STICKER_ID)), cursor.getInt(cursor.getColumnIndexOrThrow(STICKER_ID)),
cursor.getString(cursor.getColumnIndexOrThrow(EMOJI)), cursor.getString(cursor.getColumnIndexOrThrow(EMOJI)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_TYPE)),
cursor.getLong(cursor.getColumnIndexOrThrow(FILE_LENGTH)), cursor.getLong(cursor.getColumnIndexOrThrow(FILE_LENGTH)),
cursor.getInt(cursor.getColumnIndexOrThrow(COVER)) == 1); cursor.getInt(cursor.getColumnIndexOrThrow(COVER)) == 1);
} }

View File

@ -144,8 +144,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int PINNED_CONVERSATIONS = 69; private static final int PINNED_CONVERSATIONS = 69;
private static final int MENTION_GLOBAL_SETTING_MIGRATION = 70; private static final int MENTION_GLOBAL_SETTING_MIGRATION = 70;
private static final int UNKNOWN_STORAGE_FIELDS = 71; private static final int UNKNOWN_STORAGE_FIELDS = 71;
private static final int STICKER_CONTENT_TYPE = 72;
private static final int DATABASE_VERSION = 71; private static final int DATABASE_VERSION = 72;
private static final String DATABASE_NAME = "signal.db"; private static final String DATABASE_NAME = "signal.db";
private final Context context; private final Context context;
@ -1013,6 +1014,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE recipient ADD COLUMN storage_proto TEXT DEFAULT NULL"); db.execSQL("ALTER TABLE recipient ADD COLUMN storage_proto TEXT DEFAULT NULL");
} }
if (oldVersion < STICKER_CONTENT_TYPE) {
db.execSQL("ALTER TABLE sticker ADD COLUMN content_type TEXT DEFAULT NULL");
}
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.database.model; package org.thoughtcrime.securesms.database.model;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class IncomingSticker { public class IncomingSticker {
@ -10,6 +11,7 @@ public class IncomingSticker {
private final String packAuthor; private final String packAuthor;
private final int stickerId; private final int stickerId;
private final String emoji; private final String emoji;
private final String contentType;
private final boolean isCover; private final boolean isCover;
private final boolean isInstalled; private final boolean isInstalled;
@ -19,6 +21,7 @@ public class IncomingSticker {
@NonNull String packAuthor, @NonNull String packAuthor,
int stickerId, int stickerId,
@NonNull String emoji, @NonNull String emoji,
@Nullable String contentType,
boolean isCover, boolean isCover,
boolean isInstalled) boolean isInstalled)
{ {
@ -28,6 +31,7 @@ public class IncomingSticker {
this.packAuthor = packAuthor; this.packAuthor = packAuthor;
this.stickerId = stickerId; this.stickerId = stickerId;
this.emoji = emoji; this.emoji = emoji;
this.contentType = contentType;
this.isCover = isCover; this.isCover = isCover;
this.isInstalled = isInstalled; this.isInstalled = isInstalled;
} }
@ -56,6 +60,10 @@ public class IncomingSticker {
return emoji; return emoji;
} }
public @Nullable String getContentType() {
return contentType;
}
public boolean isCover() { public boolean isCover() {
return isCover; return isCover;
} }

View File

@ -3,8 +3,10 @@ package org.thoughtcrime.securesms.database.model;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.util.MediaUtil;
import java.util.Objects; import java.util.Objects;
@ -18,6 +20,7 @@ public final class StickerRecord {
private final String packKey; private final String packKey;
private final int stickerId; private final int stickerId;
private final String emoji; private final String emoji;
private final String contentType;
private final long size; private final long size;
private final boolean isCover; private final boolean isCover;
@ -26,6 +29,7 @@ public final class StickerRecord {
@NonNull String packKey, @NonNull String packKey,
int stickerId, int stickerId,
@NonNull String emoji, @NonNull String emoji,
@Nullable String contentType,
long size, long size,
boolean isCover) boolean isCover)
{ {
@ -34,6 +38,7 @@ public final class StickerRecord {
this.packKey = packKey; this.packKey = packKey;
this.stickerId = stickerId; this.stickerId = stickerId;
this.emoji = emoji; this.emoji = emoji;
this.contentType = contentType;
this.size = size; this.size = size;
this.isCover = isCover; this.isCover = isCover;
} }
@ -62,6 +67,10 @@ public final class StickerRecord {
return emoji; return emoji;
} }
public @NonNull String getContentType() {
return contentType == null ? MediaUtil.IMAGE_WEBP : contentType;
}
public long getSize() { public long getSize() {
return size; return size;
} }
@ -81,11 +90,12 @@ public final class StickerRecord {
isCover == that.isCover && isCover == that.isCover &&
packId.equals(that.packId) && packId.equals(that.packId) &&
packKey.equals(that.packKey) && packKey.equals(that.packKey) &&
emoji.equals(that.emoji); emoji.equals(that.emoji) &&
Objects.equals(contentType, that.contentType);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(rowId, packId, packKey, stickerId, emoji, size, isCover); return Objects.hash(rowId, packId, packKey, stickerId, emoji, contentType, size, isCover);
} }
} }

View File

@ -1665,7 +1665,7 @@ public final class PushProcessMessageJob extends BaseJob {
if (stickerRecord != null) { if (stickerRecord != null) {
return Optional.of(new UriAttachment(stickerRecord.getUri(), return Optional.of(new UriAttachment(stickerRecord.getUri(),
stickerRecord.getUri(), stickerRecord.getUri(),
MediaUtil.IMAGE_WEBP, stickerRecord.getContentType(),
AttachmentDatabase.TRANSFER_PROGRESS_DONE, AttachmentDatabase.TRANSFER_PROGRESS_DONE,
stickerRecord.getSize(), stickerRecord.getSize(),
StickerSlide.WIDTH, StickerSlide.WIDTH,

View File

@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.model.Mention; import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.PartProgressEvent; import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.Job;
@ -283,9 +284,11 @@ public abstract class PushSendJob extends SendJob {
byte[] packId = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackId()); byte[] packId = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackId());
byte[] packKey = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackKey()); byte[] packKey = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackKey());
int stickerId = stickerAttachment.getSticker().getStickerId(); int stickerId = stickerAttachment.getSticker().getStickerId();
StickerRecord record = DatabaseFactory.getStickerDatabase(context).getSticker(stickerAttachment.getSticker().getPackId(), stickerId, false);
String emoji = record != null ? record.getEmoji() : null;
SignalServiceAttachment attachment = getAttachmentPointerFor(stickerAttachment); SignalServiceAttachment attachment = getAttachmentPointerFor(stickerAttachment);
return Optional.of(new SignalServiceDataMessage.Sticker(packId, packKey, stickerId, attachment)); return Optional.of(new SignalServiceDataMessage.Sticker(packId, packKey, stickerId, emoji, attachment));
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, "Failed to decode sticker id/key", e); Log.w(TAG, "Failed to decode sticker id/key", e);
return Optional.absent(); return Optional.absent();

View File

@ -29,6 +29,7 @@ public class StickerDownloadJob extends BaseJob {
private static final String KEY_PACK_AUTHOR = "pack_author"; private static final String KEY_PACK_AUTHOR = "pack_author";
private static final String KEY_STICKER_ID = "sticker_id"; private static final String KEY_STICKER_ID = "sticker_id";
private static final String KEY_EMOJI = "emoji"; private static final String KEY_EMOJI = "emoji";
private static final String KEY_CONTENT_TYPE = "content_type";
private static final String KEY_COVER = "cover"; private static final String KEY_COVER = "cover";
private static final String KEY_INSTALLED = "installed"; private static final String KEY_INSTALLED = "installed";
private static final String KEY_NOTIFY = "notify"; private static final String KEY_NOTIFY = "notify";
@ -59,6 +60,7 @@ public class StickerDownloadJob extends BaseJob {
.putString(KEY_PACK_AUTHOR, sticker.getPackAuthor()) .putString(KEY_PACK_AUTHOR, sticker.getPackAuthor())
.putInt(KEY_STICKER_ID, sticker.getStickerId()) .putInt(KEY_STICKER_ID, sticker.getStickerId())
.putString(KEY_EMOJI, sticker.getEmoji()) .putString(KEY_EMOJI, sticker.getEmoji())
.putString(KEY_CONTENT_TYPE, sticker.getContentType())
.putBoolean(KEY_COVER, sticker.isCover()) .putBoolean(KEY_COVER, sticker.isCover())
.putBoolean(KEY_INSTALLED, sticker.isInstalled()) .putBoolean(KEY_INSTALLED, sticker.isInstalled())
.putBoolean(KEY_NOTIFY, notify) .putBoolean(KEY_NOTIFY, notify)
@ -111,6 +113,7 @@ public class StickerDownloadJob extends BaseJob {
data.getString(KEY_PACK_AUTHOR), data.getString(KEY_PACK_AUTHOR),
data.getInt(KEY_STICKER_ID), data.getInt(KEY_STICKER_ID),
data.getString(KEY_EMOJI), data.getString(KEY_EMOJI),
data.getString(KEY_CONTENT_TYPE),
data.getBoolean(KEY_COVER), data.getBoolean(KEY_COVER),
data.getBoolean(KEY_INSTALLED)); data.getBoolean(KEY_INSTALLED));

View File

@ -135,6 +135,7 @@ public class StickerPackDownloadJob extends BaseJob {
manifest.getAuthor().or(""), manifest.getAuthor().or(""),
cover.getId(), cover.getId(),
"", "",
cover.getContentType(),
true, true,
!isReferencePack), !isReferencePack),
notify)); notify));
@ -151,6 +152,7 @@ public class StickerPackDownloadJob extends BaseJob {
manifest.getAuthor().or(""), manifest.getAuthor().or(""),
stickerInfo.getId(), stickerInfo.getId(),
stickerInfo.getEmoji(), stickerInfo.getEmoji(),
stickerInfo.getContentType(),
false, false,
true), true),
notify)); notify));

View File

@ -61,7 +61,6 @@ public class SignalGlideModule extends AppGlideModule {
@Override @Override
public void applyOptions(Context context, GlideBuilder builder) { public void applyOptions(Context context, GlideBuilder builder) {
builder.setLogLevel(Log.ERROR); builder.setLogLevel(Log.ERROR);
// builder.setDiskCache(new NoopDiskCacheFactory());
} }
@Override @Override

View File

@ -22,8 +22,8 @@ public class StickerSlide extends Slide {
super(context, attachment); super(context, attachment);
} }
public StickerSlide(Context context, Uri uri, long size, @NonNull StickerLocator stickerLocator) { public StickerSlide(Context context, Uri uri, long size, @NonNull StickerLocator stickerLocator, @NonNull String contentType) {
super(context, constructAttachmentFromUri(context, uri, MediaUtil.IMAGE_WEBP, size, WIDTH, HEIGHT, true, null, null, stickerLocator, null, null, false, false, false)); super(context, constructAttachmentFromUri(context, uri, contentType, size, WIDTH, HEIGHT, true, null, null, stickerLocator, null, null, false, false, false));
} }
@Override @Override
@ -41,6 +41,11 @@ public class StickerSlide extends Slide {
return true; return true;
} }
@Override
public boolean isBorderless() {
return true;
}
@Override @Override
public @NonNull String getContentDescription() { public @NonNull String getContentDescription() {
return context.getString(R.string.Slide_sticker); return context.getString(R.string.Slide_sticker);

View File

@ -314,6 +314,8 @@ public class ShareActivity extends PassphraseRequiredActivity
intent.putExtra(ConversationActivity.MEDIA_EXTRA, shareData.getMedia()); intent.putExtra(ConversationActivity.MEDIA_EXTRA, shareData.getMedia());
} else if (shareData != null && shareData.isForPrimitive()) { } else if (shareData != null && shareData.isForPrimitive()) {
Log.i(TAG, "Shared data is a primitive type."); Log.i(TAG, "Shared data is a primitive type.");
} else if (shareData == null && stickerExtra != null) {
intent.setType(getIntent().getType());
} else { } else {
Log.i(TAG, "Shared data was not external."); Log.i(TAG, "Shared data was not external.");
} }

View File

@ -4,6 +4,7 @@ import android.net.Uri;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.util.ArrayList; import java.util.ArrayList;
@ -66,17 +67,19 @@ public final class StickerManifest {
private final String packKey; private final String packKey;
private final int id; private final int id;
private final String emoji; private final String emoji;
private final String contentType;
private final Optional<Uri> uri; private final Optional<Uri> uri;
public Sticker(@NonNull String packId, @NonNull String packKey, int id, @NonNull String emoji) { public Sticker(@NonNull String packId, @NonNull String packKey, int id, @NonNull String emoji, @Nullable String contentType) {
this(packId, packKey, id, emoji, null); this(packId, packKey, id, emoji, contentType, null);
} }
public Sticker(@NonNull String packId, @NonNull String packKey, int id, @NonNull String emoji, @Nullable Uri uri) { public Sticker(@NonNull String packId, @NonNull String packKey, int id, @NonNull String emoji, @Nullable String contentType, @Nullable Uri uri) {
this.packId = packId; this.packId = packId;
this.packKey = packKey; this.packKey = packKey;
this.id = id; this.id = id;
this.emoji = emoji; this.emoji = emoji;
this.contentType = contentType;
this.uri = Optional.fromNullable(uri); this.uri = Optional.fromNullable(uri);
} }
@ -96,6 +99,10 @@ public final class StickerManifest {
return emoji; return emoji;
} }
public @Nullable String getContentType() {
return contentType;
}
public Optional<Uri> getUri() { public Optional<Uri> getUri() {
return uri; return uri;
} }

View File

@ -126,11 +126,11 @@ public final class StickerPackPreviewRepository {
@NonNull String packKey, @NonNull String packKey,
@NonNull SignalServiceStickerManifest.StickerInfo remoteSticker) @NonNull SignalServiceStickerManifest.StickerInfo remoteSticker)
{ {
return new StickerManifest.Sticker(packId, packKey, remoteSticker.getId(), remoteSticker.getEmoji()); return new StickerManifest.Sticker(packId, packKey, remoteSticker.getId(), remoteSticker.getEmoji(), remoteSticker.getContentType());
} }
private StickerManifest.Sticker toSticker(@NonNull StickerRecord record) { private StickerManifest.Sticker toSticker(@NonNull StickerRecord record) {
return new StickerManifest.Sticker(record.getPackId(), record.getPackKey(), record.getStickerId(), record.getEmoji(), record.getUri()); return new StickerManifest.Sticker(record.getPackId(), record.getPackKey(), record.getStickerId(), record.getEmoji(), record.getContentType(), record.getUri());
} }
static class StickerManifestResult { static class StickerManifestResult {

View File

@ -10,6 +10,8 @@ import android.widget.ImageView;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.GlideRequests;
@ -37,6 +39,7 @@ final class StickerPreviewPopup extends PopupWindow {
void presentSticker(@NonNull Object stickerGlideModel, @Nullable String emoji) { void presentSticker(@NonNull Object stickerGlideModel, @Nullable String emoji) {
emojiText.setText(emoji); emojiText.setText(emoji);
glideRequests.load(stickerGlideModel) glideRequests.load(stickerGlideModel)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(image); .into(image);
} }
} }

View File

@ -14,11 +14,14 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.Pair;
import java.lang.ref.WeakReference;
public class StickerRolloverTouchListener implements RecyclerView.OnItemTouchListener { public class StickerRolloverTouchListener implements RecyclerView.OnItemTouchListener {
private final StickerPreviewPopup popup; private final StickerPreviewPopup popup;
private final RolloverEventListener eventListener; private final RolloverEventListener eventListener;
private final RolloverStickerRetriever stickerRetriever; private final RolloverStickerRetriever stickerRetriever;
private WeakReference<View> currentView;
private boolean hoverMode; private boolean hoverMode;
StickerRolloverTouchListener(@NonNull Context context, StickerRolloverTouchListener(@NonNull Context context,
@ -29,6 +32,8 @@ public class StickerRolloverTouchListener implements RecyclerView.OnItemTouchLis
this.eventListener = eventListener; this.eventListener = eventListener;
this.stickerRetriever = stickerRetriever; this.stickerRetriever = stickerRetriever;
this.popup = new StickerPreviewPopup(context, glideRequests); this.popup = new StickerPreviewPopup(context, glideRequests);
this.currentView = new WeakReference<>(null);
popup.setAnimationStyle(R.style.StickerPopupAnimation); popup.setAnimationStyle(R.style.StickerPopupAnimation);
} }
@ -45,15 +50,19 @@ public class StickerRolloverTouchListener implements RecyclerView.OnItemTouchLis
hoverMode = false; hoverMode = false;
popup.dismiss(); popup.dismiss();
eventListener.onStickerPopupEnded(); eventListener.onStickerPopupEnded();
currentView.clear();
break; break;
default: default:
for (int i = 0, len = recyclerView.getChildCount(); i < len; i++) { for (int i = 0, len = recyclerView.getChildCount(); i < len; i++) {
View child = recyclerView.getChildAt(i); View child = recyclerView.getChildAt(i);
if (ViewUtil.isPointInsideView(recyclerView, motionEvent.getRawX(), motionEvent.getRawY()) && if (ViewUtil.isPointInsideView(recyclerView, motionEvent.getRawX(), motionEvent.getRawY()) &&
ViewUtil.isPointInsideView(child, motionEvent.getRawX(), motionEvent.getRawY())) ViewUtil.isPointInsideView(child, motionEvent.getRawX(), motionEvent.getRawY()) &&
child != currentView.get())
{ {
showStickerForView(recyclerView, child); showStickerForView(recyclerView, child);
currentView = new WeakReference<>(child);
break;
} }
} }
} }

View File

@ -3,7 +3,4 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sticker_keyboard_page_image" android:id="@+id/sticker_keyboard_page_image"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content" />
android:layout_marginTop="4dp">
</ImageView>

View File

@ -17,7 +17,7 @@
<ImageView <ImageView
android:id="@+id/sticker_install_cover" android:id="@+id/sticker_install_cover"
android:layout_width="wrap_content" android:layout_width="48dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
app:layout_constraintTop_toTopOf="@id/sticker_install_title" app:layout_constraintTop_toTopOf="@id/sticker_install_title"

View File

@ -218,11 +218,11 @@ public class SignalServiceMessageReceiver {
StickerProtos.Pack pack = StickerProtos.Pack.parseFrom(outputStream.toByteArray()); StickerProtos.Pack pack = StickerProtos.Pack.parseFrom(outputStream.toByteArray());
List<SignalServiceStickerManifest.StickerInfo> stickers = new ArrayList<>(pack.getStickersCount()); List<SignalServiceStickerManifest.StickerInfo> stickers = new ArrayList<>(pack.getStickersCount());
SignalServiceStickerManifest.StickerInfo cover = pack.hasCover() ? new SignalServiceStickerManifest.StickerInfo(pack.getCover().getId(), pack.getCover().getEmoji()) SignalServiceStickerManifest.StickerInfo cover = pack.hasCover() ? new SignalServiceStickerManifest.StickerInfo(pack.getCover().getId(), pack.getCover().getEmoji(), pack.getCover().getContentType())
: null; : null;
for (StickerProtos.Pack.Sticker sticker : pack.getStickersList()) { for (StickerProtos.Pack.Sticker sticker : pack.getStickersList()) {
stickers.add(new SignalServiceStickerManifest.StickerInfo(sticker.getId(), sticker.getEmoji())); stickers.add(new SignalServiceStickerManifest.StickerInfo(sticker.getId(), sticker.getEmoji(), sticker.getContentType()));
} }
return new SignalServiceStickerManifest(pack.getTitle(), pack.getAuthor(), cover, stickers); return new SignalServiceStickerManifest(pack.getTitle(), pack.getAuthor(), cover, stickers);

View File

@ -660,6 +660,7 @@ public class SignalServiceMessageSender {
stickerBuilder.setPackId(ByteString.copyFrom(message.getSticker().get().getPackId())); stickerBuilder.setPackId(ByteString.copyFrom(message.getSticker().get().getPackId()));
stickerBuilder.setPackKey(ByteString.copyFrom(message.getSticker().get().getPackKey())); stickerBuilder.setPackKey(ByteString.copyFrom(message.getSticker().get().getPackKey()));
stickerBuilder.setStickerId(message.getSticker().get().getStickerId()); stickerBuilder.setStickerId(message.getSticker().get().getStickerId());
stickerBuilder.setEmoji(message.getSticker().get().getEmoji());
if (message.getSticker().get().getAttachment().isStream()) { if (message.getSticker().get().getAttachment().isStream()) {
stickerBuilder.setData(createAttachmentPointer(message.getSticker().get().getAttachment().asStream())); stickerBuilder.setData(createAttachmentPointer(message.getSticker().get().getAttachment().asStream()));

View File

@ -738,6 +738,7 @@ public final class SignalServiceContent {
return new SignalServiceDataMessage.Sticker(sticker.getPackId().toByteArray(), return new SignalServiceDataMessage.Sticker(sticker.getPackId().toByteArray(),
sticker.getPackKey().toByteArray(), sticker.getPackKey().toByteArray(),
sticker.getStickerId(), sticker.getStickerId(),
sticker.getEmoji(),
createAttachmentPointer(sticker.getData())); createAttachmentPointer(sticker.getData()));
} }

View File

@ -449,12 +449,14 @@ public class SignalServiceDataMessage {
private final byte[] packId; private final byte[] packId;
private final byte[] packKey; private final byte[] packKey;
private final int stickerId; private final int stickerId;
private final String emoji;
private final SignalServiceAttachment attachment; private final SignalServiceAttachment attachment;
public Sticker(byte[] packId, byte[] packKey, int stickerId, SignalServiceAttachment attachment) { public Sticker(byte[] packId, byte[] packKey, int stickerId, String emoji, SignalServiceAttachment attachment) {
this.packId = packId; this.packId = packId;
this.packKey = packKey; this.packKey = packKey;
this.stickerId = stickerId; this.stickerId = stickerId;
this.emoji = emoji;
this.attachment = attachment; this.attachment = attachment;
} }
@ -470,6 +472,10 @@ public class SignalServiceDataMessage {
return stickerId; return stickerId;
} }
public String getEmoji() {
return emoji;
}
public SignalServiceAttachment getAttachment() { public SignalServiceAttachment getAttachment() {
return attachment; return attachment;
} }

View File

@ -39,10 +39,12 @@ public class SignalServiceStickerManifest {
public static final class StickerInfo { public static final class StickerInfo {
private final int id; private final int id;
private final String emoji; private final String emoji;
private final String contentType;
public StickerInfo(int id, String emoji) { public StickerInfo(int id, String emoji, String contentType) {
this.id = id; this.id = id;
this.emoji = emoji; this.emoji = emoji;
this.contentType = contentType;
} }
public int getId() { public int getId() {
@ -52,5 +54,9 @@ public class SignalServiceStickerManifest {
public String getEmoji() { public String getEmoji() {
return emoji; return emoji;
} }
public String getContentType() {
return contentType;
}
} }
} }

View File

@ -215,6 +215,7 @@ message DataMessage {
optional bytes packKey = 2; optional bytes packKey = 2;
optional uint32 stickerId = 3; optional uint32 stickerId = 3;
optional AttachmentPointer data = 4; optional AttachmentPointer data = 4;
optional string emoji = 5;
} }
message Reaction { message Reaction {

View File

@ -14,6 +14,7 @@ message Pack {
message Sticker { message Sticker {
optional uint32 id = 1; optional uint32 id = 1;
optional string emoji = 2; optional string emoji = 2;
optional string contentType = 3;
} }
optional string title = 1; optional string title = 1;