diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a6cc1bd48f..9b0d5f7750 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -336,7 +336,7 @@
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
-
-
+
-
-
-
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9808b7a2b2..2a67b73f8e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -254,6 +254,7 @@
Deleting messages...
Original message not found
Original message no longer available
+ Failed to open message
There is no browser installed on your device.
diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java
index 7d166bdb84..8cd621f99f 100644
--- a/src/org/thoughtcrime/securesms/ApplicationContext.java
+++ b/src/org/thoughtcrime/securesms/ApplicationContext.java
@@ -62,7 +62,7 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener;
-import org.thoughtcrime.securesms.revealable.RevealableMessageManager;
+import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager;
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
@@ -92,7 +92,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
private static final String TAG = ApplicationContext.class.getSimpleName();
private ExpiringMessageManager expiringMessageManager;
- private RevealableMessageManager revealableMessageManager;
+ private ViewOnceMessageManager viewOnceMessageManager;
private TypingStatusRepository typingStatusRepository;
private TypingStatusSender typingStatusSender;
private JobManager jobManager;
@@ -157,8 +157,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
return expiringMessageManager;
}
- public RevealableMessageManager getRevealableMessageManager() {
- return revealableMessageManager;
+ public ViewOnceMessageManager getViewOnceMessageManager() {
+ return viewOnceMessageManager;
}
public TypingStatusRepository getTypingStatusRepository() {
@@ -252,7 +252,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
private void initializeRevealableMessageManager() {
- this.revealableMessageManager = new RevealableMessageManager(this);
+ this.viewOnceMessageManager = new ViewOnceMessageManager(this);
}
private void initializeTypingStatusRepository() {
diff --git a/src/org/thoughtcrime/securesms/BindableConversationItem.java b/src/org/thoughtcrime/securesms/BindableConversationItem.java
index fdded7b42c..88d5657177 100644
--- a/src/org/thoughtcrime/securesms/BindableConversationItem.java
+++ b/src/org/thoughtcrime/securesms/BindableConversationItem.java
@@ -38,7 +38,7 @@ public interface BindableConversationItem extends Unbindable {
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms);
void onStickerClicked(@NonNull StickerLocator stickerLocator);
- void onRevealableMessageClicked(@NonNull MmsMessageRecord messageRecord);
+ void onViewOnceMessageClicked(@NonNull MmsMessageRecord messageRecord);
void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView);
void onAddToContactsClicked(@NonNull Contact contact);
void onMessageSharedContactClicked(@NonNull List choices);
diff --git a/src/org/thoughtcrime/securesms/ShareActivity.java b/src/org/thoughtcrime/securesms/ShareActivity.java
index 578ecd4c2e..0bd2c873bd 100644
--- a/src/org/thoughtcrime/securesms/ShareActivity.java
+++ b/src/org/thoughtcrime/securesms/ShareActivity.java
@@ -340,7 +340,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
.forData(inputStream, fileSize == null ? 0 : fileSize)
.withMimeType(mimeType)
.withFileName(fileName)
- .createForMultipleSessionsOnDisk(context, e -> Log.w(TAG, "Failed to write to disk.", e));
+ .createForMultipleSessionsOnDisk(context);
} catch (IOException ioe) {
Log.w(TAG, ioe);
return null;
diff --git a/src/org/thoughtcrime/securesms/attachments/TombstoneAttachment.java b/src/org/thoughtcrime/securesms/attachments/TombstoneAttachment.java
index 79feb548c3..ed3b3f6e0d 100644
--- a/src/org/thoughtcrime/securesms/attachments/TombstoneAttachment.java
+++ b/src/org/thoughtcrime/securesms/attachments/TombstoneAttachment.java
@@ -7,6 +7,12 @@ import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
+/**
+ * An attachment that represents where an attachment used to be. Useful when you need to know that
+ * a message had an attachment and some metadata about it (like the contentType), even though the
+ * underlying media no longer exists. An example usecase would be view-once messages, so that we can
+ * quote them and know their contentType even though the media has been deleted.
+ */
public class TombstoneAttachment extends Attachment {
public TombstoneAttachment(@NonNull String contentType, boolean quote) {
diff --git a/src/org/thoughtcrime/securesms/audio/AudioRecorder.java b/src/org/thoughtcrime/securesms/audio/AudioRecorder.java
index bb390f36c7..0eeb48cff0 100644
--- a/src/org/thoughtcrime/securesms/audio/AudioRecorder.java
+++ b/src/org/thoughtcrime/securesms/audio/AudioRecorder.java
@@ -50,7 +50,7 @@ public class AudioRecorder {
captureUri = BlobProvider.getInstance()
.forData(new ParcelFileDescriptor.AutoCloseInputStream(fds[0]), 0)
.withMimeType(MediaUtil.AUDIO_AAC)
- .createForSingleSessionOnDisk(context, e -> Log.w(TAG, "Error during recording", e));
+ .createForSingleSessionOnDiskAsync(context, () -> Log.i(TAG, "Write successful."), e -> Log.w(TAG, "Error during recording", e));
audioCodec = new AudioCodec();
audioCodec.start(new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]));
diff --git a/src/org/thoughtcrime/securesms/backup/FullBackupExporter.java b/src/org/thoughtcrime/securesms/backup/FullBackupExporter.java
index c698a5dfd3..0ffe1a40a5 100644
--- a/src/org/thoughtcrime/securesms/backup/FullBackupExporter.java
+++ b/src/org/thoughtcrime/securesms/backup/FullBackupExporter.java
@@ -27,7 +27,6 @@ import org.thoughtcrime.securesms.database.OneTimePreKeyDatabase;
import org.thoughtcrime.securesms.database.SearchDatabase;
import org.thoughtcrime.securesms.database.SessionDatabase;
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
-import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
@@ -254,19 +253,19 @@ public class FullBackupExporter extends FullBackupBase {
}
private static boolean isNonExpiringMessage(@NonNull Cursor cursor) {
- return cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 &&
- cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_DURATION)) <= 0;
+ return cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 &&
+ cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) <= 0;
}
private static boolean isForNonExpiringMessage(@NonNull SQLiteDatabase db, long mmsId) {
- String[] columns = new String[] { MmsDatabase.EXPIRES_IN, MmsDatabase.REVEAL_DURATION };
+ String[] columns = new String[] { MmsDatabase.EXPIRES_IN, MmsDatabase.VIEW_ONCE};
String where = MmsDatabase.ID + " = ?";
String[] args = new String[] { String.valueOf(mmsId) };
try (Cursor mmsCursor = db.query(MmsDatabase.TABLE_NAME, columns, where, args, null, null, null)) {
if (mmsCursor != null && mmsCursor.moveToFirst()) {
- return mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN)) == 0 &&
- mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_DURATION)) == 0;
+ return mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN)) == 0 &&
+ mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) == 0;
}
}
diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java
index 3934fedbae..a088e737f2 100644
--- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java
+++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java
@@ -542,8 +542,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
boolean initiating = threadId == -1;
TransportOption transport = data.getParcelableExtra(MediaSendActivity.EXTRA_TRANSPORT);
String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
- long revealDuration = data.getLongExtra(MediaSendActivity.EXTRA_REVEAL_DURATION, 0);
- QuoteModel quote = (revealDuration == 0) ? inputPanel.getQuote().orNull() : null;
+ boolean viewOnce = data.getBooleanExtra(MediaSendActivity.EXTRA_VIEW_ONCE, false);
+ QuoteModel quote = viewOnce ? inputPanel.getQuote().orNull() : null;
SlideDeck slideDeck = new SlideDeck();
if (transport == null) {
@@ -575,7 +575,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
Collections.emptyList(),
Collections.emptyList(),
expiresIn,
- revealDuration,
+ viewOnce,
subscriptionId,
initiating,
true).addListener(new AssertedSuccessListener() {
@@ -1813,7 +1813,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
long expiresIn = recipient.getExpireMessages() * 1000L;
boolean initiating = threadId == -1;
- sendMediaMessage(isSmsForced(), "", attachmentManager.buildSlideDeck(), null, contacts, Collections.emptyList(), expiresIn, 0, subscriptionId, initiating, false);
+ sendMediaMessage(isSmsForced(), "", attachmentManager.buildSlideDeck(), null, contacts, Collections.emptyList(), expiresIn, false, subscriptionId, initiating, false);
}
private void selectContactInfo(ContactData contactData) {
@@ -2135,7 +2135,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else if (!forceSms && identityRecords.isUntrusted()) {
handleUntrustedRecipients();
} else if (isMediaMessage) {
- sendMediaMessage(forceSms, expiresIn, 0, subscriptionId, initiating);
+ sendMediaMessage(forceSms, expiresIn, false, subscriptionId, initiating);
} else {
sendTextMessage(forceSms, expiresIn, subscriptionId, initiating);
}
@@ -2151,11 +2151,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
- private void sendMediaMessage(final boolean forceSms, final long expiresIn, final long revealDuration, final int subscriptionId, boolean initiating)
+ private void sendMediaMessage(final boolean forceSms, final long expiresIn, final boolean viewOnce, final int subscriptionId, boolean initiating)
throws InvalidMessageException
{
Log.i(TAG, "Sending media message...");
- sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), inputPanel.getQuote().orNull(), Collections.emptyList(), linkPreviewViewModel.getActiveLinkPreviews(), expiresIn, revealDuration, subscriptionId, initiating, true);
+ sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), inputPanel.getQuote().orNull(), Collections.emptyList(), linkPreviewViewModel.getActiveLinkPreviews(), expiresIn, viewOnce, subscriptionId, initiating, true);
}
private ListenableFuture sendMediaMessage(final boolean forceSms,
@@ -2165,7 +2165,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
List contacts,
List previews,
final long expiresIn,
- final long revealDuration,
+ final boolean viewOnce,
final int subscriptionId,
final boolean initiating,
final boolean clearComposeBox)
@@ -2184,7 +2184,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
- OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, revealDuration, distributionType, quote, contacts, previews);
+ OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, viewOnce, distributionType, quote, contacts, previews);
final SettableFuture future = new SettableFuture<>();
final Context context = getApplicationContext();
@@ -2385,7 +2385,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
SlideDeck slideDeck = new SlideDeck();
slideDeck.addSlide(audioSlide);
- sendMediaMessage(forceSms, "", slideDeck, inputPanel.getQuote().orNull(), Collections.emptyList(), Collections.emptyList(), expiresIn, 0, subscriptionId, initiating, true).addListener(new AssertedSuccessListener() {
+ sendMediaMessage(forceSms, "", slideDeck, inputPanel.getQuote().orNull(), Collections.emptyList(), Collections.emptyList(), expiresIn, false, subscriptionId, initiating, true).addListener(new AssertedSuccessListener() {
@Override
public void onSuccess(Void nothing) {
new AsyncTask() {
@@ -2513,7 +2513,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
slideDeck.addSlide(stickerSlide);
- sendMediaMessage(transport.isSms(), "", slideDeck, null, Collections.emptyList(), Collections.emptyList(), expiresIn, 0, subscriptionId, initiating, clearCompose);
+ sendMediaMessage(transport.isSms(), "", slideDeck, null, Collections.emptyList(), Collections.emptyList(), expiresIn, false, subscriptionId, initiating, clearCompose);
}
@@ -2696,7 +2696,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else {
SlideDeck slideDeck = messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck();
- if (messageRecord.isMms() && ((MmsMessageRecord) messageRecord).getRevealDuration() > 0 && slideDeck.getSlides().size() > 0) {
+ if (messageRecord.isMms() && ((MmsMessageRecord) messageRecord).isViewOnce() && slideDeck.getSlides().size() > 0) {
Attachment attachment = new TombstoneAttachment(slideDeck.getSlides().get(0).getContentType(), true);
slideDeck = new SlideDeck();
slideDeck.addSlide(MediaUtil.getSlideForAttachment(this, attachment));
diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java
index 4ed11fed3c..1b4d10f488 100644
--- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java
+++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java
@@ -79,7 +79,7 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
-import org.thoughtcrime.securesms.jobs.MultiDeviceRevealUpdateJob;
+import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
@@ -89,9 +89,10 @@ import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.profiles.UnknownSenderView;
+import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.revealable.RevealableMessageActivity;
-import org.thoughtcrime.securesms.revealable.RevealableUtil;
+import org.thoughtcrime.securesms.revealable.ViewOnceMessageActivity;
+import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.stickers.StickerLocator;
@@ -102,6 +103,7 @@ import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
+import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -963,35 +965,46 @@ public class ConversationFragment extends Fragment
}
@Override
- public void onRevealableMessageClicked(@NonNull MmsMessageRecord messageRecord) {
- if (messageRecord.getRevealDuration() == 0) {
+ public void onViewOnceMessageClicked(@NonNull MmsMessageRecord messageRecord) {
+ if (!messageRecord.isViewOnce()) {
throw new AssertionError("Non-revealable message clicked.");
}
- if (messageRecord.getRevealStartTime() == 0) {
- SimpleTask.run(getLifecycle(), () -> {
- if (!messageRecord.isOutgoing()) {
- Log.i(TAG, "Marking revealable message as opened.");
-
- DatabaseFactory.getMmsDatabase(requireContext()).markRevealStarted(messageRecord.getId());
-
- ApplicationContext.getInstance(requireContext())
- .getRevealableMessageManager()
- .scheduleIfNecessary();
-
- ApplicationContext.getInstance(requireContext())
- .getJobManager()
- .add(new MultiDeviceRevealUpdateJob(new MessagingDatabase.SyncMessageId(messageRecord.getIndividualRecipient().getAddress(), messageRecord.getDateSent())));
- } else {
- Log.i(TAG, "Opening your own revealable message. It will automatically be marked as opened when it is sent.");
- }
- return null;
- }, (nothing) -> {
- startActivity(RevealableMessageActivity.getIntent(requireContext(), messageRecord.getId()));
- });
- } else if (RevealableUtil.isViewable(messageRecord)) {
- startActivity(RevealableMessageActivity.getIntent(requireContext(), messageRecord.getId()));
+ if (!ViewOnceUtil.isViewable(messageRecord)) {
+ Log.w(TAG, "View-once photo is not viewable!");
+ return;
}
+
+ SimpleTask.run(getLifecycle(), () -> {
+ Log.i(TAG, "Copying the view-once photo to temp storage and deleting underlying media.");
+
+ try {
+ InputStream inputStream = PartAuthority.getAttachmentStream(requireContext(), messageRecord.getSlideDeck().getThumbnailSlide().getUri());
+ Uri tempUri = BlobProvider.getInstance().forData(inputStream, 0).createForSingleSessionOnDisk(requireContext());
+
+ DatabaseFactory.getAttachmentDatabase(requireContext()).deleteAttachmentFilesForMessage(messageRecord.getId());
+
+ ApplicationContext.getInstance(requireContext())
+ .getViewOnceMessageManager()
+ .scheduleIfNecessary();
+
+ ApplicationContext.getInstance(requireContext())
+ .getJobManager()
+ .add(new MultiDeviceViewOnceOpenJob(new MessagingDatabase.SyncMessageId(messageRecord.getIndividualRecipient().getAddress(), messageRecord.getDateSent())));
+
+ return tempUri;
+ } catch (IOException e) {
+ return null;
+ }
+ }, (uri) -> {
+ if (uri != null) {
+ startActivity(ViewOnceMessageActivity.getIntent(requireContext(), messageRecord.getId(), uri));
+ } else {
+ Log.w(TAG, "Failed to open view-once photo. Showing a toast and deleting the attachments for the message just in case.");
+ Toast.makeText(requireContext(), R.string.ConversationFragment_failed_to_open_message, Toast.LENGTH_SHORT).show();
+ SignalExecutors.BOUNDED.execute(() -> DatabaseFactory.getAttachmentDatabase(requireContext()).deleteAttachmentFilesForMessage(messageRecord.getId()));
+ }
+ });
}
@Override
diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java
index ee8b44c974..b6ae879d10 100644
--- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java
@@ -68,7 +68,7 @@ import org.thoughtcrime.securesms.components.DocumentView;
import org.thoughtcrime.securesms.components.LinkPreviewView;
import org.thoughtcrime.securesms.components.Outliner;
import org.thoughtcrime.securesms.components.QuoteView;
-import org.thoughtcrime.securesms.revealable.RevealableMessageView;
+import org.thoughtcrime.securesms.revealable.ViewOnceMessageView;
import org.thoughtcrime.securesms.components.SharedContactView;
import org.thoughtcrime.securesms.components.StickerView;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
@@ -99,7 +99,7 @@ import org.thoughtcrime.securesms.mms.SlidesClickedListener;
import org.thoughtcrime.securesms.mms.TextSlide;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
-import org.thoughtcrime.securesms.revealable.RevealableUtil;
+import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
import org.thoughtcrime.securesms.stickers.StickerUrl;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicTheme;
@@ -163,7 +163,7 @@ public class ConversationItem extends LinearLayout
private Stub sharedContactStub;
private Stub linkPreviewStub;
private Stub stickerStub;
- private Stub revealableStub;
+ private Stub revealableStub;
private @Nullable EventListener eventListener;
private int defaultBubbleColor;
@@ -175,7 +175,7 @@ public class ConversationItem extends LinearLayout
private final SharedContactEventListener sharedContactEventListener = new SharedContactEventListener();
private final SharedContactClickListener sharedContactClickListener = new SharedContactClickListener();
private final LinkPreviewClickListener linkPreviewClickListener = new LinkPreviewClickListener();
- private final RevealableMessageClickListener revealableClickListener = new RevealableMessageClickListener();
+ private final ViewOnceMessageClickListener revealableClickListener = new ViewOnceMessageClickListener();
private final Context context;
@@ -314,7 +314,7 @@ public class ConversationItem extends LinearLayout
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
- if (!messageRecord.isOutgoing() && hasRevealableMessage(messageRecord) && RevealableUtil.isRevealExpired((MmsMessageRecord) messageRecord)) {
+ if (!messageRecord.isOutgoing() && isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord)) {
outliner.setColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_text_secondary_color));
outliner.draw(canvas, bodyBubble.getTop() + getPaddingTop(), bodyBubble.getRight(), bodyBubble.getBottom() + getPaddingTop(), bodyBubble.getLeft());
}
@@ -324,7 +324,7 @@ public class ConversationItem extends LinearLayout
int availableWidth;
if (hasAudio(messageRecord)) {
availableWidth = audioViewStub.get().getMeasuredWidth() + ViewUtil.getLeftMargin(audioViewStub.get()) + ViewUtil.getRightMargin(audioViewStub.get());
- } else if (!hasRevealableMessage(messageRecord) && (hasThumbnail(messageRecord) || hasBigImageLinkPreview(messageRecord))) {
+ } else if (!isViewOnceMessage(messageRecord) && (hasThumbnail(messageRecord) || hasBigImageLinkPreview(messageRecord))) {
availableWidth = mediaThumbnailStub.get().getMeasuredWidth();
} else {
availableWidth = bodyBubble.getMeasuredWidth() - bodyBubble.getPaddingLeft() - bodyBubble.getPaddingRight();
@@ -361,7 +361,7 @@ public class ConversationItem extends LinearLayout
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
footer.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_text_secondary_color));
footer.setIconColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_icon_color));
- } else if (hasRevealableMessage(messageRecord) && RevealableUtil.isRevealExpired((MmsMessageRecord) messageRecord)) {
+ } else if (isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord)) {
bodyBubble.getBackground().setColorFilter(ThemeUtil.getThemedColor(context, R.attr.conversation_item_reveal_viewed_background_color), PorterDuff.Mode.MULTIPLY);
footer.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_text_secondary_color));
footer.setIconColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_icon_color));
@@ -440,7 +440,7 @@ public class ConversationItem extends LinearLayout
!hasDocument(messageRecord) &&
!hasSharedContact(messageRecord) &&
!hasSticker(messageRecord) &&
- !hasRevealableMessage(messageRecord);
+ !isViewOnceMessage(messageRecord);
}
private boolean hasDocument(MessageRecord messageRecord) {
@@ -477,8 +477,8 @@ public class ConversationItem extends LinearLayout
!StickerUrl.isValidShareLink(linkPreview.getUrl());
}
- private boolean hasRevealableMessage(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord) messageRecord).getRevealDuration() > 0;
+ private boolean isViewOnceMessage(MessageRecord messageRecord) {
+ return messageRecord.isMms() && ((MmsMessageRecord) messageRecord).isViewOnce();
}
private void setBodyText(MessageRecord messageRecord, @Nullable String searchQuery) {
@@ -512,7 +512,7 @@ public class ConversationItem extends LinearLayout
{
boolean showControls = !messageRecord.isFailed();
- if (hasRevealableMessage(messageRecord)) {
+ if (isViewOnceMessage(messageRecord)) {
revealableStub.get().setVisibility(VISIBLE);
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
@@ -928,7 +928,7 @@ public class ConversationItem extends LinearLayout
}
private void setGroupAuthorColor(@NonNull MessageRecord messageRecord) {
- if (!messageRecord.isOutgoing() && hasRevealableMessage(messageRecord) && RevealableUtil.isRevealExpired((MmsMessageRecord) messageRecord)) {
+ if (!messageRecord.isOutgoing() && isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord)) {
groupSender.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_sticker_author_color));
groupSenderProfileName.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_sticker_author_color));
} else if (hasSticker(messageRecord)) {
@@ -1169,13 +1169,13 @@ public class ConversationItem extends LinearLayout
}
}
- private class RevealableMessageClickListener implements View.OnClickListener {
+ private class ViewOnceMessageClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
- RevealableMessageView revealView = (RevealableMessageView) view;
+ ViewOnceMessageView revealView = (ViewOnceMessageView) view;
- if (eventListener != null && batchSelected.isEmpty() && messageRecord.isMms() && RevealableUtil.isViewable((MmsMessageRecord) messageRecord)) {
- eventListener.onRevealableMessageClicked((MmsMessageRecord) messageRecord);
+ if (eventListener != null && batchSelected.isEmpty() && messageRecord.isMms() && ViewOnceUtil.isViewable((MmsMessageRecord) messageRecord)) {
+ eventListener.onViewOnceMessageClicked((MmsMessageRecord) messageRecord);
} else if (batchSelected.isEmpty() && messageRecord.isMms() && revealView.requiresTapToDownload((MmsMessageRecord) messageRecord)) {
singleDownloadClickListener.onClick(view, ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlide());
} else {
diff --git a/src/org/thoughtcrime/securesms/database/MediaDatabase.java b/src/org/thoughtcrime/securesms/database/MediaDatabase.java
index d169f26568..7ba327c8da 100644
--- a/src/org/thoughtcrime/securesms/database/MediaDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/MediaDatabase.java
@@ -47,7 +47,7 @@ public class MediaDatabase extends Database {
+ "WHERE " + AttachmentDatabase.MMS_ID + " IN (SELECT " + MmsSmsColumns.ID
+ " FROM " + MmsDatabase.TABLE_NAME
+ " WHERE " + MmsDatabase.THREAD_ID + " = ?) AND (%s) AND "
- + MmsDatabase.REVEAL_DURATION + " = 0 AND "
+ + MmsDatabase.VIEW_ONCE + " = 0 AND "
+ AttachmentDatabase.DATA + " IS NOT NULL AND "
+ AttachmentDatabase.QUOTE + " = 0 AND "
+ AttachmentDatabase.STICKER_PACK_ID + " IS NULL "
diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java
index 53ded94af1..8fdafe582c 100644
--- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java
@@ -63,8 +63,8 @@ import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
-import org.thoughtcrime.securesms.revealable.RevealExpirationInfo;
-import org.thoughtcrime.securesms.revealable.RevealableUtil;
+import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
+import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@@ -109,8 +109,7 @@ public class MmsDatabase extends MessagingDatabase {
static final String SHARED_CONTACTS = "shared_contacts";
static final String LINK_PREVIEWS = "previews";
- public static final String REVEAL_DURATION = "reveal_duration";
- public static final String REVEAL_START_TIME = "reveal_start_time";
+ public static final String VIEW_ONCE = "reveal_duration";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
THREAD_ID + " INTEGER, " + DATE_SENT + " INTEGER, " + DATE_RECEIVED + " INTEGER, " + MESSAGE_BOX + " INTEGER, " +
@@ -131,7 +130,7 @@ public class MmsDatabase extends MessagingDatabase {
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + QUOTE_ID + " INTEGER DEFAULT 0, " +
QUOTE_AUTHOR + " TEXT, " + QUOTE_BODY + " TEXT, " + QUOTE_ATTACHMENT + " INTEGER DEFAULT -1, " +
QUOTE_MISSING + " INTEGER DEFAULT 0, " + SHARED_CONTACTS + " TEXT, " + UNIDENTIFIED + " INTEGER DEFAULT 0, " +
- LINK_PREVIEWS + " TEXT, " + REVEAL_DURATION + " INTEGER DEFAULT 0, " + REVEAL_START_TIME + " INTEGER DEFAULT 0);";
+ LINK_PREVIEWS + " TEXT, " + VIEW_ONCE + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
@@ -152,7 +151,7 @@ public class MmsDatabase extends MessagingDatabase {
BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_ID,
DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED, QUOTE_ID, QUOTE_AUTHOR, QUOTE_BODY, QUOTE_ATTACHMENT, QUOTE_MISSING,
- SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, REVEAL_DURATION, REVEAL_START_TIME,
+ SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, VIEW_ONCE,
"json_group_array(json_object(" +
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
@@ -437,60 +436,6 @@ public class MmsDatabase extends MessagingDatabase {
notifyConversationListeners(threadId);
}
- public void markRevealStarted(long messageId) {
- markRevealStarted(messageId, System.currentTimeMillis());
- }
-
- public void markRevealStarted(long messageId, long startTime) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(REVEAL_START_TIME, startTime);
-
- SQLiteDatabase db = databaseHelper.getWritableDatabase();
- db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(messageId)});
-
- long threadId = getThreadIdForMessage(messageId);
- notifyConversationListeners(threadId);
- }
-
- public List markRevealStarted(@NonNull SyncMessageId messageId, long proposedStartTime) {
- SQLiteDatabase db = databaseHelper.getWritableDatabase();
- List expirationInfos = new LinkedList<>();
-
- String[] projection = new String[] { ID, ADDRESS, THREAD_ID, DATE_SENT, DATE_RECEIVED, REVEAL_DURATION, REVEAL_START_TIME };
- String selection = DATE_SENT + " = ?";
- String[] args = new String[] { String.valueOf(messageId.getTimetamp()) };
-
- try (Cursor cursor = db.query(TABLE_NAME, projection, selection, args, null, null, null)) {
- while (cursor != null && cursor.moveToNext()) {
- Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
- Address ourAddress = messageId.getAddress();
-
- if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
- long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
- long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
- long receiveTime = cursor.getLong(cursor.getColumnIndexOrThrow(DATE_RECEIVED));
- long revealDuration = cursor.getLong(cursor.getColumnIndexOrThrow(REVEAL_DURATION));
- long revealStartTime = cursor.getLong(cursor.getColumnIndexOrThrow(REVEAL_START_TIME));
-
- revealStartTime = revealStartTime > 0 ? Math.min(proposedStartTime, revealStartTime) : proposedStartTime;
- revealStartTime = Math.min(revealStartTime, System.currentTimeMillis());
-
- ContentValues values = new ContentValues();
-
- values.put(REVEAL_START_TIME, revealStartTime);
- expirationInfos.add(new RevealExpirationInfo(id, receiveTime, revealStartTime, revealDuration));
-
- db.update(TABLE_NAME, values, ID_WHERE, new String[] { String.valueOf(id) });
-
- DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
- notifyConversationListeners(threadId);
- }
- }
- }
-
- return expirationInfos;
- }
-
public void markAsNotified(long id) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
@@ -668,7 +613,7 @@ public class MmsDatabase extends MessagingDatabase {
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
- long revealDuration = cursor.getLong(cursor.getColumnIndexOrThrow(REVEAL_DURATION));
+ boolean viewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(VIEW_ONCE)) == 1;
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
int distributionType = DatabaseFactory.getThreadDatabase(context).getDistributionType(threadId);
@@ -715,12 +660,12 @@ public class MmsDatabase extends MessagingDatabase {
}
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
- return new OutgoingGroupMediaMessage(recipient, body, attachments, timestamp, 0, 0, quote, contacts, previews);
+ return new OutgoingGroupMediaMessage(recipient, body, attachments, timestamp, 0, false, quote, contacts, previews);
} else if (Types.isExpirationTimerUpdate(outboxType)) {
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
}
- OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, revealDuration, distributionType, quote, contacts, previews, networkFailures, mismatches);
+ OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, viewOnce, distributionType, quote, contacts, previews, networkFailures, mismatches);
if (Types.isSecureType(outboxType)) {
return new OutgoingSecureMediaMessage(message);
@@ -824,7 +769,7 @@ public class MmsDatabase extends MessagingDatabase {
contentValues.put(READ, 1);
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
contentValues.put(EXPIRES_IN, request.getExpiresIn());
- contentValues.put(REVEAL_DURATION, request.getRevealDuration());
+ contentValues.put(VIEW_ONCE, request.isViewOnce());
List attachments = new LinkedList<>();
@@ -892,7 +837,7 @@ public class MmsDatabase extends MessagingDatabase {
contentValues.put(PART_COUNT, retrieved.getAttachments().size());
contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
- contentValues.put(REVEAL_DURATION, retrieved.getRevealDuration());
+ contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0);
contentValues.put(READ, retrieved.isExpirationUpdate() ? 1 : 0);
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
@@ -1048,7 +993,7 @@ public class MmsDatabase extends MessagingDatabase {
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
contentValues.put(EXPIRES_IN, message.getExpiresIn());
- contentValues.put(REVEAL_DURATION, message.getRevealDuration());
+ contentValues.put(VIEW_ONCE, message.isViewOnce());
contentValues.put(ADDRESS, message.getRecipient().getAddress().serialize());
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(Long::longValue).sum());
contentValues.put(READ_RECEIPT_COUNT, Stream.of(earlyReadReceipts.values()).mapToLong(Long::longValue).sum());
@@ -1307,34 +1252,31 @@ public class MmsDatabase extends MessagingDatabase {
database.delete(TABLE_NAME, null, null);
}
- public @Nullable RevealExpirationInfo getNearestExpiringRevealableMessage() {
+ public @Nullable
+ ViewOnceExpirationInfo getNearestExpiringViewOnceMessage() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
- RevealExpirationInfo info = null;
+ ViewOnceExpirationInfo info = null;
long nearestExpiration = Long.MAX_VALUE;
String query = "SELECT " +
TABLE_NAME + "." + ID + ", " +
- REVEAL_DURATION + ", " +
- REVEAL_START_TIME + ", " +
+ VIEW_ONCE + ", " +
DATE_RECEIVED + " " +
"FROM " + TABLE_NAME + " INNER JOIN " + AttachmentDatabase.TABLE_NAME + " " +
"ON " + TABLE_NAME + "." + ID + " = " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " " +
"WHERE " +
- REVEAL_DURATION + " > 0 AND " +
+ VIEW_ONCE + " > 0 AND " +
"(" + AttachmentDatabase.DATA + " NOT NULL OR " + AttachmentDatabase.TRANSFER_STATE + " != ?)";
String[] args = new String[] { String.valueOf(AttachmentDatabase.TRANSFER_PROGRESS_DONE) };
try (Cursor cursor = db.rawQuery(query, args)) {
while (cursor != null && cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
- long revealDuration = cursor.getLong(cursor.getColumnIndexOrThrow(REVEAL_DURATION));
- long revealStartTime = cursor.getLong(cursor.getColumnIndexOrThrow(REVEAL_START_TIME));
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(DATE_RECEIVED));
- long expiresAt = revealStartTime > 0 ? revealStartTime + revealDuration
- : dateReceived + RevealableUtil.MAX_LIFESPAN;
+ long expiresAt = dateReceived + ViewOnceUtil.MAX_LIFESPAN;
if (info == null || expiresAt < nearestExpiration) {
- info = new RevealExpirationInfo(id, dateReceived, revealStartTime, revealDuration);
+ info = new ViewOnceExpirationInfo(id, dateReceived);
nearestExpiration = expiresAt;
}
}
@@ -1442,8 +1384,7 @@ public class MmsDatabase extends MessagingDatabase {
message.getSubscriptionId(),
message.getExpiresIn(),
System.currentTimeMillis(),
- message.getRevealDuration(),
- 0,
+ message.isViewOnce(),
0,
message.getOutgoingQuote() != null ?
new Quote(message.getOutgoingQuote().getId(),
@@ -1541,8 +1482,7 @@ public class MmsDatabase extends MessagingDatabase {
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.UNIDENTIFIED)) == 1;
- long revealDuration = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_DURATION));
- long revealStartTime = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_START_TIME));
+ boolean isViewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) == 1;
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
readReceiptCount = 0;
@@ -1563,8 +1503,7 @@ public class MmsDatabase extends MessagingDatabase {
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
threadId, body, slideDeck, partCount, box, mismatches,
networkFailures, subscriptionId, expiresIn, expireStarted,
- revealDuration, revealStartTime,
- readReceiptCount, quote, contacts, previews, unidentified);
+ isViewOnce, readReceiptCount, quote, contacts, previews, unidentified);
}
private Recipient getRecipientFor(String serialized) {
diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
index dfa9614d98..fd2962f2fd 100644
--- a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
@@ -71,8 +71,7 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.QUOTE_ATTACHMENT,
MmsDatabase.SHARED_CONTACTS,
MmsDatabase.LINK_PREVIEWS,
- MmsDatabase.REVEAL_DURATION,
- MmsDatabase.REVEAL_START_TIME};
+ MmsDatabase.VIEW_ONCE};
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
@@ -273,8 +272,7 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.QUOTE_ATTACHMENT,
MmsDatabase.SHARED_CONTACTS,
MmsDatabase.LINK_PREVIEWS,
- MmsDatabase.REVEAL_DURATION,
- MmsDatabase.REVEAL_START_TIME};
+ MmsDatabase.VIEW_ONCE};
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
@@ -301,8 +299,7 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.QUOTE_ATTACHMENT,
MmsDatabase.SHARED_CONTACTS,
MmsDatabase.LINK_PREVIEWS,
- MmsDatabase.REVEAL_DURATION,
- MmsDatabase.REVEAL_START_TIME};
+ MmsDatabase.VIEW_ONCE};
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
@@ -373,8 +370,7 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(MmsDatabase.QUOTE_ATTACHMENT);
mmsColumnsPresent.add(MmsDatabase.SHARED_CONTACTS);
mmsColumnsPresent.add(MmsDatabase.LINK_PREVIEWS);
- mmsColumnsPresent.add(MmsDatabase.REVEAL_DURATION);
- mmsColumnsPresent.add(MmsDatabase.REVEAL_START_TIME);
+ mmsColumnsPresent.add(MmsDatabase.VIEW_ONCE);
Set smsColumnsPresent = new HashSet<>();
smsColumnsPresent.add(MmsSmsColumns.ID);
diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java
index c378c6373c..bd24659770 100644
--- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java
@@ -46,7 +46,6 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.JsonUtils;
-import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.Pair;
@@ -630,7 +629,7 @@ public class ThreadDatabase extends Database {
SlideDeck slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
Slide thumbnail = slideDeck.getThumbnailSlide();
- if (thumbnail != null && ((MmsMessageRecord) record).getRevealDuration() == 0) {
+ if (thumbnail != null && !((MmsMessageRecord) record).isViewOnce()) {
return thumbnail.getThumbnailUri();
}
@@ -650,7 +649,7 @@ public class ThreadDatabase extends Database {
}
private @Nullable Extra getExtrasFor(MessageRecord record) {
- if (record.isMms() && ((MmsMessageRecord) record).getRevealDuration() > 0) {
+ if (record.isMms() && ((MmsMessageRecord) record).isViewOnce()) {
return Extra.forRevealableMessage();
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
return Extra.forSticker();
diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
index 67aafa94a8..d9a2307f03 100644
--- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
+++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
@@ -67,11 +67,13 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int JOBMANAGER_STRIKES_BACK = 20;
private static final int STICKERS = 21;
private static final int REVEALABLE_MESSAGES = 22;
+ private static final int VIEW_ONCE_ONLY = 23;
- private static final int DATABASE_VERSION = 22;
+ private static final int DATABASE_VERSION = 23;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
+
private final DatabaseSecret databaseSecret;
public SQLCipherOpenHelper(@NonNull Context context, @NonNull DatabaseSecret databaseSecret) {
@@ -471,6 +473,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE thread ADD COLUMN snippet_extras TEXT DEFAULT NULL");
}
+ if (oldVersion < VIEW_ONCE_ONLY) {
+ db.execSQL("UPDATE mms SET reveal_duration = 1 WHERE reveal_duration > 0");
+ db.execSQL("UPDATE mms SET reveal_start_time = 0");
+ }
+
db.setTransactionSuccessful();
} finally {
db.endTransaction();
diff --git a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java
index 3ad7384af9..6b3108eca9 100644
--- a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java
@@ -55,13 +55,13 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
List mismatches,
List failures, int subscriptionId,
long expiresIn, long expireStarted,
- long revealDuration, long revealStartTime, int readReceiptCount,
+ boolean viewOnce, int readReceiptCount,
@Nullable Quote quote, @NonNull List contacts,
@NonNull List linkPreviews, boolean unidentified)
{
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
- subscriptionId, expiresIn, expireStarted, revealDuration, revealStartTime, slideDeck,
+ subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
readReceiptCount, quote, contacts, linkPreviews, unidentified);
this.partCount = partCount;
}
diff --git a/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java
index a4bf04975b..add9c7bf05 100644
--- a/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java
@@ -22,25 +22,23 @@ public abstract class MmsMessageRecord extends MessageRecord {
private final @NonNull List contacts = new LinkedList<>();
private final @NonNull List linkPreviews = new LinkedList<>();
- private final long revealDuration;
- private final long revealStartTime;
+ private final boolean viewOnce;
MmsMessageRecord(long id, String body, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId, long dateSent,
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
long type, List mismatches,
List networkFailures, int subscriptionId, long expiresIn,
- long expireStarted, long revealDuration, long revealStartTime,
+ long expireStarted, boolean viewOnce,
@NonNull SlideDeck slideDeck, int readReceiptCount,
@Nullable Quote quote, @NonNull List contacts,
@NonNull List linkPreviews, boolean unidentified)
{
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified);
- this.slideDeck = slideDeck;
- this.quote = quote;
- this.revealDuration = revealDuration;
- this.revealStartTime = revealStartTime;
+ this.slideDeck = slideDeck;
+ this.quote = quote;
+ this.viewOnce = viewOnce;
this.contacts.addAll(contacts);
this.linkPreviews.addAll(linkPreviews);
@@ -83,11 +81,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
return linkPreviews;
}
- public long getRevealDuration() {
- return revealDuration;
- }
-
- public long getRevealStartTime() {
- return revealStartTime;
+ public boolean isViewOnce() {
+ return viewOnce;
}
}
diff --git a/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java
index fbdafae288..7ce9a14803 100644
--- a/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java
@@ -57,7 +57,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
super(id, "", conversationRecipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
new LinkedList(), new LinkedList(), subscriptionId,
- 0, 0, 0, 0, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false);
+ 0, 0, false, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false);
this.contentLocation = contentLocation;
this.messageSize = messageSize;
diff --git a/src/org/thoughtcrime/securesms/giph/ui/GiphyActivity.java b/src/org/thoughtcrime/securesms/giph/ui/GiphyActivity.java
index 9601ea0452..2611e46b81 100644
--- a/src/org/thoughtcrime/securesms/giph/ui/GiphyActivity.java
+++ b/src/org/thoughtcrime/securesms/giph/ui/GiphyActivity.java
@@ -121,7 +121,7 @@ public class GiphyActivity extends PassphraseRequiredActionBarActivity
return BlobProvider.getInstance()
.forData(data)
.withMimeType(MediaUtil.IMAGE_GIF)
- .createForSingleSessionOnDisk(GiphyActivity.this, e -> Log.w(TAG, "Failed to write to disk.", e));
+ .createForSingleSessionOnDisk(GiphyActivity.this);
} catch (InterruptedException | ExecutionException | IOException e) {
Log.w(TAG, e);
return null;
diff --git a/src/org/thoughtcrime/securesms/groups/GroupManager.java b/src/org/thoughtcrime/securesms/groups/GroupManager.java
index 7ec883a459..924e402b98 100644
--- a/src/org/thoughtcrime/securesms/groups/GroupManager.java
+++ b/src/org/thoughtcrime/securesms/groups/GroupManager.java
@@ -115,7 +115,7 @@ public class GroupManager {
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, null, null);
}
- OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, 0, null, Collections.emptyList(), Collections.emptyList());
+ OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList());
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
return new GroupActionResult(groupRecipient, threadId);
diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
index c7eb6cc595..77f53a65ef 100644
--- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
+++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java
@@ -212,7 +212,7 @@ public class GroupMessageProcessor {
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId(), false));
Recipient recipient = Recipient.from(context, addres, false);
- OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, 0, null, Collections.emptyList(), Collections.emptyList());
+ OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, false, null, Collections.emptyList(), Collections.emptyList());
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
@@ -222,7 +222,7 @@ public class GroupMessageProcessor {
} else {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
String body = Base64.encodeBytes(storage.toByteArray());
- IncomingTextMessage incoming = new IncomingTextMessage(Address.fromExternal(context, content.getSender()), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(group), 0, 0, content.isNeedsReceipt());
+ IncomingTextMessage incoming = new IncomingTextMessage(Address.fromExternal(context, content.getSender()), content.getSenderDevice(), content.getTimestamp(), body, Optional.of(group), 0, content.isNeedsReceipt());
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
Optional insertResult = smsDatabase.insertMessageInbox(groupMessage);
diff --git a/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java
index 07b6162a09..fe9d2ce24d 100644
--- a/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java
+++ b/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java
@@ -41,10 +41,10 @@ public final class JobManagerFactories {
put(MultiDeviceGroupUpdateJob.KEY, new MultiDeviceGroupUpdateJob.Factory());
put(MultiDeviceProfileKeyUpdateJob.KEY, new MultiDeviceProfileKeyUpdateJob.Factory());
put(MultiDeviceReadUpdateJob.KEY, new MultiDeviceReadUpdateJob.Factory());
- put(MultiDeviceRevealUpdateJob.KEY, new MultiDeviceRevealUpdateJob.Factory());
put(MultiDeviceStickerPackOperationJob.KEY, new MultiDeviceStickerPackOperationJob.Factory());
put(MultiDeviceStickerPackSyncJob.KEY, new MultiDeviceStickerPackSyncJob.Factory());
put(MultiDeviceVerifiedUpdateJob.KEY, new MultiDeviceVerifiedUpdateJob.Factory());
+ put(MultiDeviceViewOnceOpenJob.KEY, new MultiDeviceViewOnceOpenJob.Factory());
put(PushContentReceiveJob.KEY, new PushContentReceiveJob.Factory());
put(PushDecryptJob.KEY, new PushDecryptJob.Factory());
put(PushGroupSendJob.KEY, new PushGroupSendJob.Factory());
diff --git a/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java
index ca57a3cc5a..af7577f097 100644
--- a/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/MmsDownloadJob.java
@@ -247,7 +247,7 @@ public class MmsDownloadJob extends BaseJob {
group = Optional.of(Address.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true)));
}
- IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, 0, false);
+ IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, false, false);
Optional insertResult = database.insertMessageInbox(message, contentLocation, threadId);
if (insertResult.isPresent()) {
diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceRevealUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceViewOnceOpenJob.java
similarity index 83%
rename from src/org/thoughtcrime/securesms/jobs/MultiDeviceRevealUpdateJob.java
rename to src/org/thoughtcrime/securesms/jobs/MultiDeviceViewOnceOpenJob.java
index a14015e10e..ed33fe5ebf 100644
--- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceRevealUpdateJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceViewOnceOpenJob.java
@@ -16,25 +16,25 @@ import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
-import org.whispersystems.signalservice.api.messages.multidevice.MessageTimerReadMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import java.io.IOException;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
-public class MultiDeviceRevealUpdateJob extends BaseJob {
+public class MultiDeviceViewOnceOpenJob extends BaseJob {
public static final String KEY = "MultiDeviceRevealUpdateJob";
- private static final String TAG = MultiDeviceRevealUpdateJob.class.getSimpleName();
+ private static final String TAG = Log.tag(MultiDeviceViewOnceOpenJob.class);
private static final String KEY_MESSAGE_ID = "message_id";
private SerializableSyncMessageId messageId;
- public MultiDeviceRevealUpdateJob(SyncMessageId messageId) {
+ public MultiDeviceViewOnceOpenJob(SyncMessageId messageId) {
this(new Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
@@ -43,7 +43,7 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
messageId);
}
- private MultiDeviceRevealUpdateJob(@NonNull Parameters parameters, @NonNull SyncMessageId syncMessageId) {
+ private MultiDeviceViewOnceOpenJob(@NonNull Parameters parameters, @NonNull SyncMessageId syncMessageId) {
super(parameters);
this.messageId = new SerializableSyncMessageId(syncMessageId.getAddress().toPhoneString(), syncMessageId.getTimetamp());
}
@@ -74,9 +74,9 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
}
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
- MessageTimerReadMessage timerMessage = new MessageTimerReadMessage(messageId.sender, messageId.timestamp);
+ ViewOnceOpenMessage openMessage = new ViewOnceOpenMessage(messageId.sender, messageId.timestamp);
- messageSender.sendMessage(SignalServiceSyncMessage.forMessageTimerRead(timerMessage), UnidentifiedAccessUtil.getAccessForSync(context));
+ messageSender.sendMessage(SignalServiceSyncMessage.forViewOnceOpen(openMessage), UnidentifiedAccessUtil.getAccessForSync(context));
}
@Override
@@ -105,9 +105,9 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
}
}
- public static final class Factory implements Job.Factory {
+ public static final class Factory implements Job.Factory {
@Override
- public @NonNull MultiDeviceRevealUpdateJob create(@NonNull Parameters parameters, @NonNull Data data) {
+ public @NonNull MultiDeviceViewOnceOpenJob create(@NonNull Parameters parameters, @NonNull Data data) {
SerializableSyncMessageId messageId;
try {
@@ -118,7 +118,7 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(messageId.sender), messageId.timestamp);
- return new MultiDeviceRevealUpdateJob(parameters, syncMessageId);
+ return new MultiDeviceViewOnceOpenJob(parameters, syncMessageId);
}
}
}
diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
index 07c5dc3ad4..1502b3dae9 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
@@ -80,8 +80,6 @@ import org.thoughtcrime.securesms.mms.StickerSlide;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.revealable.RevealExpirationInfo;
-import org.thoughtcrime.securesms.revealable.RevealableMessageManager;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
@@ -112,13 +110,13 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
-import org.whispersystems.signalservice.api.messages.multidevice.MessageTimerReadMessage;
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
@@ -283,7 +281,7 @@ public class PushDecryptJob extends BaseJob {
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get());
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get());
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp());
- else if (syncMessage.getMessageTimerRead().isPresent()) handleSynchronizeMessageTimerReadMessage(syncMessage.getMessageTimerRead().get(), content.getTimestamp());
+ else if (syncMessage.getViewOnceOpen().isPresent()) handleSynchronizeViewOnceOpenMessage(syncMessage.getViewOnceOpen().get(), content.getTimestamp());
else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get());
else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get());
else Log.w(TAG, "Contains no known sync types...");
@@ -431,7 +429,7 @@ public class PushDecryptJob extends BaseJob {
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromExternal(context, content.getSender()),
content.getSenderDevice(),
content.getTimestamp(),
- "", Optional.absent(), 0, 0,
+ "", Optional.absent(), 0,
content.isNeedsReceipt());
Long threadId;
@@ -515,7 +513,7 @@ public class PushDecryptJob extends BaseJob {
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
message.getTimestamp(), -1,
message.getExpiresInSeconds() * 1000L, true,
- 0,
+ false,
content.isNeedsReceipt(),
Optional.absent(),
message.getGroupInfo(),
@@ -676,11 +674,14 @@ public class PushDecryptJob extends BaseJob {
MessageNotifier.updateNotification(context);
}
- private void handleSynchronizeMessageTimerReadMessage(@NonNull MessageTimerReadMessage timerMessage, long envelopeTimestamp) {
- SyncMessageId messageId = new SyncMessageId(Address.fromExternal(context, timerMessage.getSender()), timerMessage.getTimestamp());
+ private void handleSynchronizeViewOnceOpenMessage(@NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp) {
+ Address author = Address.fromExternal(context, openMessage.getSender());
+ long timestamp = openMessage.getTimestamp();
+ MessageRecord record = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(timestamp, author);
- DatabaseFactory.getMmsDatabase(context).markRevealStarted(messageId, envelopeTimestamp);
- ApplicationContext.getInstance(context).getRevealableMessageManager().scheduleIfNecessary();
+ if (record != null && record.isMms()) {
+ DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentFilesForMessage(record.getId());
+ }
MessageNotifier.setLastDesktopActivityTimestamp(envelopeTimestamp);
MessageNotifier.cancelDelayedNotifications();
@@ -707,7 +708,7 @@ public class PushDecryptJob extends BaseJob {
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
message.getTimestamp(), -1,
message.getExpiresInSeconds() * 1000L, false,
- message.getMessageTimerInSeconds() * 1000,
+ message.isViewOnce(),
content.isNeedsReceipt(),
message.getBody(),
message.getGroupInfo(),
@@ -747,8 +748,8 @@ public class PushDecryptJob extends BaseJob {
if (insertResult.isPresent()) {
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
- if (message.getMessageTimerInSeconds() > 0) {
- ApplicationContext.getInstance(context).getRevealableMessageManager().scheduleIfNecessary();
+ if (message.isViewOnce()) {
+ ApplicationContext.getInstance(context).getViewOnceMessageManager().scheduleIfNecessary();
}
}
}
@@ -780,8 +781,8 @@ public class PushDecryptJob extends BaseJob {
Optional sticker = getStickerAttachment(message.getMessage().getSticker());
Optional> sharedContacts = getContacts(message.getMessage().getSharedContacts());
Optional> previews = getLinkPreviews(message.getMessage().getPreviews(), message.getMessage().getBody().or(""));
- long messageTimer = message.getMessage().getMessageTimerInSeconds() * 1000;
- List syncAttachments = messageTimer == 0 ? PointerAttachment.forPointers(message.getMessage().getAttachments()) : Collections.emptyList();
+ boolean viewOnce = message.getMessage().isViewOnce();
+ List syncAttachments = viewOnce ? Collections.emptyList() : PointerAttachment.forPointers(message.getMessage().getAttachments());
if (sticker.isPresent()) {
syncAttachments.add(sticker.get());
@@ -791,7 +792,7 @@ public class PushDecryptJob extends BaseJob {
syncAttachments,
message.getTimestamp(), -1,
message.getMessage().getExpiresInSeconds() * 1000,
- messageTimer,
+ viewOnce,
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
sharedContacts.or(Collections.emptyList()),
previews.or(Collections.emptyList()),
@@ -921,7 +922,6 @@ public class PushDecryptJob extends BaseJob {
message.getTimestamp(), body,
message.getGroupInfo(),
message.getExpiresInSeconds() * 1000L,
- message.getMessageTimerInSeconds() * 1000L,
content.isNeedsReceipt());
textMessage = new IncomingEncryptedMessage(textMessage, body);
@@ -956,7 +956,7 @@ public class PushDecryptJob extends BaseJob {
long messageId;
if (isGroup) {
- OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient, new SlideDeck(), body, message.getTimestamp(), -1, expiresInMillis, 0, ThreadDatabase.DistributionTypes.DEFAULT, null, Collections.emptyList(), Collections.emptyList());
+ OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient, new SlideDeck(), body, message.getTimestamp(), -1, expiresInMillis, false, ThreadDatabase.DistributionTypes.DEFAULT, null, Collections.emptyList(), Collections.emptyList());
outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage);
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, GroupReceiptDatabase.STATUS_UNKNOWN, null);
@@ -1195,7 +1195,7 @@ public class PushDecryptJob extends BaseJob {
}
private boolean isInvalidMessage(@NonNull SignalServiceDataMessage message) {
- if (message.getMessageTimerInSeconds() > 0) {
+ if (message.isViewOnce()) {
return !message.getAttachments().isPresent() ||
message.getAttachments().get().size() != 1 ||
!MediaUtil.isImageType(message.getAttachments().get().get(0).getContentType().toLowerCase());
@@ -1229,7 +1229,7 @@ public class PushDecryptJob extends BaseJob {
if (message.isMms()) {
MmsMessageRecord mmsMessage = (MmsMessageRecord) message;
- if (mmsMessage.getRevealDuration() == 0) {
+ if (!mmsMessage.isViewOnce()) {
attachments = mmsMessage.getSlideDeck().asAttachments();
if (attachments.isEmpty()) {
@@ -1335,7 +1335,7 @@ public class PushDecryptJob extends BaseJob {
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
senderDevice, timestamp, "",
- group, 0, 0, false);
+ group, 0, false);
textMessage = new IncomingEncryptedMessage(textMessage, "");
return database.insertMessageInbox(textMessage);
diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java
index 6077c4e062..4888e270b1 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java
@@ -195,11 +195,8 @@ public class PushGroupSendJob extends PushSendJob {
.scheduleDeletion(messageId, true, message.getExpiresIn());
}
- if (message.getRevealDuration() > 0) {
- database.markRevealStarted(messageId);
- ApplicationContext.getInstance(context)
- .getRevealableMessageManager()
- .scheduleIfNecessary();
+ if (message.isViewOnce()) {
+ DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentFilesForMessage(messageId);
}
} else if (!networkFailures.isEmpty()) {
throw new RetryLaterException();
@@ -269,7 +266,7 @@ public class PushGroupSendJob extends PushSendJob {
.withAttachments(attachmentPointers)
.withBody(message.getBody())
.withExpiration((int)(message.getExpiresIn() / 1000))
- .withMessageTimer((int)(message.getRevealDuration() / 1000))
+ .withViewOnce(message.isViewOnce())
.asExpirationUpdate(message.isExpirationUpdate())
.withProfileKey(profileKey.orNull())
.withQuote(quote.orNull())
diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java
index fc2b73ddb2..cd5b990e55 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java
@@ -164,11 +164,8 @@ public class PushMediaSendJob extends PushSendJob {
expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn());
}
- if (message.getRevealDuration() > 0) {
- database.markRevealStarted(messageId);
- ApplicationContext.getInstance(context)
- .getRevealableMessageManager()
- .scheduleIfNecessary();
+ if (message.isViewOnce()) {
+ DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentFilesForMessage(messageId);
}
log(TAG, "Sent message: " + messageId);
@@ -230,7 +227,7 @@ public class PushMediaSendJob extends PushSendJob {
.withAttachments(serviceAttachments)
.withTimestamp(message.getSentTimeMillis())
.withExpiration((int)(message.getExpiresIn() / 1000))
- .withMessageTimer((int) message.getRevealDuration() / 1000)
+ .withViewOnce(message.isViewOnce())
.withProfileKey(profileKey.orNull())
.withQuote(quote.orNull())
.withSticker(sticker.orNull())
diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java b/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java
index a95f7b5225..1329e5330c 100644
--- a/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java
+++ b/src/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java
@@ -50,7 +50,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
-import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.RevealState;
+import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.ViewOnceState;
import org.thoughtcrime.securesms.mms.GifSlide;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.ImageSlide;
@@ -101,10 +101,10 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
{
private static final String TAG = MediaSendActivity.class.getSimpleName();
- public static final String EXTRA_MEDIA = "media";
- public static final String EXTRA_MESSAGE = "message";
- public static final String EXTRA_TRANSPORT = "transport";
- public static final String EXTRA_REVEAL_DURATION = "reveal_duration";
+ public static final String EXTRA_MEDIA = "media";
+ public static final String EXTRA_MESSAGE = "message";
+ public static final String EXTRA_TRANSPORT = "transport";
+ public static final String EXTRA_VIEW_ONCE = "view_once";
private static final String KEY_ADDRESS = "address";
@@ -391,7 +391,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
Uri uri = BlobProvider.getInstance()
.forData(data)
.withMimeType(MediaUtil.IMAGE_JPEG)
- .createForSingleSessionOnDisk(this, e -> Log.w(TAG, "Failed to write to disk.", e));
+ .createForSingleSessionOnDisk(this);
return new Media(uri,
MediaUtil.IMAGE_JPEG,
System.currentTimeMillis(),
@@ -527,14 +527,14 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
if (state == null) return;
hud.setVisibility(state.isHudVisible() ? View.VISIBLE : View.GONE);
- composeContainer.setVisibility(state.isComposeVisible() ? View.VISIBLE : (state.getRevealState() == RevealState.GONE ? View.GONE : View.INVISIBLE));
+ composeContainer.setVisibility(state.isComposeVisible() ? View.VISIBLE : (state.getViewOnceState() == ViewOnceState.GONE ? View.GONE : View.INVISIBLE));
captionText.setVisibility(state.isCaptionVisible() ? View.VISIBLE : View.GONE);
int captionBackground;
if (state.getRailState() == MediaSendViewModel.RailState.VIEWABLE) {
captionBackground = R.color.core_grey_90;
- } else if (state.getRevealState() == RevealState.ENABLED) {
+ } else if (state.getViewOnceState() == ViewOnceState.ENABLED) {
captionBackground = 0;
} else {
captionBackground = R.color.transparent_black_70;
@@ -572,7 +572,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
break;
}
- switch (state.getRevealState()) {
+ switch (state.getViewOnceState()) {
case ENABLED:
revealButton.setVisibility(View.VISIBLE);
revealButton.setImageResource(R.drawable.ic_view_once_32);
@@ -815,7 +815,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
Uri uri = BlobProvider.getInstance()
.forData(outputStream.toByteArray())
.withMimeType(MediaUtil.IMAGE_JPEG)
- .createForSingleSessionOnDisk(context, e -> Log.w(TAG, "Failed to write to disk.", e));
+ .createForSingleSessionOnDisk(context);
Media updated = new Media(uri, MediaUtil.IMAGE_JPEG, media.getDate(), bitmap.getWidth(), bitmap.getHeight(), outputStream.size(), media.getBucketId(), media.getCaption());
@@ -859,9 +859,9 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
Intent intent = new Intent();
intent.putParcelableArrayListExtra(EXTRA_MEDIA, mediaList);
- intent.putExtra(EXTRA_MESSAGE, viewModel.getRevealDuration() == 0 ? message : "");
+ intent.putExtra(EXTRA_MESSAGE, viewModel.isViewOnce() ? "" : message);
intent.putExtra(EXTRA_TRANSPORT, transport);
- intent.putExtra(EXTRA_REVEAL_DURATION, viewModel.getRevealDuration());
+ intent.putExtra(EXTRA_VIEW_ONCE, viewModel.isViewOnce());
setResult(RESULT_OK, intent);
} else {
@@ -885,7 +885,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
System.currentTimeMillis(),
-1,
recipient.getExpireMessages() * 1000,
- viewModel.getRevealDuration(),
+ viewModel.isViewOnce(),
ThreadDatabase.DistributionTypes.DEFAULT,
null,
Collections.emptyList(),
diff --git a/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java b/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java
index 6d642c0c9b..fc62144069 100644
--- a/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java
+++ b/src/org/thoughtcrime/securesms/mediasend/MediaSendViewModel.java
@@ -61,12 +61,12 @@ class MediaSendViewModel extends ViewModel {
private boolean isSms;
private Optional lastCameraCapture;
- private boolean hudVisible;
- private boolean composeVisible;
- private boolean captionVisible;
- private ButtonState buttonState;
- private RailState railState;
- private RevealState revealState;
+ private boolean hudVisible;
+ private boolean composeVisible;
+ private boolean captionVisible;
+ private ButtonState buttonState;
+ private RailState railState;
+ private ViewOnceState viewOnceState;
private @Nullable Recipient recipient;
@@ -86,7 +86,7 @@ class MediaSendViewModel extends ViewModel {
this.body = "";
this.buttonState = ButtonState.GONE;
this.railState = RailState.GONE;
- this.revealState = RevealState.GONE;
+ this.viewOnceState = ViewOnceState.GONE;
this.page = Page.UNKNOWN;
position.setValue(-1);
@@ -174,7 +174,7 @@ class MediaSendViewModel extends ViewModel {
captionVisible = false;
buttonState = ButtonState.COUNT;
railState = RailState.VIEWABLE;
- revealState = RevealState.GONE;
+ viewOnceState = ViewOnceState.GONE;
hudState.setValue(buildHudState());
}
@@ -182,19 +182,19 @@ class MediaSendViewModel extends ViewModel {
void onImageEditorStarted() {
page = Page.EDITOR;
hudVisible = true;
- composeVisible = revealState != RevealState.ENABLED;
+ composeVisible = viewOnceState != ViewOnceState.ENABLED;
captionVisible = getSelectedMediaOrDefault().size() > 1 || (getSelectedMediaOrDefault().size() > 0 && getSelectedMediaOrDefault().get(0).getCaption().isPresent());
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
- if (revealState == RevealState.GONE && revealSupported()) {
+ if (viewOnceState == ViewOnceState.GONE && viewOnceSupported()) {
// TODO[reveal]
-// revealState = TextSecurePreferences.isRevealableMessageEnabled(application) ? RevealState.ENABLED : RevealState.DISABLED;
- revealState = RevealState.GONE;
- } else if (!revealSupported()) {
- revealState = RevealState.GONE;
+// viewOnceState = TextSecurePreferences.isRevealableMessageEnabled(application) ? ViewOnceState.ENABLED : ViewOnceState.DISABLED;
+ viewOnceState = ViewOnceState.GONE;
+ } else if (!viewOnceSupported()) {
+ viewOnceState = ViewOnceState.GONE;
}
- railState = !isSms && revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
+ railState = !isSms && viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
hudState.setValue(buildHudState());
}
@@ -203,10 +203,10 @@ class MediaSendViewModel extends ViewModel {
// TODO: Don't need this?
Page previous = page;
- page = Page.CAMERA;
- hudVisible = false;
- revealState = RevealState.GONE;
- buttonState = ButtonState.COUNT;
+ page = Page.CAMERA;
+ hudVisible = false;
+ viewOnceState = ViewOnceState.GONE;
+ buttonState = ButtonState.COUNT;
List selected = getSelectedMediaOrDefault();
@@ -225,7 +225,7 @@ class MediaSendViewModel extends ViewModel {
composeVisible = false;
captionVisible = false;
buttonState = ButtonState.COUNT;
- revealState = RevealState.GONE;
+ viewOnceState = ViewOnceState.GONE;
railState = getSelectedMediaOrDefault().isEmpty() ? RailState.GONE : RailState.VIEWABLE;
lastCameraCapture = Optional.absent();
@@ -239,7 +239,7 @@ class MediaSendViewModel extends ViewModel {
composeVisible = false;
captionVisible = false;
buttonState = ButtonState.COUNT;
- revealState = RevealState.GONE;
+ viewOnceState = ViewOnceState.GONE;
railState = getSelectedMediaOrDefault().isEmpty() ? RailState.GONE : RailState.VIEWABLE;
lastCameraCapture = Optional.absent();
@@ -255,9 +255,9 @@ class MediaSendViewModel extends ViewModel {
void onRevealButtonToggled() {
hudVisible = true;
- revealState = revealState == RevealState.ENABLED ? RevealState.DISABLED : RevealState.ENABLED;
- composeVisible = revealState != RevealState.ENABLED;
- railState = revealState == RevealState.ENABLED || isSms ? RailState.GONE : RailState.INTERACTIVE;
+ viewOnceState = viewOnceState == ViewOnceState.ENABLED ? ViewOnceState.DISABLED : ViewOnceState.ENABLED;
+ composeVisible = viewOnceState != ViewOnceState.ENABLED;
+ railState = viewOnceState == ViewOnceState.ENABLED || isSms ? RailState.GONE : RailState.INTERACTIVE;
captionVisible = false;
List uncaptioned = Stream.of(getSelectedMediaOrDefault())
@@ -266,7 +266,7 @@ class MediaSendViewModel extends ViewModel {
selectedMedia.setValue(uncaptioned);
- TextSecurePreferences.setIsRevealableMessageEnabled(application, revealState == RevealState.ENABLED);
+ TextSecurePreferences.setIsRevealableMessageEnabled(application, viewOnceState == ViewOnceState.ENABLED);
hudState.setValue(buildHudState());
}
@@ -274,14 +274,14 @@ class MediaSendViewModel extends ViewModel {
void onKeyboardHidden(boolean isSms) {
if (page != Page.EDITOR) return;
- composeVisible = (revealState != RevealState.ENABLED);
+ composeVisible = (viewOnceState != ViewOnceState.ENABLED);
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
if (isSms) {
railState = RailState.GONE;
captionVisible = false;
} else {
- railState = revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
+ railState = viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
if (getSelectedMediaOrDefault().size() > 1 || (getSelectedMediaOrDefault().size() > 0 && getSelectedMediaOrDefault().get(0).getCaption().isPresent())) {
captionVisible = true;
@@ -296,18 +296,18 @@ class MediaSendViewModel extends ViewModel {
if (isSms) {
railState = RailState.GONE;
- composeVisible = (revealState == RevealState.GONE);
+ composeVisible = (viewOnceState == ViewOnceState.GONE);
captionVisible = false;
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
} else {
if (isCaptionFocused) {
- railState = revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
+ railState = viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
composeVisible = false;
captionVisible = true;
buttonState = ButtonState.GONE;
} else if (isComposeFocused) {
- railState = revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
- composeVisible = (revealState != RevealState.ENABLED);
+ railState = viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
+ composeVisible = (viewOnceState != ViewOnceState.ENABLED);
captionVisible = false;
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
}
@@ -357,7 +357,7 @@ class MediaSendViewModel extends ViewModel {
}
if (getSelectedMediaOrDefault().size() == 1) {
- revealState = revealSupported() ? RevealState.DISABLED : RevealState.GONE;
+ viewOnceState = viewOnceSupported() ? ViewOnceState.DISABLED : ViewOnceState.GONE;
}
hudState.setValue(buildHudState());
@@ -448,10 +448,9 @@ class MediaSendViewModel extends ViewModel {
return maxSelection;
}
- long getRevealDuration() {
+ boolean isViewOnce() {
// TODO[reveal]
-// return revealState == RevealState.ENABLED ? RevealableUtil.DURATION : 0;
- return 0;
+ return false;
}
private @NonNull List getSelectedMediaOrDefault() {
@@ -473,13 +472,13 @@ class MediaSendViewModel extends ViewModel {
private HudState buildHudState() {
// TODO[reveal]
- RevealState updatedRevealState = RevealState.GONE;
- List selectedMedia = getSelectedMediaOrDefault();
- int selectionCount = selectedMedia.size();
- ButtonState updatedButtonState = buttonState == ButtonState.COUNT && selectionCount == 0 ? ButtonState.GONE : buttonState;
- boolean updatedCaptionVisible = captionVisible && (selectedMedia.size() > 1 || (selectedMedia.size() > 0 && selectedMedia.get(0).getCaption().isPresent()));
+ ViewOnceState updatedViewOnceState = ViewOnceState.GONE;
+ List selectedMedia = getSelectedMediaOrDefault();
+ int selectionCount = selectedMedia.size();
+ ButtonState updatedButtonState = buttonState == ButtonState.COUNT && selectionCount == 0 ? ButtonState.GONE : buttonState;
+ boolean updatedCaptionVisible = captionVisible && (selectedMedia.size() > 1 || (selectedMedia.size() > 0 && selectedMedia.get(0).getCaption().isPresent()));
- return new HudState(hudVisible, composeVisible, updatedCaptionVisible, selectionCount, updatedButtonState, railState, updatedRevealState);
+ return new HudState(hudVisible, composeVisible, updatedCaptionVisible, selectionCount, updatedButtonState, railState, updatedViewOnceState);
}
private void clearPersistedMedia() {
@@ -489,7 +488,7 @@ class MediaSendViewModel extends ViewModel {
.forEach(uri -> BlobProvider.getInstance().delete(application.getApplicationContext(), uri));
}
- private boolean revealSupported() {
+ private boolean viewOnceSupported() {
return !isSms && (recipient == null || !recipient.isLocalNumber()) && mediaSupportsRevealableMessage(getSelectedMediaOrDefault());
}
@@ -520,7 +519,7 @@ class MediaSendViewModel extends ViewModel {
INTERACTIVE, VIEWABLE, GONE
}
- enum RevealState {
+ enum ViewOnceState {
ENABLED, DISABLED, GONE
}
@@ -532,7 +531,7 @@ class MediaSendViewModel extends ViewModel {
private final int selectionCount;
private final ButtonState buttonState;
private final RailState railState;
- private final RevealState revealState;
+ private final ViewOnceState viewOnceState;
HudState(boolean hudVisible,
boolean composeVisible,
@@ -540,7 +539,7 @@ class MediaSendViewModel extends ViewModel {
int selectionCount,
@NonNull ButtonState buttonState,
@NonNull RailState railState,
- @NonNull RevealState revealState)
+ @NonNull ViewOnceState viewOnceState)
{
this.hudVisible = hudVisible;
this.composeVisible = composeVisible;
@@ -548,7 +547,7 @@ class MediaSendViewModel extends ViewModel {
this.selectionCount = selectionCount;
this.buttonState = buttonState;
this.railState = railState;
- this.revealState = revealState;
+ this.viewOnceState = viewOnceState;
}
public boolean isHudVisible() {
@@ -575,9 +574,8 @@ class MediaSendViewModel extends ViewModel {
return hudVisible ? railState : RailState.GONE;
}
- public @NonNull
- RevealState getRevealState() {
- return hudVisible ? revealState : RevealState.GONE;
+ public @NonNull ViewOnceState getViewOnceState() {
+ return hudVisible ? viewOnceState : ViewOnceState.GONE;
}
}
diff --git a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java
index 5c85f0c072..2a623ca71c 100644
--- a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java
+++ b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java
@@ -24,9 +24,9 @@ public class IncomingMediaMessage {
private final int subscriptionId;
private final long expiresIn;
private final boolean expirationUpdate;
- private final long revealDuration;
private final QuoteModel quote;
private final boolean unidentified;
+ private final boolean viewOnce;
private final List attachments = new LinkedList<>();
private final List sharedContacts = new LinkedList<>();
@@ -40,7 +40,7 @@ public class IncomingMediaMessage {
int subscriptionId,
long expiresIn,
boolean expirationUpdate,
- long revealDuration,
+ boolean viewOnce,
boolean unidentified)
{
this.from = from;
@@ -51,7 +51,7 @@ public class IncomingMediaMessage {
this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn;
this.expirationUpdate = expirationUpdate;
- this.revealDuration = revealDuration;
+ this.viewOnce = viewOnce;
this.quote = null;
this.unidentified = unidentified;
@@ -63,7 +63,7 @@ public class IncomingMediaMessage {
int subscriptionId,
long expiresIn,
boolean expirationUpdate,
- long revealDuration,
+ boolean viewOnce,
boolean unidentified,
Optional body,
Optional group,
@@ -80,7 +80,7 @@ public class IncomingMediaMessage {
this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn;
this.expirationUpdate = expirationUpdate;
- this.revealDuration = revealDuration;
+ this.viewOnce = viewOnce;
this.quote = quote.orNull();
this.unidentified = unidentified;
@@ -132,8 +132,8 @@ public class IncomingMediaMessage {
return expiresIn;
}
- public long getRevealDuration() {
- return revealDuration;
+ public boolean isViewOnce() {
+ return viewOnce;
}
public boolean isGroupMessage() {
diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java
index bd521a7310..fd86024544 100644
--- a/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java
+++ b/src/org/thoughtcrime/securesms/mms/OutgoingExpirationUpdateMessage.java
@@ -11,7 +11,7 @@ public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) {
super(recipient, "", new LinkedList(), sentTimeMillis,
- ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn, 0, null, Collections.emptyList(),
+ ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn, false, null, Collections.emptyList(),
Collections.emptyList());
}
diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java
index 36d567acfa..2fb734f87c 100644
--- a/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java
+++ b/src/org/thoughtcrime/securesms/mms/OutgoingGroupMediaMessage.java
@@ -24,14 +24,14 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
@NonNull List avatar,
long sentTimeMillis,
long expiresIn,
- long revealDuration,
+ boolean viewOnce,
@Nullable QuoteModel quote,
@NonNull List contacts,
@NonNull List previews)
throws IOException
{
super(recipient, encodedGroupContext, avatar, sentTimeMillis,
- ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn, revealDuration, quote, contacts, previews);
+ ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn, viewOnce, quote, contacts, previews);
this.group = GroupContext.parseFrom(Base64.decode(encodedGroupContext));
}
@@ -41,7 +41,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
@Nullable final Attachment avatar,
long sentTimeMillis,
long expireIn,
- long revealDuration,
+ boolean viewOnce,
@Nullable QuoteModel quote,
@NonNull List contacts,
@NonNull List previews)
@@ -49,7 +49,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
super(recipient, Base64.encodeBytes(group.toByteArray()),
new LinkedList() {{if (avatar != null) add(avatar);}},
System.currentTimeMillis(),
- ThreadDatabase.DistributionTypes.CONVERSATION, expireIn, revealDuration, quote, contacts, previews);
+ ThreadDatabase.DistributionTypes.CONVERSATION, expireIn, viewOnce, quote, contacts, previews);
this.group = group;
}
diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java
index cc36527bc4..d9d02b62f8 100644
--- a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java
+++ b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java
@@ -23,7 +23,7 @@ public class OutgoingMediaMessage {
private final int distributionType;
private final int subscriptionId;
private final long expiresIn;
- private final long revealDuration;
+ private final boolean viewOnce;
private final QuoteModel outgoingQuote;
private final List networkFailures = new LinkedList<>();
@@ -33,7 +33,7 @@ public class OutgoingMediaMessage {
public OutgoingMediaMessage(Recipient recipient, String message,
List attachments, long sentTimeMillis,
- int subscriptionId, long expiresIn, long revealDuration,
+ int subscriptionId, long expiresIn, boolean viewOnce,
int distributionType,
@Nullable QuoteModel outgoingQuote,
@NonNull List contacts,
@@ -48,7 +48,7 @@ public class OutgoingMediaMessage {
this.attachments = attachments;
this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn;
- this.revealDuration = revealDuration;
+ this.viewOnce = viewOnce;
this.outgoingQuote = outgoingQuote;
this.contacts.addAll(contacts);
@@ -59,7 +59,7 @@ public class OutgoingMediaMessage {
public OutgoingMediaMessage(Recipient recipient, SlideDeck slideDeck, String message,
long sentTimeMillis, int subscriptionId, long expiresIn,
- long revealDuration, int distributionType,
+ boolean viewOnce, int distributionType,
@Nullable QuoteModel outgoingQuote,
@NonNull List contacts,
@NonNull List linkPreviews)
@@ -68,7 +68,7 @@ public class OutgoingMediaMessage {
buildMessage(slideDeck, message),
slideDeck.asAttachments(),
sentTimeMillis, subscriptionId,
- expiresIn, revealDuration, distributionType, outgoingQuote,
+ expiresIn, viewOnce, distributionType, outgoingQuote,
contacts, linkPreviews, new LinkedList<>(), new LinkedList<>());
}
@@ -80,7 +80,7 @@ public class OutgoingMediaMessage {
this.sentTimeMillis = that.sentTimeMillis;
this.subscriptionId = that.subscriptionId;
this.expiresIn = that.expiresIn;
- this.revealDuration = that.revealDuration;
+ this.viewOnce = that.viewOnce;
this.outgoingQuote = that.outgoingQuote;
this.identityKeyMismatches.addAll(that.identityKeyMismatches);
@@ -129,8 +129,8 @@ public class OutgoingMediaMessage {
return expiresIn;
}
- public long getRevealDuration() {
- return revealDuration;
+ public boolean isViewOnce() {
+ return viewOnce;
}
public @Nullable QuoteModel getOutgoingQuote() {
diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java
index 839b26ce44..2aec2a3400 100644
--- a/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java
+++ b/src/org/thoughtcrime/securesms/mms/OutgoingSecureMediaMessage.java
@@ -18,12 +18,12 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
long sentTimeMillis,
int distributionType,
long expiresIn,
- long revealDuration,
+ boolean viewOnce,
@Nullable QuoteModel quote,
@NonNull List contacts,
@NonNull List previews)
{
- super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, revealDuration, distributionType, quote, contacts, previews, Collections.emptyList(), Collections.emptyList());
+ super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, viewOnce, distributionType, quote, contacts, previews, Collections.emptyList(), Collections.emptyList());
}
public OutgoingSecureMediaMessage(OutgoingMediaMessage base) {
diff --git a/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java b/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java
index 09c9ed8c69..ab568b80b8 100644
--- a/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java
+++ b/src/org/thoughtcrime/securesms/notifications/AndroidAutoReplyReceiver.java
@@ -76,7 +76,7 @@ public class AndroidAutoReplyReceiver extends BroadcastReceiver {
if (recipient.isGroupRecipient()) {
Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");
- OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0, 0, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
+ OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<>(), System.currentTimeMillis(), subscriptionId, expiresIn, false, 0, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
replyThreadId = MessageSender.send(context, reply, threadId, false, null);
} else {
Log.w("AndroidAutoReplyReceiver", "Sending regular message ");
diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java
index 5879eebd2d..c8fef46bca 100644
--- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java
+++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java
@@ -465,7 +465,7 @@ public class MessageNotifier {
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_sticker));
slideDeck = ((MmsMessageRecord) record).getSlideDeck();
- } else if (record.isMms() && ((MmsMessageRecord) record).getRevealDuration() > 0) {
+ } else if (record.isMms() && ((MmsMessageRecord) record).isViewOnce()) {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_disappearing_photo));
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
diff --git a/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java b/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java
index 7276d03b02..96a3322592 100644
--- a/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java
+++ b/src/org/thoughtcrime/securesms/notifications/RemoteReplyReceiver.java
@@ -76,7 +76,7 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
switch (replyMethod) {
case GroupMessage: {
- OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0, 0, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
+ OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<>(), System.currentTimeMillis(), subscriptionId, expiresIn, false, 0, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
threadId = MessageSender.send(context, reply, -1, false, null);
break;
}
diff --git a/src/org/thoughtcrime/securesms/providers/BlobProvider.java b/src/org/thoughtcrime/securesms/providers/BlobProvider.java
index 0cdb50da9a..41f76b28d7 100644
--- a/src/org/thoughtcrime/securesms/providers/BlobProvider.java
+++ b/src/org/thoughtcrime/securesms/providers/BlobProvider.java
@@ -25,6 +25,8 @@ import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Allows for the creation and retrieval of blobs.
@@ -173,7 +175,34 @@ public class BlobProvider {
}
@WorkerThread
- private synchronized @NonNull Uri writeBlobSpecToDisk(@NonNull Context context, @NonNull BlobSpec blobSpec, @Nullable ErrorListener errorListener) throws IOException {
+ private synchronized @NonNull Uri writeBlobSpecToDisk(@NonNull Context context, @NonNull BlobSpec blobSpec)
+ throws IOException
+ {
+ CountDownLatch latch = new CountDownLatch(1);
+ AtomicReference exception = new AtomicReference<>(null);
+ Uri uri = writeBlobSpecToDiskAsync(context, blobSpec, latch::countDown, exception::set);
+
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+
+ if (exception.get() != null) {
+ throw exception.get();
+ }
+
+ return uri;
+ }
+
+
+ @WorkerThread
+ private synchronized @NonNull Uri writeBlobSpecToDiskAsync(@NonNull Context context,
+ @NonNull BlobSpec blobSpec,
+ @Nullable SuccessListener successListener,
+ @Nullable ErrorListener errorListener)
+ throws IOException
+ {
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
String directory = getDirectory(blobSpec.getStorageType());
File outputFile = new File(getOrCreateCacheDirectory(context, directory), buildFileName(blobSpec.id));
@@ -182,6 +211,10 @@ public class BlobProvider {
SignalExecutors.UNBOUNDED.execute(() -> {
try {
Util.copy(blobSpec.getData(), outputStream);
+
+ if (successListener != null) {
+ successListener.onSuccess();
+ }
} catch (IOException e) {
if (errorListener != null) {
errorListener.onError(e);
@@ -258,8 +291,23 @@ public class BlobProvider {
* period from one {@link Application#onCreate()} to the next.
*/
@WorkerThread
- public Uri createForSingleSessionOnDisk(@NonNull Context context, @Nullable ErrorListener errorListener) throws IOException {
- return writeBlobSpecToDisk(context, buildBlobSpec(StorageType.SINGLE_SESSION_DISK), errorListener);
+ public Uri createForSingleSessionOnDisk(@NonNull Context context) throws IOException {
+ return writeBlobSpecToDisk(context, buildBlobSpec(StorageType.SINGLE_SESSION_DISK));
+ }
+
+ /**
+ * Create a blob that will exist for a single app session. An app session is defined as the
+ * period from one {@link Application#onCreate()} to the next. The file will be created on disk
+ * synchronously, but the data will copied asynchronously. This is helpful when the copy is
+ * long-running, such as in the case of recording a voice note.
+ */
+ @WorkerThread
+ public Uri createForSingleSessionOnDiskAsync(@NonNull Context context,
+ @Nullable SuccessListener successListener,
+ @Nullable ErrorListener errorListener)
+ throws IOException
+ {
+ return writeBlobSpecToDiskAsync(context, buildBlobSpec(StorageType.SINGLE_SESSION_DISK), successListener, errorListener);
}
/**
@@ -267,8 +315,25 @@ public class BlobProvider {
* eventually call {@link BlobProvider#delete(Context, Uri)} when the blob is no longer in use.
*/
@WorkerThread
- public Uri createForMultipleSessionsOnDisk(@NonNull Context context, @Nullable ErrorListener errorListener) throws IOException {
- return writeBlobSpecToDisk(context, buildBlobSpec(StorageType.MULTI_SESSION_DISK), errorListener);
+ public Uri createForMultipleSessionsOnDisk(@NonNull Context context) throws IOException {
+ return writeBlobSpecToDisk(context, buildBlobSpec(StorageType.MULTI_SESSION_DISK));
+ }
+
+ /**
+ * Create a blob that will exist for multiple app sessions. The file will be created on disk
+ * synchronously, but the data will copied asynchronously. This is helpful when the copy is
+ * long-running, such as in the case of recording a voice note.
+ *
+ * It is the caller's responsibility to eventually call {@link BlobProvider#delete(Context, Uri)}
+ * when the blob is no longer in use.
+ */
+ @WorkerThread
+ public Uri createForMultipleSessionsOnDiskAsync(@NonNull Context context,
+ @Nullable SuccessListener successListener,
+ @Nullable ErrorListener errorListener)
+ throws IOException
+ {
+ return writeBlobSpecToDiskAsync(context, buildBlobSpec(StorageType.MULTI_SESSION_DISK), successListener, errorListener);
}
}
@@ -311,6 +376,11 @@ public class BlobProvider {
}
}
+ public interface SuccessListener {
+ @WorkerThread
+ void onSuccess();
+ }
+
public interface ErrorListener {
@WorkerThread
void onError(IOException e);
diff --git a/src/org/thoughtcrime/securesms/revealable/RevealExpirationInfo.java b/src/org/thoughtcrime/securesms/revealable/RevealExpirationInfo.java
deleted file mode 100644
index eb5e07f097..0000000000
--- a/src/org/thoughtcrime/securesms/revealable/RevealExpirationInfo.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.thoughtcrime.securesms.revealable;
-
-public class RevealExpirationInfo {
-
- private final long messageId;
- private final long receiveTime;
- private final long revealStartTime;
- private final long revealDuration;
-
- public RevealExpirationInfo(long messageId, long receiveTime, long revealStartTime, long revealDuration) {
- this.messageId = messageId;
- this.receiveTime = receiveTime;
- this.revealStartTime = revealStartTime;
- this.revealDuration = revealDuration;
- }
-
- public long getMessageId() {
- return messageId;
- }
-
- public long getReceiveTime() {
- return receiveTime;
- }
-
- public long getRevealStartTime() {
- return revealStartTime;
- }
-
- public long getRevealDuration() {
- return revealDuration;
- }
-}
diff --git a/src/org/thoughtcrime/securesms/revealable/RevealableMessageActivity.java b/src/org/thoughtcrime/securesms/revealable/RevealableMessageActivity.java
deleted file mode 100644
index e05b5701a7..0000000000
--- a/src/org/thoughtcrime/securesms/revealable/RevealableMessageActivity.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.thoughtcrime.securesms.revealable;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.Observer;
-import androidx.lifecycle.ViewModelProviders;
-
-import com.pnikosis.materialishprogress.ProgressWheel;
-
-import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
-import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.logging.Log;
-import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
-import org.thoughtcrime.securesms.mms.GlideApp;
-import org.thoughtcrime.securesms.util.Util;
-
-public class RevealableMessageActivity extends PassphraseRequiredActionBarActivity {
-
- private static final String TAG = Log.tag(RevealableMessageActivity.class);
-
- private static final String KEY_MESSAGE_ID = "message_id";
-
- private ImageView image;
- private View closeButton;
- private RevealableMessageViewModel viewModel;
-
- public static Intent getIntent(@NonNull Context context, long messageId) {
- Intent intent = new Intent(context, RevealableMessageActivity.class);
- intent.putExtra(KEY_MESSAGE_ID, messageId);
- return intent;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState, boolean ready) {
- super.onCreate(savedInstanceState, ready);
- setContentView(R.layout.revealable_message_activity);
-
- this.image = findViewById(R.id.reveal_image);
- this.closeButton = findViewById(R.id.reveal_close_button);
-
- image.setOnClickListener(v -> finish());
- closeButton.setOnClickListener(v -> finish());
-
- initViewModel(getIntent().getLongExtra(KEY_MESSAGE_ID, -1));
- }
-
- private void initViewModel(long messageId) {
- RevealableMessageRepository repository = new RevealableMessageRepository(this);
- viewModel = ViewModelProviders.of(this, new RevealableMessageViewModel.Factory(getApplication(), messageId, repository))
- .get(RevealableMessageViewModel.class);
-
- viewModel.getMessage().observe(this, (message) -> {
- if (message == null) return;
-
- if (message.isPresent()) {
- //noinspection ConstantConditions
- GlideApp.with(this)
- .load(new DecryptableUri(message.get().getSlideDeck().getThumbnailSlide().getUri()))
- .into(image);
- } else {
- image.setImageDrawable(null);
- finish();
- }
- });
- }
-}
diff --git a/src/org/thoughtcrime/securesms/revealable/RevealableUtil.java b/src/org/thoughtcrime/securesms/revealable/RevealableUtil.java
deleted file mode 100644
index 6ea1955c47..0000000000
--- a/src/org/thoughtcrime/securesms/revealable/RevealableUtil.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.thoughtcrime.securesms.revealable;
-
-import androidx.annotation.Nullable;
-
-import org.thoughtcrime.securesms.attachments.Attachment;
-import org.thoughtcrime.securesms.database.AttachmentDatabase;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-
-import java.util.concurrent.TimeUnit;
-
-public class RevealableUtil {
-
- public static final long MAX_LIFESPAN = TimeUnit.DAYS.toMillis(30);
- public static final long DURATION = TimeUnit.SECONDS.toMillis(5);
-
- public static boolean isViewable(@Nullable MmsMessageRecord message) {
- if (message.getRevealDuration() == 0) {
- return true;
- } else if (message.getSlideDeck().getThumbnailSlide() == null) {
- return false;
- } else if (message.getSlideDeck().getThumbnailSlide().getUri() == null) {
- return false;
- } else if (message.isOutgoing() && message.getSlideDeck().getThumbnailSlide().getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_STARTED) {
- return true;
- } else if (message.getSlideDeck().getThumbnailSlide().getTransferState() != AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
- return false;
- } else if (isRevealExpired(message)) {
- return false;
- } else {
- return true;
- }
- }
-
- public static boolean isRevealExpired(@Nullable MmsMessageRecord message) {
- if (message == null) {
- return false;
- } else if (message.getRevealDuration() == 0) {
- return false;
- } else if (message.getDateReceived() + MAX_LIFESPAN < System.currentTimeMillis()) {
- return true;
- } else if (message.getRevealStartTime() == 0) {
- return false;
- } else if (message.getRevealStartTime() + message.getRevealDuration() < System.currentTimeMillis()) {
- return true;
- } else {
- return false;
- }
- }
-}
diff --git a/src/org/thoughtcrime/securesms/revealable/ViewOnceExpirationInfo.java b/src/org/thoughtcrime/securesms/revealable/ViewOnceExpirationInfo.java
new file mode 100644
index 0000000000..26722b0c30
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/revealable/ViewOnceExpirationInfo.java
@@ -0,0 +1,20 @@
+package org.thoughtcrime.securesms.revealable;
+
+public class ViewOnceExpirationInfo {
+
+ private final long messageId;
+ private final long receiveTime;
+
+ public ViewOnceExpirationInfo(long messageId, long receiveTime) {
+ this.messageId = messageId;
+ this.receiveTime = receiveTime;
+ }
+
+ public long getMessageId() {
+ return messageId;
+ }
+
+ public long getReceiveTime() {
+ return receiveTime;
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java b/src/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java
new file mode 100644
index 0000000000..1f7cf5d8a5
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java
@@ -0,0 +1,81 @@
+package org.thoughtcrime.securesms.revealable;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.ViewModelProviders;
+
+import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.logging.Log;
+import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
+import org.thoughtcrime.securesms.mms.GlideApp;
+import org.thoughtcrime.securesms.providers.BlobProvider;
+
+public class ViewOnceMessageActivity extends PassphraseRequiredActionBarActivity {
+
+ private static final String TAG = Log.tag(ViewOnceMessageActivity.class);
+
+ private static final String KEY_MESSAGE_ID = "message_id";
+ private static final String KEY_URI = "uri";
+
+ private ImageView image;
+ private View closeButton;
+ private ViewOnceMessageViewModel viewModel;
+ private Uri uri;
+
+ public static Intent getIntent(@NonNull Context context, long messageId, @NonNull Uri uri) {
+ Intent intent = new Intent(context, ViewOnceMessageActivity.class);
+ intent.putExtra(KEY_MESSAGE_ID, messageId);
+ intent.putExtra(KEY_URI, uri);
+ return intent;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState, boolean ready) {
+ super.onCreate(savedInstanceState, ready);
+ setContentView(R.layout.view_once_message_activity);
+
+ this.image = findViewById(R.id.view_once_image);
+ this.closeButton = findViewById(R.id.view_once_close_button);
+ this.uri = getIntent().getParcelableExtra(KEY_URI);
+
+ image.setOnClickListener(v -> finish());
+ closeButton.setOnClickListener(v -> finish());
+
+
+ initViewModel(getIntent().getLongExtra(KEY_MESSAGE_ID, -1), uri);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ BlobProvider.getInstance().delete(this, uri);
+ finish();
+ }
+
+ private void initViewModel(long messageId, @NonNull Uri uri) {
+ ViewOnceMessageRepository repository = new ViewOnceMessageRepository(this);
+
+ viewModel = ViewModelProviders.of(this, new ViewOnceMessageViewModel.Factory(getApplication(), messageId, repository))
+ .get(ViewOnceMessageViewModel.class);
+
+ viewModel.getMessage().observe(this, (message) -> {
+ if (message == null) return;
+
+ if (message.isPresent()) {
+ GlideApp.with(this)
+ .load(new DecryptableUri(uri))
+ .into(image);
+ } else {
+ image.setImageDrawable(null);
+ finish();
+ }
+ });
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/revealable/RevealableMessageManager.java b/src/org/thoughtcrime/securesms/revealable/ViewOnceMessageManager.java
similarity index 59%
rename from src/org/thoughtcrime/securesms/revealable/RevealableMessageManager.java
rename to src/org/thoughtcrime/securesms/revealable/ViewOnceMessageManager.java
index cda737ebb3..7e9550e31e 100644
--- a/src/org/thoughtcrime/securesms/revealable/RevealableMessageManager.java
+++ b/src/org/thoughtcrime/securesms/revealable/ViewOnceMessageManager.java
@@ -20,14 +20,14 @@ import org.thoughtcrime.securesms.service.TimedEventManager;
/**
* Manages clearing removable message content after they're opened.
*/
-public class RevealableMessageManager extends TimedEventManager {
+public class ViewOnceMessageManager extends TimedEventManager {
- private static final String TAG = Log.tag(RevealableMessageManager.class);
+ private static final String TAG = Log.tag(ViewOnceMessageManager.class);
private final MmsDatabase mmsDatabase;
private final AttachmentDatabase attachmentDatabase;
- public RevealableMessageManager(@NonNull Application application) {
+ public ViewOnceMessageManager(@NonNull Application application) {
super(application, "RevealableMessageManager");
this.mmsDatabase = DatabaseFactory.getMmsDatabase(application);
@@ -38,8 +38,8 @@ public class RevealableMessageManager extends TimedEventManager> message;
private final ContentObserver observer;
- private RevealableMessageViewModel(@NonNull Application application,
- long messageId,
- @NonNull RevealableMessageRepository repository)
+ private ViewOnceMessageViewModel(@NonNull Application application,
+ long messageId,
+ @NonNull ViewOnceMessageRepository repository)
{
this.application = application;
this.repository = repository;
@@ -74,13 +74,13 @@ class RevealableMessageViewModel extends ViewModel {
static class Factory extends ViewModelProvider.NewInstanceFactory {
- private final Application application;
- private final long messageId;
- private final RevealableMessageRepository repository;
+ private final Application application;
+ private final long messageId;
+ private final ViewOnceMessageRepository repository;
Factory(@NonNull Application application,
long messageId,
- @NonNull RevealableMessageRepository repository)
+ @NonNull ViewOnceMessageRepository repository)
{
this.application = application;
this.messageId = messageId;
@@ -90,7 +90,7 @@ class RevealableMessageViewModel extends ViewModel {
@Override
public @NonNull T create(@NonNull Class modelClass) {
//noinspection ConstantConditions
- return modelClass.cast(new RevealableMessageViewModel(application, messageId, repository));
+ return modelClass.cast(new ViewOnceMessageViewModel(application, messageId, repository));
}
}
}
diff --git a/src/org/thoughtcrime/securesms/revealable/ViewOnceUtil.java b/src/org/thoughtcrime/securesms/revealable/ViewOnceUtil.java
new file mode 100644
index 0000000000..6db290780c
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/revealable/ViewOnceUtil.java
@@ -0,0 +1,69 @@
+package org.thoughtcrime.securesms.revealable;
+
+import androidx.annotation.NonNull;
+
+import org.thoughtcrime.securesms.database.AttachmentDatabase;
+import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
+
+import java.util.concurrent.TimeUnit;
+
+public class ViewOnceUtil {
+
+ public static final long MAX_LIFESPAN = TimeUnit.DAYS.toMillis(30);
+
+ public static boolean isViewable(@NonNull MmsMessageRecord message) {
+ if (!message.isViewOnce()) {
+ return true;
+ }
+
+ if (message.isOutgoing()) {
+ return false;
+ }
+
+ if (message.getSlideDeck().getThumbnailSlide() == null) {
+ return false;
+ }
+
+ if (message.getSlideDeck().getThumbnailSlide().getUri() == null) {
+ return false;
+ }
+
+ if (message.getSlideDeck().getThumbnailSlide().getTransferState() != AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
+ return false;
+ }
+
+ if (isViewed(message)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean isViewed(@NonNull MmsMessageRecord message) {
+ if (!message.isViewOnce()) {
+ return false;
+ }
+
+ if (message.getDateReceived() + MAX_LIFESPAN <= System.currentTimeMillis()) {
+ return true;
+ }
+
+ if (message.getSlideDeck().getThumbnailSlide() != null && message.getSlideDeck().getThumbnailSlide().getTransferState() != AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
+ return false;
+ }
+
+ if (message.getSlideDeck().getThumbnailSlide() == null) {
+ return true;
+ }
+
+ if (message.getSlideDeck().getThumbnailSlide().getUri() == null) {
+ return true;
+ }
+
+ if (message.isOutgoing()) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/sms/IncomingJoinedMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingJoinedMessage.java
index 658caddb1a..8ce4bec8b4 100644
--- a/src/org/thoughtcrime/securesms/sms/IncomingJoinedMessage.java
+++ b/src/org/thoughtcrime/securesms/sms/IncomingJoinedMessage.java
@@ -7,7 +7,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
public class IncomingJoinedMessage extends IncomingTextMessage {
public IncomingJoinedMessage(Address sender) {
- super(sender, 1, System.currentTimeMillis(), null, Optional.absent(), 0, 0, false);
+ super(sender, 1, System.currentTimeMillis(), null, Optional.absent(), 0, false);
}
@Override
diff --git a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java
index 4ebddcd739..3d2e97d789 100644
--- a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java
+++ b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java
@@ -42,7 +42,6 @@ public class IncomingTextMessage implements Parcelable {
private final boolean push;
private final int subscriptionId;
private final long expiresInMillis;
- private final long revealDuration;
private final boolean unidentified;
public IncomingTextMessage(@NonNull Context context, @NonNull SmsMessage message, int subscriptionId) {
@@ -56,7 +55,6 @@ public class IncomingTextMessage implements Parcelable {
this.sentTimestampMillis = message.getTimestampMillis();
this.subscriptionId = subscriptionId;
this.expiresInMillis = 0;
- this.revealDuration = 0;
this.groupId = null;
this.push = false;
this.unidentified = false;
@@ -64,7 +62,7 @@ public class IncomingTextMessage implements Parcelable {
public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis,
String encodedBody, Optional group,
- long expiresInMillis, long revealDuration, boolean unidentified)
+ long expiresInMillis, boolean unidentified)
{
this.message = encodedBody;
this.sender = sender;
@@ -77,7 +75,6 @@ public class IncomingTextMessage implements Parcelable {
this.push = true;
this.subscriptionId = -1;
this.expiresInMillis = expiresInMillis;
- this.revealDuration = revealDuration;
this.unidentified = unidentified;
if (group.isPresent()) {
@@ -100,7 +97,6 @@ public class IncomingTextMessage implements Parcelable {
this.push = (in.readInt() == 1);
this.subscriptionId = in.readInt();
this.expiresInMillis = in.readLong();
- this.revealDuration = in.readLong();
this.unidentified = in.readInt() == 1;
}
@@ -117,7 +113,6 @@ public class IncomingTextMessage implements Parcelable {
this.push = base.isPush();
this.subscriptionId = base.getSubscriptionId();
this.expiresInMillis = base.getExpiresIn();
- this.revealDuration = base.getRevealDuration();
this.unidentified = base.isUnidentified();
}
@@ -140,7 +135,6 @@ public class IncomingTextMessage implements Parcelable {
this.push = fragments.get(0).isPush();
this.subscriptionId = fragments.get(0).getSubscriptionId();
this.expiresInMillis = fragments.get(0).getExpiresIn();
- this.revealDuration = fragments.get(0).getRevealDuration();
this.unidentified = fragments.get(0).isUnidentified();
}
@@ -158,7 +152,6 @@ public class IncomingTextMessage implements Parcelable {
this.push = true;
this.subscriptionId = -1;
this.expiresInMillis = 0;
- this.revealDuration = 0;
this.unidentified = false;
}
@@ -170,10 +163,6 @@ public class IncomingTextMessage implements Parcelable {
return expiresInMillis;
}
- public long getRevealDuration() {
- return revealDuration;
- }
-
public long getSentTimestampMillis() {
return sentTimestampMillis;
}
@@ -281,7 +270,6 @@ public class IncomingTextMessage implements Parcelable {
out.writeInt(push ? 1 : 0);
out.writeInt(subscriptionId);
out.writeLong(expiresInMillis);
- out.writeLong(revealDuration);
out.writeInt(unidentified ? 1 : 0);
}
}
diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java
index 71f8baf138..d64de8220d 100644
--- a/src/org/thoughtcrime/securesms/util/GroupUtil.java
+++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java
@@ -73,7 +73,7 @@ public class GroupUtil {
.setType(GroupContext.Type.QUIT)
.build();
- return Optional.of(new OutgoingGroupMediaMessage(groupRecipient, groupContext, null, System.currentTimeMillis(), 0, 0, null, Collections.emptyList(), Collections.emptyList()));
+ return Optional.of(new OutgoingGroupMediaMessage(groupRecipient, groupContext, null, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList()));
}
diff --git a/src/org/thoughtcrime/securesms/util/IdentityUtil.java b/src/org/thoughtcrime/securesms/util/IdentityUtil.java
index 6d00ed29ee..d6d66ce9e5 100644
--- a/src/org/thoughtcrime/securesms/util/IdentityUtil.java
+++ b/src/org/thoughtcrime/securesms/util/IdentityUtil.java
@@ -78,7 +78,7 @@ public class IdentityUtil {
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
if (remote) {
- IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0, 0, false);
+ IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0, false);
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
else incoming = new IncomingIdentityDefaultMessage(incoming);
@@ -98,7 +98,7 @@ public class IdentityUtil {
}
if (remote) {
- IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.absent(), 0, 0, false);
+ IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.absent(), 0, false);
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
else incoming = new IncomingIdentityDefaultMessage(incoming);
@@ -128,14 +128,14 @@ public class IdentityUtil {
while ((groupRecord = reader.getNext()) != null) {
if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive()) {
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
- IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0, 0, false);
+ IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0, false);
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
smsDatabase.insertMessageInbox(groupUpdate);
}
}
- IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.absent(), 0, 0, false);
+ IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.absent(), 0, false);
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
Optional insertResult = smsDatabase.insertMessageInbox(individualUpdate);
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index c840ccbcb8..b761fb19c1 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -183,7 +183,7 @@ public class TextSecurePreferences {
private static final String MEDIA_KEYBOARD_MODE = "pref_media_keyboard_mode";
- private static final String REVEALABLE_MESSAGE_DEFAULT = "pref_revealable_message_default";
+ private static final String VIEW_ONCE_DEFAULT = "pref_revealable_message_default";
private static final String SEEN_CAMERA_FIRST_TOOLTIP = "pref_seen_camera_first_tooltip";
@@ -1103,11 +1103,11 @@ public class TextSecurePreferences {
}
public static void setIsRevealableMessageEnabled(Context context, boolean value) {
- setBooleanPreference(context, REVEALABLE_MESSAGE_DEFAULT, value);
+ setBooleanPreference(context, VIEW_ONCE_DEFAULT, value);
}
public static boolean isRevealableMessageEnabled(Context context) {
- return getBooleanPreference(context, REVEALABLE_MESSAGE_DEFAULT, false);
+ return getBooleanPreference(context, VIEW_ONCE_DEFAULT, false);
}
public static void setHasSeenCameraFirstTooltip(Context context, boolean value) {