mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 13:18:34 +00:00
Update view-once message behavior.
This commit is contained in:
parent
3439eb4536
commit
57835dc8f1
@ -336,7 +336,7 @@
|
|||||||
android:windowSoftInputMode="stateUnchanged"
|
android:windowSoftInputMode="stateUnchanged"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".revealable.RevealableMessageActivity"
|
<activity android:name=".revealable.ViewOnceMessageActivity"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/TextSecure.FullScreenMedia"
|
android:theme="@style/TextSecure.FullScreenMedia"
|
||||||
android:windowSoftInputMode="stateHidden"
|
android:windowSoftInputMode="stateHidden"
|
||||||
@ -584,7 +584,7 @@
|
|||||||
|
|
||||||
<receiver android:name=".service.ExpirationListener" />
|
<receiver android:name=".service.ExpirationListener" />
|
||||||
|
|
||||||
<receiver android:name=".revealable.RevealableMessageManager$RevealAlarm" />
|
<receiver android:name=".revealable.ViewOnceMessageManager$ViewOnceAlarm" />
|
||||||
|
|
||||||
<provider android:name=".providers.PartProvider"
|
<provider android:name=".providers.PartProvider"
|
||||||
android:grantUriPermissions="true"
|
android:grantUriPermissions="true"
|
||||||
|
10
build.gradle
10
build.gradle
@ -86,7 +86,7 @@ dependencies {
|
|||||||
implementation 'org.conscrypt:conscrypt-android:2.0.0'
|
implementation 'org.conscrypt:conscrypt-android:2.0.0'
|
||||||
implementation 'org.signal:aesgcmprovider:0.0.3'
|
implementation 'org.signal:aesgcmprovider:0.0.3'
|
||||||
|
|
||||||
implementation 'org.whispersystems:signal-service-android:2.13.6'
|
implementation 'org.whispersystems:signal-service-android:2.13.7'
|
||||||
|
|
||||||
implementation 'org.whispersystems:webrtc-android:M75'
|
implementation 'org.whispersystems:webrtc-android:M75'
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ dependencyVerification {
|
|||||||
'com.google.android.exoplayer:exoplayer-core:b6ab34abac36bc2bc6934b7a50008162feca2c0fde91aaf1e8c1c22f2c16e2c0',
|
'com.google.android.exoplayer:exoplayer-core:b6ab34abac36bc2bc6934b7a50008162feca2c0fde91aaf1e8c1c22f2c16e2c0',
|
||||||
'org.conscrypt:conscrypt-android:400ca559a49b860a82862b22cee0e3110764bdcf7ee7c79e7479895c25cdfc09',
|
'org.conscrypt:conscrypt-android:400ca559a49b860a82862b22cee0e3110764bdcf7ee7c79e7479895c25cdfc09',
|
||||||
'org.signal:aesgcmprovider:6eb4422e8a618b3b76cb2096a3619d251f9e27989dc68307a1e5414c3710f2d1',
|
'org.signal:aesgcmprovider:6eb4422e8a618b3b76cb2096a3619d251f9e27989dc68307a1e5414c3710f2d1',
|
||||||
'org.whispersystems:signal-service-android:fa8c1b82d066bd6902ffd7e3a0c4343c3afa0379c26c78c06323c300d5afca7b',
|
'org.whispersystems:signal-service-android:5115aa434c52ca671c513995e6ae67d73f3abaaa605f9e6cf64c2e01da961c7e',
|
||||||
'org.whispersystems:webrtc-android:f8231bb57923afb243760213dc58924e85cce42f2f3cc8cb33a6d883672a921a',
|
'org.whispersystems:webrtc-android:f8231bb57923afb243760213dc58924e85cce42f2f3cc8cb33a6d883672a921a',
|
||||||
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
||||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||||
@ -265,7 +265,7 @@ dependencyVerification {
|
|||||||
'androidx.constraintlayout:constraintlayout-solver:965c177e64fbd81bd1d27b402b66ef9d7bc7b5cb5f718044bf7a453abc542045',
|
'androidx.constraintlayout:constraintlayout-solver:965c177e64fbd81bd1d27b402b66ef9d7bc7b5cb5f718044bf7a453abc542045',
|
||||||
'com.google.auto.value:auto-value-annotations:0e951fee8c31f60270bc46553a8586001b7b93dbb12aec06373aa99a150392c0',
|
'com.google.auto.value:auto-value-annotations:0e951fee8c31f60270bc46553a8586001b7b93dbb12aec06373aa99a150392c0',
|
||||||
'org.signal:signal-metadata-android:02323bc29317fa9d3b62fab0b507c94ba2e9bcc4a78d588888ffd313853757b3',
|
'org.signal:signal-metadata-android:02323bc29317fa9d3b62fab0b507c94ba2e9bcc4a78d588888ffd313853757b3',
|
||||||
'org.whispersystems:signal-service-java:b36c460bb8ed8ff134c35df87781dea2f30bc33fa8a10c8c3d9314dae752a7da',
|
'org.whispersystems:signal-service-java:34c1efbfdc9cca44946a92f1ba330066bc533056a4db3359a1af96e519893b2e',
|
||||||
'com.github.bumptech.glide:disklrucache:4696a81340eb6beee21ab93f703ed6e7ae49fb4ce3bc2fbc546e5bacd21b96b9',
|
'com.github.bumptech.glide:disklrucache:4696a81340eb6beee21ab93f703ed6e7ae49fb4ce3bc2fbc546e5bacd21b96b9',
|
||||||
'com.github.bumptech.glide:annotations:702a7521cb3f6d7e55edd66e90bda1a1975baf971d25f75b75638579f86bc69b',
|
'com.github.bumptech.glide:annotations:702a7521cb3f6d7e55edd66e90bda1a1975baf971d25f75b75638579f86bc69b',
|
||||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||||
@ -277,12 +277,12 @@ dependencyVerification {
|
|||||||
'org.whispersystems:signal-protocol-java:7f6df67a963acbab7716424b01b12fa7279f18a9623a2a7c8ba7b1c285830168',
|
'org.whispersystems:signal-protocol-java:7f6df67a963acbab7716424b01b12fa7279f18a9623a2a7c8ba7b1c285830168',
|
||||||
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
||||||
'com.googlecode.libphonenumber:libphonenumber:dbf4bf566d17a60044c19e282a619684e4b4abb0f9f9f24f843c55d19826ab5e',
|
'com.googlecode.libphonenumber:libphonenumber:dbf4bf566d17a60044c19e282a619684e4b4abb0f9f9f24f843c55d19826ab5e',
|
||||||
'com.fasterxml.jackson.core:jackson-databind:2351c3eba73a545db9079f5d6d768347ad72666537362c8220fe3e950a55a864',
|
'com.fasterxml.jackson.core:jackson-databind:fb262d42ea2de98044b62d393950a5aa050435fec38bbcadf2325cf7dc41b848',
|
||||||
'com.squareup.okhttp3:okhttp:07c3d82ca7eaf4722f00b2da807dc7860f6169ae60cfedcf5d40218f90880a46',
|
'com.squareup.okhttp3:okhttp:07c3d82ca7eaf4722f00b2da807dc7860f6169ae60cfedcf5d40218f90880a46',
|
||||||
'org.threeten:threetenbp:f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7',
|
'org.threeten:threetenbp:f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7',
|
||||||
'org.whispersystems:curve25519-android:b502bcf83efe001f09a7a9efda6f0fa772c43ed5924e97816296ed3503caa092',
|
'org.whispersystems:curve25519-android:b502bcf83efe001f09a7a9efda6f0fa772c43ed5924e97816296ed3503caa092',
|
||||||
'com.fasterxml.jackson.core:jackson-annotations:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a',
|
'com.fasterxml.jackson.core:jackson-annotations:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a',
|
||||||
'com.fasterxml.jackson.core:jackson-core:d934dab0bd48994eeea2c1b493cb547158a338a80b58c4fbc8e85fb0905e105f',
|
'com.fasterxml.jackson.core:jackson-core:3083079be6088db2ed0a0c6ff92204e0aa48fa1de9db5b59c468f35acf882c2c',
|
||||||
'com.squareup.okio:okio:693fa319a7e8843300602b204023b7674f106ebcb577f2dd5807212b66118bd2',
|
'com.squareup.okio:okio:693fa319a7e8843300602b204023b7674f106ebcb577f2dd5807212b66118bd2',
|
||||||
'org.whispersystems:curve25519-java:0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d',
|
'org.whispersystems:curve25519-java:0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d',
|
||||||
]
|
]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.thoughtcrime.securesms.revealable.RevealableMessageView
|
<org.thoughtcrime.securesms.revealable.ViewOnceMessageView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.thoughtcrime.securesms.revealable.RevealableMessageView
|
<org.thoughtcrime.securesms.revealable.ViewOnceMessageView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -7,13 +7,13 @@
|
|||||||
android:background="@color/core_black">
|
android:background="@color/core_black">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/reveal_image"
|
android:id="@+id/view_once_image"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:scaleType="fitCenter"/>
|
android:scaleType="fitCenter"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/reveal_close_button"
|
android:id="@+id/view_once_close_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="19dp"
|
android:layout_marginTop="19dp"
|
@ -351,7 +351,7 @@
|
|||||||
<attr name="labeledEditText_textLayout" format="reference" />
|
<attr name="labeledEditText_textLayout" format="reference" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="RevealableMessageView">
|
<declare-styleable name="ViewOnceMessageView">
|
||||||
<attr name="revealable_unopenedForegroundColor" format="color" />
|
<attr name="revealable_unopenedForegroundColor" format="color" />
|
||||||
<attr name="revealable_openedForegroundColor" format="color" />
|
<attr name="revealable_openedForegroundColor" format="color" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
@ -254,6 +254,7 @@
|
|||||||
<string name="ConversationFragment_deleting_messages">Deleting messages...</string>
|
<string name="ConversationFragment_deleting_messages">Deleting messages...</string>
|
||||||
<string name="ConversationFragment_quoted_message_not_found">Original message not found</string>
|
<string name="ConversationFragment_quoted_message_not_found">Original message not found</string>
|
||||||
<string name="ConversationFragment_quoted_message_no_longer_available">Original message no longer available</string>
|
<string name="ConversationFragment_quoted_message_no_longer_available">Original message no longer available</string>
|
||||||
|
<string name="ConversationFragment_failed_to_open_message">Failed to open message</string>
|
||||||
|
|
||||||
<!-- ConversationListActivity -->
|
<!-- ConversationListActivity -->
|
||||||
<string name="ConversationListActivity_there_is_no_browser_installed_on_your_device">There is no browser installed on your device.</string>
|
<string name="ConversationListActivity_there_is_no_browser_installed_on_your_device">There is no browser installed on your device.</string>
|
||||||
|
@ -62,7 +62,7 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
|||||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
import org.thoughtcrime.securesms.service.LocalBackupListener;
|
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.RotateSenderCertificateListener;
|
||||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||||
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
|
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 static final String TAG = ApplicationContext.class.getSimpleName();
|
||||||
|
|
||||||
private ExpiringMessageManager expiringMessageManager;
|
private ExpiringMessageManager expiringMessageManager;
|
||||||
private RevealableMessageManager revealableMessageManager;
|
private ViewOnceMessageManager viewOnceMessageManager;
|
||||||
private TypingStatusRepository typingStatusRepository;
|
private TypingStatusRepository typingStatusRepository;
|
||||||
private TypingStatusSender typingStatusSender;
|
private TypingStatusSender typingStatusSender;
|
||||||
private JobManager jobManager;
|
private JobManager jobManager;
|
||||||
@ -157,8 +157,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
|
|||||||
return expiringMessageManager;
|
return expiringMessageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RevealableMessageManager getRevealableMessageManager() {
|
public ViewOnceMessageManager getViewOnceMessageManager() {
|
||||||
return revealableMessageManager;
|
return viewOnceMessageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypingStatusRepository getTypingStatusRepository() {
|
public TypingStatusRepository getTypingStatusRepository() {
|
||||||
@ -252,7 +252,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeRevealableMessageManager() {
|
private void initializeRevealableMessageManager() {
|
||||||
this.revealableMessageManager = new RevealableMessageManager(this);
|
this.viewOnceMessageManager = new ViewOnceMessageManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTypingStatusRepository() {
|
private void initializeTypingStatusRepository() {
|
||||||
|
@ -38,7 +38,7 @@ public interface BindableConversationItem extends Unbindable {
|
|||||||
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
|
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
|
||||||
void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms);
|
void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms);
|
||||||
void onStickerClicked(@NonNull StickerLocator stickerLocator);
|
void onStickerClicked(@NonNull StickerLocator stickerLocator);
|
||||||
void onRevealableMessageClicked(@NonNull MmsMessageRecord messageRecord);
|
void onViewOnceMessageClicked(@NonNull MmsMessageRecord messageRecord);
|
||||||
void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView);
|
void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView);
|
||||||
void onAddToContactsClicked(@NonNull Contact contact);
|
void onAddToContactsClicked(@NonNull Contact contact);
|
||||||
void onMessageSharedContactClicked(@NonNull List<Recipient> choices);
|
void onMessageSharedContactClicked(@NonNull List<Recipient> choices);
|
||||||
|
@ -340,7 +340,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
.forData(inputStream, fileSize == null ? 0 : fileSize)
|
.forData(inputStream, fileSize == null ? 0 : fileSize)
|
||||||
.withMimeType(mimeType)
|
.withMimeType(mimeType)
|
||||||
.withFileName(fileName)
|
.withFileName(fileName)
|
||||||
.createForMultipleSessionsOnDisk(context, e -> Log.w(TAG, "Failed to write to disk.", e));
|
.createForMultipleSessionsOnDisk(context);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, ioe);
|
Log.w(TAG, ioe);
|
||||||
return null;
|
return null;
|
||||||
|
@ -7,6 +7,12 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
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 class TombstoneAttachment extends Attachment {
|
||||||
|
|
||||||
public TombstoneAttachment(@NonNull String contentType, boolean quote) {
|
public TombstoneAttachment(@NonNull String contentType, boolean quote) {
|
||||||
|
@ -50,7 +50,7 @@ public class AudioRecorder {
|
|||||||
captureUri = BlobProvider.getInstance()
|
captureUri = BlobProvider.getInstance()
|
||||||
.forData(new ParcelFileDescriptor.AutoCloseInputStream(fds[0]), 0)
|
.forData(new ParcelFileDescriptor.AutoCloseInputStream(fds[0]), 0)
|
||||||
.withMimeType(MediaUtil.AUDIO_AAC)
|
.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 = new AudioCodec();
|
||||||
|
|
||||||
audioCodec.start(new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]));
|
audioCodec.start(new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]));
|
||||||
|
@ -27,7 +27,6 @@ import org.thoughtcrime.securesms.database.OneTimePreKeyDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.SearchDatabase;
|
import org.thoughtcrime.securesms.database.SearchDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SessionDatabase;
|
import org.thoughtcrime.securesms.database.SessionDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
|
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.StickerDatabase;
|
import org.thoughtcrime.securesms.database.StickerDatabase;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||||
@ -255,18 +254,18 @@ public class FullBackupExporter extends FullBackupBase {
|
|||||||
|
|
||||||
private static boolean isNonExpiringMessage(@NonNull Cursor cursor) {
|
private static boolean isNonExpiringMessage(@NonNull Cursor cursor) {
|
||||||
return cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 &&
|
return cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 &&
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_DURATION)) <= 0;
|
cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isForNonExpiringMessage(@NonNull SQLiteDatabase db, long mmsId) {
|
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 where = MmsDatabase.ID + " = ?";
|
||||||
String[] args = new String[] { String.valueOf(mmsId) };
|
String[] args = new String[] { String.valueOf(mmsId) };
|
||||||
|
|
||||||
try (Cursor mmsCursor = db.query(MmsDatabase.TABLE_NAME, columns, where, args, null, null, null)) {
|
try (Cursor mmsCursor = db.query(MmsDatabase.TABLE_NAME, columns, where, args, null, null, null)) {
|
||||||
if (mmsCursor != null && mmsCursor.moveToFirst()) {
|
if (mmsCursor != null && mmsCursor.moveToFirst()) {
|
||||||
return mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN)) == 0 &&
|
return mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN)) == 0 &&
|
||||||
mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_DURATION)) == 0;
|
mmsCursor.getLong(mmsCursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,8 +542,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
boolean initiating = threadId == -1;
|
boolean initiating = threadId == -1;
|
||||||
TransportOption transport = data.getParcelableExtra(MediaSendActivity.EXTRA_TRANSPORT);
|
TransportOption transport = data.getParcelableExtra(MediaSendActivity.EXTRA_TRANSPORT);
|
||||||
String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
|
String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
|
||||||
long revealDuration = data.getLongExtra(MediaSendActivity.EXTRA_REVEAL_DURATION, 0);
|
boolean viewOnce = data.getBooleanExtra(MediaSendActivity.EXTRA_VIEW_ONCE, false);
|
||||||
QuoteModel quote = (revealDuration == 0) ? inputPanel.getQuote().orNull() : null;
|
QuoteModel quote = viewOnce ? inputPanel.getQuote().orNull() : null;
|
||||||
SlideDeck slideDeck = new SlideDeck();
|
SlideDeck slideDeck = new SlideDeck();
|
||||||
|
|
||||||
if (transport == null) {
|
if (transport == null) {
|
||||||
@ -575,7 +575,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
Collections.emptyList(),
|
Collections.emptyList(),
|
||||||
Collections.emptyList(),
|
Collections.emptyList(),
|
||||||
expiresIn,
|
expiresIn,
|
||||||
revealDuration,
|
viewOnce,
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
initiating,
|
initiating,
|
||||||
true).addListener(new AssertedSuccessListener<Void>() {
|
true).addListener(new AssertedSuccessListener<Void>() {
|
||||||
@ -1813,7 +1813,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||||
boolean initiating = threadId == -1;
|
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) {
|
private void selectContactInfo(ContactData contactData) {
|
||||||
@ -2135,7 +2135,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
} else if (!forceSms && identityRecords.isUntrusted()) {
|
} else if (!forceSms && identityRecords.isUntrusted()) {
|
||||||
handleUntrustedRecipients();
|
handleUntrustedRecipients();
|
||||||
} else if (isMediaMessage) {
|
} else if (isMediaMessage) {
|
||||||
sendMediaMessage(forceSms, expiresIn, 0, subscriptionId, initiating);
|
sendMediaMessage(forceSms, expiresIn, false, subscriptionId, initiating);
|
||||||
} else {
|
} else {
|
||||||
sendTextMessage(forceSms, expiresIn, subscriptionId, initiating);
|
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
|
throws InvalidMessageException
|
||||||
{
|
{
|
||||||
Log.i(TAG, "Sending media message...");
|
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<Void> sendMediaMessage(final boolean forceSms,
|
private ListenableFuture<Void> sendMediaMessage(final boolean forceSms,
|
||||||
@ -2165,7 +2165,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
List<Contact> contacts,
|
List<Contact> contacts,
|
||||||
List<LinkPreview> previews,
|
List<LinkPreview> previews,
|
||||||
final long expiresIn,
|
final long expiresIn,
|
||||||
final long revealDuration,
|
final boolean viewOnce,
|
||||||
final int subscriptionId,
|
final int subscriptionId,
|
||||||
final boolean initiating,
|
final boolean initiating,
|
||||||
final boolean clearComposeBox)
|
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<Void> future = new SettableFuture<>();
|
final SettableFuture<Void> future = new SettableFuture<>();
|
||||||
final Context context = getApplicationContext();
|
final Context context = getApplicationContext();
|
||||||
@ -2385,7 +2385,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
SlideDeck slideDeck = new SlideDeck();
|
SlideDeck slideDeck = new SlideDeck();
|
||||||
slideDeck.addSlide(audioSlide);
|
slideDeck.addSlide(audioSlide);
|
||||||
|
|
||||||
sendMediaMessage(forceSms, "", slideDeck, inputPanel.getQuote().orNull(), Collections.emptyList(), Collections.emptyList(), expiresIn, 0, subscriptionId, initiating, true).addListener(new AssertedSuccessListener<Void>() {
|
sendMediaMessage(forceSms, "", slideDeck, inputPanel.getQuote().orNull(), Collections.emptyList(), Collections.emptyList(), expiresIn, false, subscriptionId, initiating, true).addListener(new AssertedSuccessListener<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Void nothing) {
|
public void onSuccess(Void nothing) {
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@ -2513,7 +2513,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
slideDeck.addSlide(stickerSlide);
|
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 {
|
} else {
|
||||||
SlideDeck slideDeck = messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck();
|
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);
|
Attachment attachment = new TombstoneAttachment(slideDeck.getSlides().get(0).getContentType(), true);
|
||||||
slideDeck = new SlideDeck();
|
slideDeck = new SlideDeck();
|
||||||
slideDeck.addSlide(MediaUtil.getSlideForAttachment(this, attachment));
|
slideDeck.addSlide(MediaUtil.getSlideForAttachment(this, attachment));
|
||||||
|
@ -79,7 +79,7 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
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.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
|
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.PartAuthority;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.profiles.UnknownSenderView;
|
import org.thoughtcrime.securesms.profiles.UnknownSenderView;
|
||||||
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.revealable.RevealableMessageActivity;
|
import org.thoughtcrime.securesms.revealable.ViewOnceMessageActivity;
|
||||||
import org.thoughtcrime.securesms.revealable.RevealableUtil;
|
import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
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.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
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.concurrent.SimpleTask;
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
@ -963,35 +965,46 @@ public class ConversationFragment extends Fragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRevealableMessageClicked(@NonNull MmsMessageRecord messageRecord) {
|
public void onViewOnceMessageClicked(@NonNull MmsMessageRecord messageRecord) {
|
||||||
if (messageRecord.getRevealDuration() == 0) {
|
if (!messageRecord.isViewOnce()) {
|
||||||
throw new AssertionError("Non-revealable message clicked.");
|
throw new AssertionError("Non-revealable message clicked.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageRecord.getRevealStartTime() == 0) {
|
if (!ViewOnceUtil.isViewable(messageRecord)) {
|
||||||
SimpleTask.run(getLifecycle(), () -> {
|
Log.w(TAG, "View-once photo is not viewable!");
|
||||||
if (!messageRecord.isOutgoing()) {
|
return;
|
||||||
Log.i(TAG, "Marking revealable message as opened.");
|
}
|
||||||
|
|
||||||
DatabaseFactory.getMmsDatabase(requireContext()).markRevealStarted(messageRecord.getId());
|
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())
|
ApplicationContext.getInstance(requireContext())
|
||||||
.getRevealableMessageManager()
|
.getViewOnceMessageManager()
|
||||||
.scheduleIfNecessary();
|
.scheduleIfNecessary();
|
||||||
|
|
||||||
ApplicationContext.getInstance(requireContext())
|
ApplicationContext.getInstance(requireContext())
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new MultiDeviceRevealUpdateJob(new MessagingDatabase.SyncMessageId(messageRecord.getIndividualRecipient().getAddress(), messageRecord.getDateSent())));
|
.add(new MultiDeviceViewOnceOpenJob(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 tempUri;
|
||||||
}
|
} catch (IOException e) {
|
||||||
return null;
|
return null;
|
||||||
}, (nothing) -> {
|
|
||||||
startActivity(RevealableMessageActivity.getIntent(requireContext(), messageRecord.getId()));
|
|
||||||
});
|
|
||||||
} else if (RevealableUtil.isViewable(messageRecord)) {
|
|
||||||
startActivity(RevealableMessageActivity.getIntent(requireContext(), messageRecord.getId()));
|
|
||||||
}
|
}
|
||||||
|
}, (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
|
@Override
|
||||||
|
@ -68,7 +68,7 @@ import org.thoughtcrime.securesms.components.DocumentView;
|
|||||||
import org.thoughtcrime.securesms.components.LinkPreviewView;
|
import org.thoughtcrime.securesms.components.LinkPreviewView;
|
||||||
import org.thoughtcrime.securesms.components.Outliner;
|
import org.thoughtcrime.securesms.components.Outliner;
|
||||||
import org.thoughtcrime.securesms.components.QuoteView;
|
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.SharedContactView;
|
||||||
import org.thoughtcrime.securesms.components.StickerView;
|
import org.thoughtcrime.securesms.components.StickerView;
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
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.mms.TextSlide;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
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.stickers.StickerUrl;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
@ -163,7 +163,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
private Stub<SharedContactView> sharedContactStub;
|
private Stub<SharedContactView> sharedContactStub;
|
||||||
private Stub<LinkPreviewView> linkPreviewStub;
|
private Stub<LinkPreviewView> linkPreviewStub;
|
||||||
private Stub<StickerView> stickerStub;
|
private Stub<StickerView> stickerStub;
|
||||||
private Stub<RevealableMessageView> revealableStub;
|
private Stub<ViewOnceMessageView> revealableStub;
|
||||||
private @Nullable EventListener eventListener;
|
private @Nullable EventListener eventListener;
|
||||||
|
|
||||||
private int defaultBubbleColor;
|
private int defaultBubbleColor;
|
||||||
@ -175,7 +175,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
private final SharedContactEventListener sharedContactEventListener = new SharedContactEventListener();
|
private final SharedContactEventListener sharedContactEventListener = new SharedContactEventListener();
|
||||||
private final SharedContactClickListener sharedContactClickListener = new SharedContactClickListener();
|
private final SharedContactClickListener sharedContactClickListener = new SharedContactClickListener();
|
||||||
private final LinkPreviewClickListener linkPreviewClickListener = new LinkPreviewClickListener();
|
private final LinkPreviewClickListener linkPreviewClickListener = new LinkPreviewClickListener();
|
||||||
private final RevealableMessageClickListener revealableClickListener = new RevealableMessageClickListener();
|
private final ViewOnceMessageClickListener revealableClickListener = new ViewOnceMessageClickListener();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
protected void dispatchDraw(Canvas canvas) {
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
super.dispatchDraw(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.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());
|
outliner.draw(canvas, bodyBubble.getTop() + getPaddingTop(), bodyBubble.getRight(), bodyBubble.getBottom() + getPaddingTop(), bodyBubble.getLeft());
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
int availableWidth;
|
int availableWidth;
|
||||||
if (hasAudio(messageRecord)) {
|
if (hasAudio(messageRecord)) {
|
||||||
availableWidth = audioViewStub.get().getMeasuredWidth() + ViewUtil.getLeftMargin(audioViewStub.get()) + ViewUtil.getRightMargin(audioViewStub.get());
|
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();
|
availableWidth = mediaThumbnailStub.get().getMeasuredWidth();
|
||||||
} else {
|
} else {
|
||||||
availableWidth = bodyBubble.getMeasuredWidth() - bodyBubble.getPaddingLeft() - bodyBubble.getPaddingRight();
|
availableWidth = bodyBubble.getMeasuredWidth() - bodyBubble.getPaddingLeft() - bodyBubble.getPaddingRight();
|
||||||
@ -361,7 +361,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
|
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
|
||||||
footer.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_text_secondary_color));
|
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));
|
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);
|
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.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_text_secondary_color));
|
||||||
footer.setIconColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_icon_color));
|
footer.setIconColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_sent_icon_color));
|
||||||
@ -440,7 +440,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
!hasDocument(messageRecord) &&
|
!hasDocument(messageRecord) &&
|
||||||
!hasSharedContact(messageRecord) &&
|
!hasSharedContact(messageRecord) &&
|
||||||
!hasSticker(messageRecord) &&
|
!hasSticker(messageRecord) &&
|
||||||
!hasRevealableMessage(messageRecord);
|
!isViewOnceMessage(messageRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasDocument(MessageRecord messageRecord) {
|
private boolean hasDocument(MessageRecord messageRecord) {
|
||||||
@ -477,8 +477,8 @@ public class ConversationItem extends LinearLayout
|
|||||||
!StickerUrl.isValidShareLink(linkPreview.getUrl());
|
!StickerUrl.isValidShareLink(linkPreview.getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasRevealableMessage(MessageRecord messageRecord) {
|
private boolean isViewOnceMessage(MessageRecord messageRecord) {
|
||||||
return messageRecord.isMms() && ((MmsMessageRecord) messageRecord).getRevealDuration() > 0;
|
return messageRecord.isMms() && ((MmsMessageRecord) messageRecord).isViewOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBodyText(MessageRecord messageRecord, @Nullable String searchQuery) {
|
private void setBodyText(MessageRecord messageRecord, @Nullable String searchQuery) {
|
||||||
@ -512,7 +512,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
{
|
{
|
||||||
boolean showControls = !messageRecord.isFailed();
|
boolean showControls = !messageRecord.isFailed();
|
||||||
|
|
||||||
if (hasRevealableMessage(messageRecord)) {
|
if (isViewOnceMessage(messageRecord)) {
|
||||||
revealableStub.get().setVisibility(VISIBLE);
|
revealableStub.get().setVisibility(VISIBLE);
|
||||||
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
|
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
|
||||||
if (audioViewStub.resolved()) audioViewStub.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) {
|
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));
|
groupSender.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_sticker_author_color));
|
||||||
groupSenderProfileName.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)) {
|
} 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
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
RevealableMessageView revealView = (RevealableMessageView) view;
|
ViewOnceMessageView revealView = (ViewOnceMessageView) view;
|
||||||
|
|
||||||
if (eventListener != null && batchSelected.isEmpty() && messageRecord.isMms() && RevealableUtil.isViewable((MmsMessageRecord) messageRecord)) {
|
if (eventListener != null && batchSelected.isEmpty() && messageRecord.isMms() && ViewOnceUtil.isViewable((MmsMessageRecord) messageRecord)) {
|
||||||
eventListener.onRevealableMessageClicked((MmsMessageRecord) messageRecord);
|
eventListener.onViewOnceMessageClicked((MmsMessageRecord) messageRecord);
|
||||||
} else if (batchSelected.isEmpty() && messageRecord.isMms() && revealView.requiresTapToDownload((MmsMessageRecord) messageRecord)) {
|
} else if (batchSelected.isEmpty() && messageRecord.isMms() && revealView.requiresTapToDownload((MmsMessageRecord) messageRecord)) {
|
||||||
singleDownloadClickListener.onClick(view, ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlide());
|
singleDownloadClickListener.onClick(view, ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlide());
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,7 +47,7 @@ public class MediaDatabase extends Database {
|
|||||||
+ "WHERE " + AttachmentDatabase.MMS_ID + " IN (SELECT " + MmsSmsColumns.ID
|
+ "WHERE " + AttachmentDatabase.MMS_ID + " IN (SELECT " + MmsSmsColumns.ID
|
||||||
+ " FROM " + MmsDatabase.TABLE_NAME
|
+ " FROM " + MmsDatabase.TABLE_NAME
|
||||||
+ " WHERE " + MmsDatabase.THREAD_ID + " = ?) AND (%s) AND "
|
+ " WHERE " + MmsDatabase.THREAD_ID + " = ?) AND (%s) AND "
|
||||||
+ MmsDatabase.REVEAL_DURATION + " = 0 AND "
|
+ MmsDatabase.VIEW_ONCE + " = 0 AND "
|
||||||
+ AttachmentDatabase.DATA + " IS NOT NULL AND "
|
+ AttachmentDatabase.DATA + " IS NOT NULL AND "
|
||||||
+ AttachmentDatabase.QUOTE + " = 0 AND "
|
+ AttachmentDatabase.QUOTE + " = 0 AND "
|
||||||
+ AttachmentDatabase.STICKER_PACK_ID + " IS NULL "
|
+ AttachmentDatabase.STICKER_PACK_ID + " IS NULL "
|
||||||
|
@ -63,8 +63,8 @@ import org.thoughtcrime.securesms.mms.QuoteModel;
|
|||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.revealable.RevealExpirationInfo;
|
import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
|
||||||
import org.thoughtcrime.securesms.revealable.RevealableUtil;
|
import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
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 SHARED_CONTACTS = "shared_contacts";
|
||||||
static final String LINK_PREVIEWS = "previews";
|
static final String LINK_PREVIEWS = "previews";
|
||||||
|
|
||||||
public static final String REVEAL_DURATION = "reveal_duration";
|
public static final String VIEW_ONCE = "reveal_duration";
|
||||||
public static final String REVEAL_START_TIME = "reveal_start_time";
|
|
||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
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, " +
|
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, " +
|
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + QUOTE_ID + " INTEGER DEFAULT 0, " +
|
||||||
QUOTE_AUTHOR + " TEXT, " + QUOTE_BODY + " TEXT, " + QUOTE_ATTACHMENT + " INTEGER DEFAULT -1, " +
|
QUOTE_AUTHOR + " TEXT, " + QUOTE_BODY + " TEXT, " + QUOTE_ATTACHMENT + " INTEGER DEFAULT -1, " +
|
||||||
QUOTE_MISSING + " INTEGER DEFAULT 0, " + SHARED_CONTACTS + " TEXT, " + UNIDENTIFIED + " INTEGER DEFAULT 0, " +
|
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 = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
"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,
|
BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_ID,
|
||||||
DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_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,
|
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(" +
|
"json_group_array(json_object(" +
|
||||||
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
|
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
|
||||||
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
|
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
|
||||||
@ -437,60 +436,6 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
notifyConversationListeners(threadId);
|
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<RevealExpirationInfo> markRevealStarted(@NonNull SyncMessageId messageId, long proposedStartTime) {
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
||||||
List<RevealExpirationInfo> 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) {
|
public void markAsNotified(long id) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
@ -668,7 +613,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
||||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
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));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||||
int distributionType = DatabaseFactory.getThreadDatabase(context).getDistributionType(threadId);
|
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))) {
|
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)) {
|
} else if (Types.isExpirationTimerUpdate(outboxType)) {
|
||||||
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
|
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)) {
|
if (Types.isSecureType(outboxType)) {
|
||||||
return new OutgoingSecureMediaMessage(message);
|
return new OutgoingSecureMediaMessage(message);
|
||||||
@ -824,7 +769,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(READ, 1);
|
contentValues.put(READ, 1);
|
||||||
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
||||||
contentValues.put(EXPIRES_IN, request.getExpiresIn());
|
contentValues.put(EXPIRES_IN, request.getExpiresIn());
|
||||||
contentValues.put(REVEAL_DURATION, request.getRevealDuration());
|
contentValues.put(VIEW_ONCE, request.isViewOnce());
|
||||||
|
|
||||||
List<Attachment> attachments = new LinkedList<>();
|
List<Attachment> attachments = new LinkedList<>();
|
||||||
|
|
||||||
@ -892,7 +837,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(PART_COUNT, retrieved.getAttachments().size());
|
contentValues.put(PART_COUNT, retrieved.getAttachments().size());
|
||||||
contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
|
contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
|
||||||
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
|
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(READ, retrieved.isExpirationUpdate() ? 1 : 0);
|
||||||
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
|
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
|
||||||
|
|
||||||
@ -1048,7 +993,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
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(ADDRESS, message.getRecipient().getAddress().serialize());
|
||||||
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(Long::longValue).sum());
|
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());
|
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);
|
database.delete(TABLE_NAME, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable RevealExpirationInfo getNearestExpiringRevealableMessage() {
|
public @Nullable
|
||||||
|
ViewOnceExpirationInfo getNearestExpiringViewOnceMessage() {
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
RevealExpirationInfo info = null;
|
ViewOnceExpirationInfo info = null;
|
||||||
long nearestExpiration = Long.MAX_VALUE;
|
long nearestExpiration = Long.MAX_VALUE;
|
||||||
|
|
||||||
String query = "SELECT " +
|
String query = "SELECT " +
|
||||||
TABLE_NAME + "." + ID + ", " +
|
TABLE_NAME + "." + ID + ", " +
|
||||||
REVEAL_DURATION + ", " +
|
VIEW_ONCE + ", " +
|
||||||
REVEAL_START_TIME + ", " +
|
|
||||||
DATE_RECEIVED + " " +
|
DATE_RECEIVED + " " +
|
||||||
"FROM " + TABLE_NAME + " INNER JOIN " + AttachmentDatabase.TABLE_NAME + " " +
|
"FROM " + TABLE_NAME + " INNER JOIN " + AttachmentDatabase.TABLE_NAME + " " +
|
||||||
"ON " + TABLE_NAME + "." + ID + " = " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " " +
|
"ON " + TABLE_NAME + "." + ID + " = " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " " +
|
||||||
"WHERE " +
|
"WHERE " +
|
||||||
REVEAL_DURATION + " > 0 AND " +
|
VIEW_ONCE + " > 0 AND " +
|
||||||
"(" + AttachmentDatabase.DATA + " NOT NULL OR " + AttachmentDatabase.TRANSFER_STATE + " != ?)";
|
"(" + AttachmentDatabase.DATA + " NOT NULL OR " + AttachmentDatabase.TRANSFER_STATE + " != ?)";
|
||||||
String[] args = new String[] { String.valueOf(AttachmentDatabase.TRANSFER_PROGRESS_DONE) };
|
String[] args = new String[] { String.valueOf(AttachmentDatabase.TRANSFER_PROGRESS_DONE) };
|
||||||
|
|
||||||
try (Cursor cursor = db.rawQuery(query, args)) {
|
try (Cursor cursor = db.rawQuery(query, args)) {
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
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 dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(DATE_RECEIVED));
|
||||||
long expiresAt = revealStartTime > 0 ? revealStartTime + revealDuration
|
long expiresAt = dateReceived + ViewOnceUtil.MAX_LIFESPAN;
|
||||||
: dateReceived + RevealableUtil.MAX_LIFESPAN;
|
|
||||||
|
|
||||||
if (info == null || expiresAt < nearestExpiration) {
|
if (info == null || expiresAt < nearestExpiration) {
|
||||||
info = new RevealExpirationInfo(id, dateReceived, revealStartTime, revealDuration);
|
info = new ViewOnceExpirationInfo(id, dateReceived);
|
||||||
nearestExpiration = expiresAt;
|
nearestExpiration = expiresAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1442,8 +1384,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
message.getSubscriptionId(),
|
message.getSubscriptionId(),
|
||||||
message.getExpiresIn(),
|
message.getExpiresIn(),
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
message.getRevealDuration(),
|
message.isViewOnce(),
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
message.getOutgoingQuote() != null ?
|
message.getOutgoingQuote() != null ?
|
||||||
new Quote(message.getOutgoingQuote().getId(),
|
new Quote(message.getOutgoingQuote().getId(),
|
||||||
@ -1541,8 +1482,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
||||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
||||||
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.UNIDENTIFIED)) == 1;
|
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.UNIDENTIFIED)) == 1;
|
||||||
long revealDuration = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_DURATION));
|
boolean isViewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) == 1;
|
||||||
long revealStartTime = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.REVEAL_START_TIME));
|
|
||||||
|
|
||||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
||||||
readReceiptCount = 0;
|
readReceiptCount = 0;
|
||||||
@ -1563,8 +1503,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
|
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
|
||||||
threadId, body, slideDeck, partCount, box, mismatches,
|
threadId, body, slideDeck, partCount, box, mismatches,
|
||||||
networkFailures, subscriptionId, expiresIn, expireStarted,
|
networkFailures, subscriptionId, expiresIn, expireStarted,
|
||||||
revealDuration, revealStartTime,
|
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified);
|
||||||
readReceiptCount, quote, contacts, previews, unidentified);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recipient getRecipientFor(String serialized) {
|
private Recipient getRecipientFor(String serialized) {
|
||||||
|
@ -71,8 +71,7 @@ public class MmsSmsDatabase extends Database {
|
|||||||
MmsDatabase.QUOTE_ATTACHMENT,
|
MmsDatabase.QUOTE_ATTACHMENT,
|
||||||
MmsDatabase.SHARED_CONTACTS,
|
MmsDatabase.SHARED_CONTACTS,
|
||||||
MmsDatabase.LINK_PREVIEWS,
|
MmsDatabase.LINK_PREVIEWS,
|
||||||
MmsDatabase.REVEAL_DURATION,
|
MmsDatabase.VIEW_ONCE};
|
||||||
MmsDatabase.REVEAL_START_TIME};
|
|
||||||
|
|
||||||
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
||||||
super(context, databaseHelper);
|
super(context, databaseHelper);
|
||||||
@ -273,8 +272,7 @@ public class MmsSmsDatabase extends Database {
|
|||||||
MmsDatabase.QUOTE_ATTACHMENT,
|
MmsDatabase.QUOTE_ATTACHMENT,
|
||||||
MmsDatabase.SHARED_CONTACTS,
|
MmsDatabase.SHARED_CONTACTS,
|
||||||
MmsDatabase.LINK_PREVIEWS,
|
MmsDatabase.LINK_PREVIEWS,
|
||||||
MmsDatabase.REVEAL_DURATION,
|
MmsDatabase.VIEW_ONCE};
|
||||||
MmsDatabase.REVEAL_START_TIME};
|
|
||||||
|
|
||||||
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||||
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||||
@ -301,8 +299,7 @@ public class MmsSmsDatabase extends Database {
|
|||||||
MmsDatabase.QUOTE_ATTACHMENT,
|
MmsDatabase.QUOTE_ATTACHMENT,
|
||||||
MmsDatabase.SHARED_CONTACTS,
|
MmsDatabase.SHARED_CONTACTS,
|
||||||
MmsDatabase.LINK_PREVIEWS,
|
MmsDatabase.LINK_PREVIEWS,
|
||||||
MmsDatabase.REVEAL_DURATION,
|
MmsDatabase.VIEW_ONCE};
|
||||||
MmsDatabase.REVEAL_START_TIME};
|
|
||||||
|
|
||||||
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
|
||||||
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
|
||||||
@ -373,8 +370,7 @@ public class MmsSmsDatabase extends Database {
|
|||||||
mmsColumnsPresent.add(MmsDatabase.QUOTE_ATTACHMENT);
|
mmsColumnsPresent.add(MmsDatabase.QUOTE_ATTACHMENT);
|
||||||
mmsColumnsPresent.add(MmsDatabase.SHARED_CONTACTS);
|
mmsColumnsPresent.add(MmsDatabase.SHARED_CONTACTS);
|
||||||
mmsColumnsPresent.add(MmsDatabase.LINK_PREVIEWS);
|
mmsColumnsPresent.add(MmsDatabase.LINK_PREVIEWS);
|
||||||
mmsColumnsPresent.add(MmsDatabase.REVEAL_DURATION);
|
mmsColumnsPresent.add(MmsDatabase.VIEW_ONCE);
|
||||||
mmsColumnsPresent.add(MmsDatabase.REVEAL_START_TIME);
|
|
||||||
|
|
||||||
Set<String> smsColumnsPresent = new HashSet<>();
|
Set<String> smsColumnsPresent = new HashSet<>();
|
||||||
smsColumnsPresent.add(MmsSmsColumns.ID);
|
smsColumnsPresent.add(MmsSmsColumns.ID);
|
||||||
|
@ -46,7 +46,6 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
import org.thoughtcrime.securesms.util.DelimiterUtil;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.Pair;
|
import org.whispersystems.libsignal.util.Pair;
|
||||||
@ -630,7 +629,7 @@ public class ThreadDatabase extends Database {
|
|||||||
SlideDeck slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
SlideDeck slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
||||||
Slide thumbnail = slideDeck.getThumbnailSlide();
|
Slide thumbnail = slideDeck.getThumbnailSlide();
|
||||||
|
|
||||||
if (thumbnail != null && ((MmsMessageRecord) record).getRevealDuration() == 0) {
|
if (thumbnail != null && !((MmsMessageRecord) record).isViewOnce()) {
|
||||||
return thumbnail.getThumbnailUri();
|
return thumbnail.getThumbnailUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,7 +649,7 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Extra getExtrasFor(MessageRecord record) {
|
private @Nullable Extra getExtrasFor(MessageRecord record) {
|
||||||
if (record.isMms() && ((MmsMessageRecord) record).getRevealDuration() > 0) {
|
if (record.isMms() && ((MmsMessageRecord) record).isViewOnce()) {
|
||||||
return Extra.forRevealableMessage();
|
return Extra.forRevealableMessage();
|
||||||
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
|
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
|
||||||
return Extra.forSticker();
|
return Extra.forSticker();
|
||||||
|
@ -67,11 +67,13 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int JOBMANAGER_STRIKES_BACK = 20;
|
private static final int JOBMANAGER_STRIKES_BACK = 20;
|
||||||
private static final int STICKERS = 21;
|
private static final int STICKERS = 21;
|
||||||
private static final int REVEALABLE_MESSAGES = 22;
|
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 static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
private final DatabaseSecret databaseSecret;
|
private final DatabaseSecret databaseSecret;
|
||||||
|
|
||||||
public SQLCipherOpenHelper(@NonNull Context context, @NonNull 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");
|
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();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -55,13 +55,13 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
|
|||||||
List<IdentityKeyMismatch> mismatches,
|
List<IdentityKeyMismatch> mismatches,
|
||||||
List<NetworkFailure> failures, int subscriptionId,
|
List<NetworkFailure> failures, int subscriptionId,
|
||||||
long expiresIn, long expireStarted,
|
long expiresIn, long expireStarted,
|
||||||
long revealDuration, long revealStartTime, int readReceiptCount,
|
boolean viewOnce, int readReceiptCount,
|
||||||
@Nullable Quote quote, @NonNull List<Contact> contacts,
|
@Nullable Quote quote, @NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> linkPreviews, boolean unidentified)
|
@NonNull List<LinkPreview> linkPreviews, boolean unidentified)
|
||||||
{
|
{
|
||||||
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
|
||||||
dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
|
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);
|
readReceiptCount, quote, contacts, linkPreviews, unidentified);
|
||||||
this.partCount = partCount;
|
this.partCount = partCount;
|
||||||
}
|
}
|
||||||
|
@ -22,15 +22,14 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
|||||||
private final @NonNull List<Contact> contacts = new LinkedList<>();
|
private final @NonNull List<Contact> contacts = new LinkedList<>();
|
||||||
private final @NonNull List<LinkPreview> linkPreviews = new LinkedList<>();
|
private final @NonNull List<LinkPreview> linkPreviews = new LinkedList<>();
|
||||||
|
|
||||||
private final long revealDuration;
|
private final boolean viewOnce;
|
||||||
private final long revealStartTime;
|
|
||||||
|
|
||||||
MmsMessageRecord(long id, String body, Recipient conversationRecipient,
|
MmsMessageRecord(long id, String body, Recipient conversationRecipient,
|
||||||
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
Recipient individualRecipient, int recipientDeviceId, long dateSent,
|
||||||
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
|
||||||
long type, List<IdentityKeyMismatch> mismatches,
|
long type, List<IdentityKeyMismatch> mismatches,
|
||||||
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
List<NetworkFailure> networkFailures, int subscriptionId, long expiresIn,
|
||||||
long expireStarted, long revealDuration, long revealStartTime,
|
long expireStarted, boolean viewOnce,
|
||||||
@NonNull SlideDeck slideDeck, int readReceiptCount,
|
@NonNull SlideDeck slideDeck, int readReceiptCount,
|
||||||
@Nullable Quote quote, @NonNull List<Contact> contacts,
|
@Nullable Quote quote, @NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> linkPreviews, boolean unidentified)
|
@NonNull List<LinkPreview> linkPreviews, boolean unidentified)
|
||||||
@ -39,8 +38,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
|||||||
|
|
||||||
this.slideDeck = slideDeck;
|
this.slideDeck = slideDeck;
|
||||||
this.quote = quote;
|
this.quote = quote;
|
||||||
this.revealDuration = revealDuration;
|
this.viewOnce = viewOnce;
|
||||||
this.revealStartTime = revealStartTime;
|
|
||||||
|
|
||||||
this.contacts.addAll(contacts);
|
this.contacts.addAll(contacts);
|
||||||
this.linkPreviews.addAll(linkPreviews);
|
this.linkPreviews.addAll(linkPreviews);
|
||||||
@ -83,11 +81,7 @@ public abstract class MmsMessageRecord extends MessageRecord {
|
|||||||
return linkPreviews;
|
return linkPreviews;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRevealDuration() {
|
public boolean isViewOnce() {
|
||||||
return revealDuration;
|
return viewOnce;
|
||||||
}
|
|
||||||
|
|
||||||
public long getRevealStartTime() {
|
|
||||||
return revealStartTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
|
|||||||
super(id, "", conversationRecipient, individualRecipient, recipientDeviceId,
|
super(id, "", conversationRecipient, individualRecipient, recipientDeviceId,
|
||||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
|
||||||
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId,
|
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), 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.contentLocation = contentLocation;
|
||||||
this.messageSize = messageSize;
|
this.messageSize = messageSize;
|
||||||
|
@ -121,7 +121,7 @@ public class GiphyActivity extends PassphraseRequiredActionBarActivity
|
|||||||
return BlobProvider.getInstance()
|
return BlobProvider.getInstance()
|
||||||
.forData(data)
|
.forData(data)
|
||||||
.withMimeType(MediaUtil.IMAGE_GIF)
|
.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) {
|
} catch (InterruptedException | ExecutionException | IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
return null;
|
return null;
|
||||||
|
@ -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);
|
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);
|
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
||||||
|
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId);
|
||||||
|
@ -212,7 +212,7 @@ public class GroupMessageProcessor {
|
|||||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId(), false));
|
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId(), false));
|
||||||
Recipient recipient = Recipient.from(context, addres, 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 threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
||||||
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
|
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ public class GroupMessageProcessor {
|
|||||||
} else {
|
} else {
|
||||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||||
String body = Base64.encodeBytes(storage.toByteArray());
|
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);
|
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
||||||
|
|
||||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
||||||
|
@ -41,10 +41,10 @@ public final class JobManagerFactories {
|
|||||||
put(MultiDeviceGroupUpdateJob.KEY, new MultiDeviceGroupUpdateJob.Factory());
|
put(MultiDeviceGroupUpdateJob.KEY, new MultiDeviceGroupUpdateJob.Factory());
|
||||||
put(MultiDeviceProfileKeyUpdateJob.KEY, new MultiDeviceProfileKeyUpdateJob.Factory());
|
put(MultiDeviceProfileKeyUpdateJob.KEY, new MultiDeviceProfileKeyUpdateJob.Factory());
|
||||||
put(MultiDeviceReadUpdateJob.KEY, new MultiDeviceReadUpdateJob.Factory());
|
put(MultiDeviceReadUpdateJob.KEY, new MultiDeviceReadUpdateJob.Factory());
|
||||||
put(MultiDeviceRevealUpdateJob.KEY, new MultiDeviceRevealUpdateJob.Factory());
|
|
||||||
put(MultiDeviceStickerPackOperationJob.KEY, new MultiDeviceStickerPackOperationJob.Factory());
|
put(MultiDeviceStickerPackOperationJob.KEY, new MultiDeviceStickerPackOperationJob.Factory());
|
||||||
put(MultiDeviceStickerPackSyncJob.KEY, new MultiDeviceStickerPackSyncJob.Factory());
|
put(MultiDeviceStickerPackSyncJob.KEY, new MultiDeviceStickerPackSyncJob.Factory());
|
||||||
put(MultiDeviceVerifiedUpdateJob.KEY, new MultiDeviceVerifiedUpdateJob.Factory());
|
put(MultiDeviceVerifiedUpdateJob.KEY, new MultiDeviceVerifiedUpdateJob.Factory());
|
||||||
|
put(MultiDeviceViewOnceOpenJob.KEY, new MultiDeviceViewOnceOpenJob.Factory());
|
||||||
put(PushContentReceiveJob.KEY, new PushContentReceiveJob.Factory());
|
put(PushContentReceiveJob.KEY, new PushContentReceiveJob.Factory());
|
||||||
put(PushDecryptJob.KEY, new PushDecryptJob.Factory());
|
put(PushDecryptJob.KEY, new PushDecryptJob.Factory());
|
||||||
put(PushGroupSendJob.KEY, new PushGroupSendJob.Factory());
|
put(PushGroupSendJob.KEY, new PushGroupSendJob.Factory());
|
||||||
|
@ -247,7 +247,7 @@ public class MmsDownloadJob extends BaseJob {
|
|||||||
group = Optional.of(Address.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true)));
|
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> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
|
Optional<InsertResult> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
|
@ -16,25 +16,25 @@ import org.thoughtcrime.securesms.util.JsonUtils;
|
|||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
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.SignalServiceSyncMessage;
|
||||||
|
import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class MultiDeviceRevealUpdateJob extends BaseJob {
|
public class MultiDeviceViewOnceOpenJob extends BaseJob {
|
||||||
|
|
||||||
public static final String KEY = "MultiDeviceRevealUpdateJob";
|
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 static final String KEY_MESSAGE_ID = "message_id";
|
||||||
|
|
||||||
private SerializableSyncMessageId messageId;
|
private SerializableSyncMessageId messageId;
|
||||||
|
|
||||||
public MultiDeviceRevealUpdateJob(SyncMessageId messageId) {
|
public MultiDeviceViewOnceOpenJob(SyncMessageId messageId) {
|
||||||
this(new Parameters.Builder()
|
this(new Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
@ -43,7 +43,7 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
|
|||||||
messageId);
|
messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiDeviceRevealUpdateJob(@NonNull Parameters parameters, @NonNull SyncMessageId syncMessageId) {
|
private MultiDeviceViewOnceOpenJob(@NonNull Parameters parameters, @NonNull SyncMessageId syncMessageId) {
|
||||||
super(parameters);
|
super(parameters);
|
||||||
this.messageId = new SerializableSyncMessageId(syncMessageId.getAddress().toPhoneString(), syncMessageId.getTimetamp());
|
this.messageId = new SerializableSyncMessageId(syncMessageId.getAddress().toPhoneString(), syncMessageId.getTimetamp());
|
||||||
}
|
}
|
||||||
@ -74,9 +74,9 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
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
|
@Override
|
||||||
@ -105,9 +105,9 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Factory implements Job.Factory<MultiDeviceRevealUpdateJob> {
|
public static final class Factory implements Job.Factory<MultiDeviceViewOnceOpenJob> {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull MultiDeviceRevealUpdateJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
public @NonNull MultiDeviceViewOnceOpenJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
SerializableSyncMessageId messageId;
|
SerializableSyncMessageId messageId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -118,7 +118,7 @@ public class MultiDeviceRevealUpdateJob extends BaseJob {
|
|||||||
|
|
||||||
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(messageId.sender), messageId.timestamp);
|
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(messageId.sender), messageId.timestamp);
|
||||||
|
|
||||||
return new MultiDeviceRevealUpdateJob(parameters, syncMessageId);
|
return new MultiDeviceViewOnceOpenJob(parameters, syncMessageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -80,8 +80,6 @@ import org.thoughtcrime.securesms.mms.StickerSlide;
|
|||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
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.service.WebRtcCallService;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
|
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.IceUpdateMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
|
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
|
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.ReadMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
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.messages.shared.SharedContact;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
|
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());
|
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get());
|
||||||
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get());
|
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(syncMessage.getRequest().get());
|
||||||
else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp());
|
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.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get());
|
||||||
else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get());
|
else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get());
|
||||||
else Log.w(TAG, "Contains no known sync types...");
|
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()),
|
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromExternal(context, content.getSender()),
|
||||||
content.getSenderDevice(),
|
content.getSenderDevice(),
|
||||||
content.getTimestamp(),
|
content.getTimestamp(),
|
||||||
"", Optional.absent(), 0, 0,
|
"", Optional.absent(), 0,
|
||||||
content.isNeedsReceipt());
|
content.isNeedsReceipt());
|
||||||
|
|
||||||
Long threadId;
|
Long threadId;
|
||||||
@ -515,7 +513,7 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||||
message.getTimestamp(), -1,
|
message.getTimestamp(), -1,
|
||||||
message.getExpiresInSeconds() * 1000L, true,
|
message.getExpiresInSeconds() * 1000L, true,
|
||||||
0,
|
false,
|
||||||
content.isNeedsReceipt(),
|
content.isNeedsReceipt(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
message.getGroupInfo(),
|
message.getGroupInfo(),
|
||||||
@ -676,11 +674,14 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
MessageNotifier.updateNotification(context);
|
MessageNotifier.updateNotification(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSynchronizeMessageTimerReadMessage(@NonNull MessageTimerReadMessage timerMessage, long envelopeTimestamp) {
|
private void handleSynchronizeViewOnceOpenMessage(@NonNull ViewOnceOpenMessage openMessage, long envelopeTimestamp) {
|
||||||
SyncMessageId messageId = new SyncMessageId(Address.fromExternal(context, timerMessage.getSender()), timerMessage.getTimestamp());
|
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);
|
if (record != null && record.isMms()) {
|
||||||
ApplicationContext.getInstance(context).getRevealableMessageManager().scheduleIfNecessary();
|
DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentFilesForMessage(record.getId());
|
||||||
|
}
|
||||||
|
|
||||||
MessageNotifier.setLastDesktopActivityTimestamp(envelopeTimestamp);
|
MessageNotifier.setLastDesktopActivityTimestamp(envelopeTimestamp);
|
||||||
MessageNotifier.cancelDelayedNotifications();
|
MessageNotifier.cancelDelayedNotifications();
|
||||||
@ -707,7 +708,7 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||||
message.getTimestamp(), -1,
|
message.getTimestamp(), -1,
|
||||||
message.getExpiresInSeconds() * 1000L, false,
|
message.getExpiresInSeconds() * 1000L, false,
|
||||||
message.getMessageTimerInSeconds() * 1000,
|
message.isViewOnce(),
|
||||||
content.isNeedsReceipt(),
|
content.isNeedsReceipt(),
|
||||||
message.getBody(),
|
message.getBody(),
|
||||||
message.getGroupInfo(),
|
message.getGroupInfo(),
|
||||||
@ -747,8 +748,8 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||||
|
|
||||||
if (message.getMessageTimerInSeconds() > 0) {
|
if (message.isViewOnce()) {
|
||||||
ApplicationContext.getInstance(context).getRevealableMessageManager().scheduleIfNecessary();
|
ApplicationContext.getInstance(context).getViewOnceMessageManager().scheduleIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -780,8 +781,8 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
Optional<Attachment> sticker = getStickerAttachment(message.getMessage().getSticker());
|
Optional<Attachment> sticker = getStickerAttachment(message.getMessage().getSticker());
|
||||||
Optional<List<Contact>> sharedContacts = getContacts(message.getMessage().getSharedContacts());
|
Optional<List<Contact>> sharedContacts = getContacts(message.getMessage().getSharedContacts());
|
||||||
Optional<List<LinkPreview>> previews = getLinkPreviews(message.getMessage().getPreviews(), message.getMessage().getBody().or(""));
|
Optional<List<LinkPreview>> previews = getLinkPreviews(message.getMessage().getPreviews(), message.getMessage().getBody().or(""));
|
||||||
long messageTimer = message.getMessage().getMessageTimerInSeconds() * 1000;
|
boolean viewOnce = message.getMessage().isViewOnce();
|
||||||
List<Attachment> syncAttachments = messageTimer == 0 ? PointerAttachment.forPointers(message.getMessage().getAttachments()) : Collections.emptyList();
|
List<Attachment> syncAttachments = viewOnce ? Collections.emptyList() : PointerAttachment.forPointers(message.getMessage().getAttachments());
|
||||||
|
|
||||||
if (sticker.isPresent()) {
|
if (sticker.isPresent()) {
|
||||||
syncAttachments.add(sticker.get());
|
syncAttachments.add(sticker.get());
|
||||||
@ -791,7 +792,7 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
syncAttachments,
|
syncAttachments,
|
||||||
message.getTimestamp(), -1,
|
message.getTimestamp(), -1,
|
||||||
message.getMessage().getExpiresInSeconds() * 1000,
|
message.getMessage().getExpiresInSeconds() * 1000,
|
||||||
messageTimer,
|
viewOnce,
|
||||||
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
||||||
sharedContacts.or(Collections.emptyList()),
|
sharedContacts.or(Collections.emptyList()),
|
||||||
previews.or(Collections.emptyList()),
|
previews.or(Collections.emptyList()),
|
||||||
@ -921,7 +922,6 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
message.getTimestamp(), body,
|
message.getTimestamp(), body,
|
||||||
message.getGroupInfo(),
|
message.getGroupInfo(),
|
||||||
message.getExpiresInSeconds() * 1000L,
|
message.getExpiresInSeconds() * 1000L,
|
||||||
message.getMessageTimerInSeconds() * 1000L,
|
|
||||||
content.isNeedsReceipt());
|
content.isNeedsReceipt());
|
||||||
|
|
||||||
textMessage = new IncomingEncryptedMessage(textMessage, body);
|
textMessage = new IncomingEncryptedMessage(textMessage, body);
|
||||||
@ -956,7 +956,7 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
long messageId;
|
long messageId;
|
||||||
|
|
||||||
if (isGroup) {
|
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);
|
outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage);
|
||||||
|
|
||||||
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, GroupReceiptDatabase.STATUS_UNKNOWN, null);
|
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) {
|
private boolean isInvalidMessage(@NonNull SignalServiceDataMessage message) {
|
||||||
if (message.getMessageTimerInSeconds() > 0) {
|
if (message.isViewOnce()) {
|
||||||
return !message.getAttachments().isPresent() ||
|
return !message.getAttachments().isPresent() ||
|
||||||
message.getAttachments().get().size() != 1 ||
|
message.getAttachments().get().size() != 1 ||
|
||||||
!MediaUtil.isImageType(message.getAttachments().get().get(0).getContentType().toLowerCase());
|
!MediaUtil.isImageType(message.getAttachments().get().get(0).getContentType().toLowerCase());
|
||||||
@ -1229,7 +1229,7 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
if (message.isMms()) {
|
if (message.isMms()) {
|
||||||
MmsMessageRecord mmsMessage = (MmsMessageRecord) message;
|
MmsMessageRecord mmsMessage = (MmsMessageRecord) message;
|
||||||
|
|
||||||
if (mmsMessage.getRevealDuration() == 0) {
|
if (!mmsMessage.isViewOnce()) {
|
||||||
attachments = mmsMessage.getSlideDeck().asAttachments();
|
attachments = mmsMessage.getSlideDeck().asAttachments();
|
||||||
|
|
||||||
if (attachments.isEmpty()) {
|
if (attachments.isEmpty()) {
|
||||||
@ -1335,7 +1335,7 @@ public class PushDecryptJob extends BaseJob {
|
|||||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
|
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
|
||||||
senderDevice, timestamp, "",
|
senderDevice, timestamp, "",
|
||||||
group, 0, 0, false);
|
group, 0, false);
|
||||||
|
|
||||||
textMessage = new IncomingEncryptedMessage(textMessage, "");
|
textMessage = new IncomingEncryptedMessage(textMessage, "");
|
||||||
return database.insertMessageInbox(textMessage);
|
return database.insertMessageInbox(textMessage);
|
||||||
|
@ -195,11 +195,8 @@ public class PushGroupSendJob extends PushSendJob {
|
|||||||
.scheduleDeletion(messageId, true, message.getExpiresIn());
|
.scheduleDeletion(messageId, true, message.getExpiresIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.getRevealDuration() > 0) {
|
if (message.isViewOnce()) {
|
||||||
database.markRevealStarted(messageId);
|
DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentFilesForMessage(messageId);
|
||||||
ApplicationContext.getInstance(context)
|
|
||||||
.getRevealableMessageManager()
|
|
||||||
.scheduleIfNecessary();
|
|
||||||
}
|
}
|
||||||
} else if (!networkFailures.isEmpty()) {
|
} else if (!networkFailures.isEmpty()) {
|
||||||
throw new RetryLaterException();
|
throw new RetryLaterException();
|
||||||
@ -269,7 +266,7 @@ public class PushGroupSendJob extends PushSendJob {
|
|||||||
.withAttachments(attachmentPointers)
|
.withAttachments(attachmentPointers)
|
||||||
.withBody(message.getBody())
|
.withBody(message.getBody())
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
.withMessageTimer((int)(message.getRevealDuration() / 1000))
|
.withViewOnce(message.isViewOnce())
|
||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
.withProfileKey(profileKey.orNull())
|
.withProfileKey(profileKey.orNull())
|
||||||
.withQuote(quote.orNull())
|
.withQuote(quote.orNull())
|
||||||
|
@ -164,11 +164,8 @@ public class PushMediaSendJob extends PushSendJob {
|
|||||||
expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn());
|
expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.getRevealDuration() > 0) {
|
if (message.isViewOnce()) {
|
||||||
database.markRevealStarted(messageId);
|
DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentFilesForMessage(messageId);
|
||||||
ApplicationContext.getInstance(context)
|
|
||||||
.getRevealableMessageManager()
|
|
||||||
.scheduleIfNecessary();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log(TAG, "Sent message: " + messageId);
|
log(TAG, "Sent message: " + messageId);
|
||||||
@ -230,7 +227,7 @@ public class PushMediaSendJob extends PushSendJob {
|
|||||||
.withAttachments(serviceAttachments)
|
.withAttachments(serviceAttachments)
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
.withMessageTimer((int) message.getRevealDuration() / 1000)
|
.withViewOnce(message.isViewOnce())
|
||||||
.withProfileKey(profileKey.orNull())
|
.withProfileKey(profileKey.orNull())
|
||||||
.withQuote(quote.orNull())
|
.withQuote(quote.orNull())
|
||||||
.withSticker(sticker.orNull())
|
.withSticker(sticker.orNull())
|
||||||
|
@ -50,7 +50,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
|||||||
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
import org.thoughtcrime.securesms.imageeditor.model.EditorModel;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
|
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.GifSlide;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.ImageSlide;
|
import org.thoughtcrime.securesms.mms.ImageSlide;
|
||||||
@ -104,7 +104,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
|||||||
public static final String EXTRA_MEDIA = "media";
|
public static final String EXTRA_MEDIA = "media";
|
||||||
public static final String EXTRA_MESSAGE = "message";
|
public static final String EXTRA_MESSAGE = "message";
|
||||||
public static final String EXTRA_TRANSPORT = "transport";
|
public static final String EXTRA_TRANSPORT = "transport";
|
||||||
public static final String EXTRA_REVEAL_DURATION = "reveal_duration";
|
public static final String EXTRA_VIEW_ONCE = "view_once";
|
||||||
|
|
||||||
|
|
||||||
private static final String KEY_ADDRESS = "address";
|
private static final String KEY_ADDRESS = "address";
|
||||||
@ -391,7 +391,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
|||||||
Uri uri = BlobProvider.getInstance()
|
Uri uri = BlobProvider.getInstance()
|
||||||
.forData(data)
|
.forData(data)
|
||||||
.withMimeType(MediaUtil.IMAGE_JPEG)
|
.withMimeType(MediaUtil.IMAGE_JPEG)
|
||||||
.createForSingleSessionOnDisk(this, e -> Log.w(TAG, "Failed to write to disk.", e));
|
.createForSingleSessionOnDisk(this);
|
||||||
return new Media(uri,
|
return new Media(uri,
|
||||||
MediaUtil.IMAGE_JPEG,
|
MediaUtil.IMAGE_JPEG,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
@ -527,14 +527,14 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
|||||||
if (state == null) return;
|
if (state == null) return;
|
||||||
|
|
||||||
hud.setVisibility(state.isHudVisible() ? View.VISIBLE : View.GONE);
|
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);
|
captionText.setVisibility(state.isCaptionVisible() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
int captionBackground;
|
int captionBackground;
|
||||||
|
|
||||||
if (state.getRailState() == MediaSendViewModel.RailState.VIEWABLE) {
|
if (state.getRailState() == MediaSendViewModel.RailState.VIEWABLE) {
|
||||||
captionBackground = R.color.core_grey_90;
|
captionBackground = R.color.core_grey_90;
|
||||||
} else if (state.getRevealState() == RevealState.ENABLED) {
|
} else if (state.getViewOnceState() == ViewOnceState.ENABLED) {
|
||||||
captionBackground = 0;
|
captionBackground = 0;
|
||||||
} else {
|
} else {
|
||||||
captionBackground = R.color.transparent_black_70;
|
captionBackground = R.color.transparent_black_70;
|
||||||
@ -572,7 +572,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state.getRevealState()) {
|
switch (state.getViewOnceState()) {
|
||||||
case ENABLED:
|
case ENABLED:
|
||||||
revealButton.setVisibility(View.VISIBLE);
|
revealButton.setVisibility(View.VISIBLE);
|
||||||
revealButton.setImageResource(R.drawable.ic_view_once_32);
|
revealButton.setImageResource(R.drawable.ic_view_once_32);
|
||||||
@ -815,7 +815,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
|||||||
Uri uri = BlobProvider.getInstance()
|
Uri uri = BlobProvider.getInstance()
|
||||||
.forData(outputStream.toByteArray())
|
.forData(outputStream.toByteArray())
|
||||||
.withMimeType(MediaUtil.IMAGE_JPEG)
|
.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());
|
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 intent = new Intent();
|
||||||
|
|
||||||
intent.putParcelableArrayListExtra(EXTRA_MEDIA, mediaList);
|
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_TRANSPORT, transport);
|
||||||
intent.putExtra(EXTRA_REVEAL_DURATION, viewModel.getRevealDuration());
|
intent.putExtra(EXTRA_VIEW_ONCE, viewModel.isViewOnce());
|
||||||
|
|
||||||
setResult(RESULT_OK, intent);
|
setResult(RESULT_OK, intent);
|
||||||
} else {
|
} else {
|
||||||
@ -885,7 +885,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
|
|||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
-1,
|
-1,
|
||||||
recipient.getExpireMessages() * 1000,
|
recipient.getExpireMessages() * 1000,
|
||||||
viewModel.getRevealDuration(),
|
viewModel.isViewOnce(),
|
||||||
ThreadDatabase.DistributionTypes.DEFAULT,
|
ThreadDatabase.DistributionTypes.DEFAULT,
|
||||||
null,
|
null,
|
||||||
Collections.emptyList(),
|
Collections.emptyList(),
|
||||||
|
@ -66,7 +66,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
private boolean captionVisible;
|
private boolean captionVisible;
|
||||||
private ButtonState buttonState;
|
private ButtonState buttonState;
|
||||||
private RailState railState;
|
private RailState railState;
|
||||||
private RevealState revealState;
|
private ViewOnceState viewOnceState;
|
||||||
|
|
||||||
private @Nullable Recipient recipient;
|
private @Nullable Recipient recipient;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
this.body = "";
|
this.body = "";
|
||||||
this.buttonState = ButtonState.GONE;
|
this.buttonState = ButtonState.GONE;
|
||||||
this.railState = RailState.GONE;
|
this.railState = RailState.GONE;
|
||||||
this.revealState = RevealState.GONE;
|
this.viewOnceState = ViewOnceState.GONE;
|
||||||
this.page = Page.UNKNOWN;
|
this.page = Page.UNKNOWN;
|
||||||
|
|
||||||
position.setValue(-1);
|
position.setValue(-1);
|
||||||
@ -174,7 +174,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
buttonState = ButtonState.COUNT;
|
buttonState = ButtonState.COUNT;
|
||||||
railState = RailState.VIEWABLE;
|
railState = RailState.VIEWABLE;
|
||||||
revealState = RevealState.GONE;
|
viewOnceState = ViewOnceState.GONE;
|
||||||
|
|
||||||
hudState.setValue(buildHudState());
|
hudState.setValue(buildHudState());
|
||||||
}
|
}
|
||||||
@ -182,19 +182,19 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
void onImageEditorStarted() {
|
void onImageEditorStarted() {
|
||||||
page = Page.EDITOR;
|
page = Page.EDITOR;
|
||||||
hudVisible = true;
|
hudVisible = true;
|
||||||
composeVisible = revealState != RevealState.ENABLED;
|
composeVisible = viewOnceState != ViewOnceState.ENABLED;
|
||||||
captionVisible = getSelectedMediaOrDefault().size() > 1 || (getSelectedMediaOrDefault().size() > 0 && getSelectedMediaOrDefault().get(0).getCaption().isPresent());
|
captionVisible = getSelectedMediaOrDefault().size() > 1 || (getSelectedMediaOrDefault().size() > 0 && getSelectedMediaOrDefault().get(0).getCaption().isPresent());
|
||||||
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
||||||
|
|
||||||
if (revealState == RevealState.GONE && revealSupported()) {
|
if (viewOnceState == ViewOnceState.GONE && viewOnceSupported()) {
|
||||||
// TODO[reveal]
|
// TODO[reveal]
|
||||||
// revealState = TextSecurePreferences.isRevealableMessageEnabled(application) ? RevealState.ENABLED : RevealState.DISABLED;
|
// viewOnceState = TextSecurePreferences.isRevealableMessageEnabled(application) ? ViewOnceState.ENABLED : ViewOnceState.DISABLED;
|
||||||
revealState = RevealState.GONE;
|
viewOnceState = ViewOnceState.GONE;
|
||||||
} else if (!revealSupported()) {
|
} else if (!viewOnceSupported()) {
|
||||||
revealState = RevealState.GONE;
|
viewOnceState = ViewOnceState.GONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
railState = !isSms && revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
|
railState = !isSms && viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
|
||||||
|
|
||||||
hudState.setValue(buildHudState());
|
hudState.setValue(buildHudState());
|
||||||
}
|
}
|
||||||
@ -205,7 +205,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
|
|
||||||
page = Page.CAMERA;
|
page = Page.CAMERA;
|
||||||
hudVisible = false;
|
hudVisible = false;
|
||||||
revealState = RevealState.GONE;
|
viewOnceState = ViewOnceState.GONE;
|
||||||
buttonState = ButtonState.COUNT;
|
buttonState = ButtonState.COUNT;
|
||||||
|
|
||||||
List<Media> selected = getSelectedMediaOrDefault();
|
List<Media> selected = getSelectedMediaOrDefault();
|
||||||
@ -225,7 +225,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
composeVisible = false;
|
composeVisible = false;
|
||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
buttonState = ButtonState.COUNT;
|
buttonState = ButtonState.COUNT;
|
||||||
revealState = RevealState.GONE;
|
viewOnceState = ViewOnceState.GONE;
|
||||||
railState = getSelectedMediaOrDefault().isEmpty() ? RailState.GONE : RailState.VIEWABLE;
|
railState = getSelectedMediaOrDefault().isEmpty() ? RailState.GONE : RailState.VIEWABLE;
|
||||||
|
|
||||||
lastCameraCapture = Optional.absent();
|
lastCameraCapture = Optional.absent();
|
||||||
@ -239,7 +239,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
composeVisible = false;
|
composeVisible = false;
|
||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
buttonState = ButtonState.COUNT;
|
buttonState = ButtonState.COUNT;
|
||||||
revealState = RevealState.GONE;
|
viewOnceState = ViewOnceState.GONE;
|
||||||
railState = getSelectedMediaOrDefault().isEmpty() ? RailState.GONE : RailState.VIEWABLE;
|
railState = getSelectedMediaOrDefault().isEmpty() ? RailState.GONE : RailState.VIEWABLE;
|
||||||
|
|
||||||
lastCameraCapture = Optional.absent();
|
lastCameraCapture = Optional.absent();
|
||||||
@ -255,9 +255,9 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
|
|
||||||
void onRevealButtonToggled() {
|
void onRevealButtonToggled() {
|
||||||
hudVisible = true;
|
hudVisible = true;
|
||||||
revealState = revealState == RevealState.ENABLED ? RevealState.DISABLED : RevealState.ENABLED;
|
viewOnceState = viewOnceState == ViewOnceState.ENABLED ? ViewOnceState.DISABLED : ViewOnceState.ENABLED;
|
||||||
composeVisible = revealState != RevealState.ENABLED;
|
composeVisible = viewOnceState != ViewOnceState.ENABLED;
|
||||||
railState = revealState == RevealState.ENABLED || isSms ? RailState.GONE : RailState.INTERACTIVE;
|
railState = viewOnceState == ViewOnceState.ENABLED || isSms ? RailState.GONE : RailState.INTERACTIVE;
|
||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
|
|
||||||
List<Media> uncaptioned = Stream.of(getSelectedMediaOrDefault())
|
List<Media> uncaptioned = Stream.of(getSelectedMediaOrDefault())
|
||||||
@ -266,7 +266,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
|
|
||||||
selectedMedia.setValue(uncaptioned);
|
selectedMedia.setValue(uncaptioned);
|
||||||
|
|
||||||
TextSecurePreferences.setIsRevealableMessageEnabled(application, revealState == RevealState.ENABLED);
|
TextSecurePreferences.setIsRevealableMessageEnabled(application, viewOnceState == ViewOnceState.ENABLED);
|
||||||
|
|
||||||
hudState.setValue(buildHudState());
|
hudState.setValue(buildHudState());
|
||||||
}
|
}
|
||||||
@ -274,14 +274,14 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
void onKeyboardHidden(boolean isSms) {
|
void onKeyboardHidden(boolean isSms) {
|
||||||
if (page != Page.EDITOR) return;
|
if (page != Page.EDITOR) return;
|
||||||
|
|
||||||
composeVisible = (revealState != RevealState.ENABLED);
|
composeVisible = (viewOnceState != ViewOnceState.ENABLED);
|
||||||
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
||||||
|
|
||||||
if (isSms) {
|
if (isSms) {
|
||||||
railState = RailState.GONE;
|
railState = RailState.GONE;
|
||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
} else {
|
} 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())) {
|
if (getSelectedMediaOrDefault().size() > 1 || (getSelectedMediaOrDefault().size() > 0 && getSelectedMediaOrDefault().get(0).getCaption().isPresent())) {
|
||||||
captionVisible = true;
|
captionVisible = true;
|
||||||
@ -296,18 +296,18 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
|
|
||||||
if (isSms) {
|
if (isSms) {
|
||||||
railState = RailState.GONE;
|
railState = RailState.GONE;
|
||||||
composeVisible = (revealState == RevealState.GONE);
|
composeVisible = (viewOnceState == ViewOnceState.GONE);
|
||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
||||||
} else {
|
} else {
|
||||||
if (isCaptionFocused) {
|
if (isCaptionFocused) {
|
||||||
railState = revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
|
railState = viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
|
||||||
composeVisible = false;
|
composeVisible = false;
|
||||||
captionVisible = true;
|
captionVisible = true;
|
||||||
buttonState = ButtonState.GONE;
|
buttonState = ButtonState.GONE;
|
||||||
} else if (isComposeFocused) {
|
} else if (isComposeFocused) {
|
||||||
railState = revealState != RevealState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
|
railState = viewOnceState != ViewOnceState.ENABLED ? RailState.INTERACTIVE : RailState.GONE;
|
||||||
composeVisible = (revealState != RevealState.ENABLED);
|
composeVisible = (viewOnceState != ViewOnceState.ENABLED);
|
||||||
captionVisible = false;
|
captionVisible = false;
|
||||||
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
buttonState = (recipient != null) ? ButtonState.SEND : ButtonState.CONTINUE;
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getSelectedMediaOrDefault().size() == 1) {
|
if (getSelectedMediaOrDefault().size() == 1) {
|
||||||
revealState = revealSupported() ? RevealState.DISABLED : RevealState.GONE;
|
viewOnceState = viewOnceSupported() ? ViewOnceState.DISABLED : ViewOnceState.GONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
hudState.setValue(buildHudState());
|
hudState.setValue(buildHudState());
|
||||||
@ -448,10 +448,9 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
return maxSelection;
|
return maxSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getRevealDuration() {
|
boolean isViewOnce() {
|
||||||
// TODO[reveal]
|
// TODO[reveal]
|
||||||
// return revealState == RevealState.ENABLED ? RevealableUtil.DURATION : 0;
|
return false;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull List<Media> getSelectedMediaOrDefault() {
|
private @NonNull List<Media> getSelectedMediaOrDefault() {
|
||||||
@ -473,13 +472,13 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
|
|
||||||
private HudState buildHudState() {
|
private HudState buildHudState() {
|
||||||
// TODO[reveal]
|
// TODO[reveal]
|
||||||
RevealState updatedRevealState = RevealState.GONE;
|
ViewOnceState updatedViewOnceState = ViewOnceState.GONE;
|
||||||
List<Media> selectedMedia = getSelectedMediaOrDefault();
|
List<Media> selectedMedia = getSelectedMediaOrDefault();
|
||||||
int selectionCount = selectedMedia.size();
|
int selectionCount = selectedMedia.size();
|
||||||
ButtonState updatedButtonState = buttonState == ButtonState.COUNT && selectionCount == 0 ? ButtonState.GONE : buttonState;
|
ButtonState updatedButtonState = buttonState == ButtonState.COUNT && selectionCount == 0 ? ButtonState.GONE : buttonState;
|
||||||
boolean updatedCaptionVisible = captionVisible && (selectedMedia.size() > 1 || (selectedMedia.size() > 0 && selectedMedia.get(0).getCaption().isPresent()));
|
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() {
|
private void clearPersistedMedia() {
|
||||||
@ -489,7 +488,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
.forEach(uri -> BlobProvider.getInstance().delete(application.getApplicationContext(), uri));
|
.forEach(uri -> BlobProvider.getInstance().delete(application.getApplicationContext(), uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean revealSupported() {
|
private boolean viewOnceSupported() {
|
||||||
return !isSms && (recipient == null || !recipient.isLocalNumber()) && mediaSupportsRevealableMessage(getSelectedMediaOrDefault());
|
return !isSms && (recipient == null || !recipient.isLocalNumber()) && mediaSupportsRevealableMessage(getSelectedMediaOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,7 +519,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
INTERACTIVE, VIEWABLE, GONE
|
INTERACTIVE, VIEWABLE, GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RevealState {
|
enum ViewOnceState {
|
||||||
ENABLED, DISABLED, GONE
|
ENABLED, DISABLED, GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,7 +531,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
private final int selectionCount;
|
private final int selectionCount;
|
||||||
private final ButtonState buttonState;
|
private final ButtonState buttonState;
|
||||||
private final RailState railState;
|
private final RailState railState;
|
||||||
private final RevealState revealState;
|
private final ViewOnceState viewOnceState;
|
||||||
|
|
||||||
HudState(boolean hudVisible,
|
HudState(boolean hudVisible,
|
||||||
boolean composeVisible,
|
boolean composeVisible,
|
||||||
@ -540,7 +539,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
int selectionCount,
|
int selectionCount,
|
||||||
@NonNull ButtonState buttonState,
|
@NonNull ButtonState buttonState,
|
||||||
@NonNull RailState railState,
|
@NonNull RailState railState,
|
||||||
@NonNull RevealState revealState)
|
@NonNull ViewOnceState viewOnceState)
|
||||||
{
|
{
|
||||||
this.hudVisible = hudVisible;
|
this.hudVisible = hudVisible;
|
||||||
this.composeVisible = composeVisible;
|
this.composeVisible = composeVisible;
|
||||||
@ -548,7 +547,7 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
this.selectionCount = selectionCount;
|
this.selectionCount = selectionCount;
|
||||||
this.buttonState = buttonState;
|
this.buttonState = buttonState;
|
||||||
this.railState = railState;
|
this.railState = railState;
|
||||||
this.revealState = revealState;
|
this.viewOnceState = viewOnceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHudVisible() {
|
public boolean isHudVisible() {
|
||||||
@ -575,9 +574,8 @@ class MediaSendViewModel extends ViewModel {
|
|||||||
return hudVisible ? railState : RailState.GONE;
|
return hudVisible ? railState : RailState.GONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull
|
public @NonNull ViewOnceState getViewOnceState() {
|
||||||
RevealState getRevealState() {
|
return hudVisible ? viewOnceState : ViewOnceState.GONE;
|
||||||
return hudVisible ? revealState : RevealState.GONE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@ public class IncomingMediaMessage {
|
|||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresIn;
|
private final long expiresIn;
|
||||||
private final boolean expirationUpdate;
|
private final boolean expirationUpdate;
|
||||||
private final long revealDuration;
|
|
||||||
private final QuoteModel quote;
|
private final QuoteModel quote;
|
||||||
private final boolean unidentified;
|
private final boolean unidentified;
|
||||||
|
private final boolean viewOnce;
|
||||||
|
|
||||||
private final List<Attachment> attachments = new LinkedList<>();
|
private final List<Attachment> attachments = new LinkedList<>();
|
||||||
private final List<Contact> sharedContacts = new LinkedList<>();
|
private final List<Contact> sharedContacts = new LinkedList<>();
|
||||||
@ -40,7 +40,7 @@ public class IncomingMediaMessage {
|
|||||||
int subscriptionId,
|
int subscriptionId,
|
||||||
long expiresIn,
|
long expiresIn,
|
||||||
boolean expirationUpdate,
|
boolean expirationUpdate,
|
||||||
long revealDuration,
|
boolean viewOnce,
|
||||||
boolean unidentified)
|
boolean unidentified)
|
||||||
{
|
{
|
||||||
this.from = from;
|
this.from = from;
|
||||||
@ -51,7 +51,7 @@ public class IncomingMediaMessage {
|
|||||||
this.subscriptionId = subscriptionId;
|
this.subscriptionId = subscriptionId;
|
||||||
this.expiresIn = expiresIn;
|
this.expiresIn = expiresIn;
|
||||||
this.expirationUpdate = expirationUpdate;
|
this.expirationUpdate = expirationUpdate;
|
||||||
this.revealDuration = revealDuration;
|
this.viewOnce = viewOnce;
|
||||||
this.quote = null;
|
this.quote = null;
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ public class IncomingMediaMessage {
|
|||||||
int subscriptionId,
|
int subscriptionId,
|
||||||
long expiresIn,
|
long expiresIn,
|
||||||
boolean expirationUpdate,
|
boolean expirationUpdate,
|
||||||
long revealDuration,
|
boolean viewOnce,
|
||||||
boolean unidentified,
|
boolean unidentified,
|
||||||
Optional<String> body,
|
Optional<String> body,
|
||||||
Optional<SignalServiceGroup> group,
|
Optional<SignalServiceGroup> group,
|
||||||
@ -80,7 +80,7 @@ public class IncomingMediaMessage {
|
|||||||
this.subscriptionId = subscriptionId;
|
this.subscriptionId = subscriptionId;
|
||||||
this.expiresIn = expiresIn;
|
this.expiresIn = expiresIn;
|
||||||
this.expirationUpdate = expirationUpdate;
|
this.expirationUpdate = expirationUpdate;
|
||||||
this.revealDuration = revealDuration;
|
this.viewOnce = viewOnce;
|
||||||
this.quote = quote.orNull();
|
this.quote = quote.orNull();
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
|
|
||||||
@ -132,8 +132,8 @@ public class IncomingMediaMessage {
|
|||||||
return expiresIn;
|
return expiresIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRevealDuration() {
|
public boolean isViewOnce() {
|
||||||
return revealDuration;
|
return viewOnce;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGroupMessage() {
|
public boolean isGroupMessage() {
|
||||||
|
@ -11,7 +11,7 @@ public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage
|
|||||||
|
|
||||||
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) {
|
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) {
|
||||||
super(recipient, "", new LinkedList<Attachment>(), sentTimeMillis,
|
super(recipient, "", new LinkedList<Attachment>(), sentTimeMillis,
|
||||||
ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn, 0, null, Collections.emptyList(),
|
ThreadDatabase.DistributionTypes.CONVERSATION, expiresIn, false, null, Collections.emptyList(),
|
||||||
Collections.emptyList());
|
Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,14 +24,14 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
|||||||
@NonNull List<Attachment> avatar,
|
@NonNull List<Attachment> avatar,
|
||||||
long sentTimeMillis,
|
long sentTimeMillis,
|
||||||
long expiresIn,
|
long expiresIn,
|
||||||
long revealDuration,
|
boolean viewOnce,
|
||||||
@Nullable QuoteModel quote,
|
@Nullable QuoteModel quote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> previews)
|
@NonNull List<LinkPreview> previews)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(recipient, encodedGroupContext, avatar, sentTimeMillis,
|
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));
|
this.group = GroupContext.parseFrom(Base64.decode(encodedGroupContext));
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
|||||||
@Nullable final Attachment avatar,
|
@Nullable final Attachment avatar,
|
||||||
long sentTimeMillis,
|
long sentTimeMillis,
|
||||||
long expireIn,
|
long expireIn,
|
||||||
long revealDuration,
|
boolean viewOnce,
|
||||||
@Nullable QuoteModel quote,
|
@Nullable QuoteModel quote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> previews)
|
@NonNull List<LinkPreview> previews)
|
||||||
@ -49,7 +49,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
|||||||
super(recipient, Base64.encodeBytes(group.toByteArray()),
|
super(recipient, Base64.encodeBytes(group.toByteArray()),
|
||||||
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
|
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
ThreadDatabase.DistributionTypes.CONVERSATION, expireIn, revealDuration, quote, contacts, previews);
|
ThreadDatabase.DistributionTypes.CONVERSATION, expireIn, viewOnce, quote, contacts, previews);
|
||||||
|
|
||||||
this.group = group;
|
this.group = group;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public class OutgoingMediaMessage {
|
|||||||
private final int distributionType;
|
private final int distributionType;
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresIn;
|
private final long expiresIn;
|
||||||
private final long revealDuration;
|
private final boolean viewOnce;
|
||||||
private final QuoteModel outgoingQuote;
|
private final QuoteModel outgoingQuote;
|
||||||
|
|
||||||
private final List<NetworkFailure> networkFailures = new LinkedList<>();
|
private final List<NetworkFailure> networkFailures = new LinkedList<>();
|
||||||
@ -33,7 +33,7 @@ public class OutgoingMediaMessage {
|
|||||||
|
|
||||||
public OutgoingMediaMessage(Recipient recipient, String message,
|
public OutgoingMediaMessage(Recipient recipient, String message,
|
||||||
List<Attachment> attachments, long sentTimeMillis,
|
List<Attachment> attachments, long sentTimeMillis,
|
||||||
int subscriptionId, long expiresIn, long revealDuration,
|
int subscriptionId, long expiresIn, boolean viewOnce,
|
||||||
int distributionType,
|
int distributionType,
|
||||||
@Nullable QuoteModel outgoingQuote,
|
@Nullable QuoteModel outgoingQuote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@ -48,7 +48,7 @@ public class OutgoingMediaMessage {
|
|||||||
this.attachments = attachments;
|
this.attachments = attachments;
|
||||||
this.subscriptionId = subscriptionId;
|
this.subscriptionId = subscriptionId;
|
||||||
this.expiresIn = expiresIn;
|
this.expiresIn = expiresIn;
|
||||||
this.revealDuration = revealDuration;
|
this.viewOnce = viewOnce;
|
||||||
this.outgoingQuote = outgoingQuote;
|
this.outgoingQuote = outgoingQuote;
|
||||||
|
|
||||||
this.contacts.addAll(contacts);
|
this.contacts.addAll(contacts);
|
||||||
@ -59,7 +59,7 @@ public class OutgoingMediaMessage {
|
|||||||
|
|
||||||
public OutgoingMediaMessage(Recipient recipient, SlideDeck slideDeck, String message,
|
public OutgoingMediaMessage(Recipient recipient, SlideDeck slideDeck, String message,
|
||||||
long sentTimeMillis, int subscriptionId, long expiresIn,
|
long sentTimeMillis, int subscriptionId, long expiresIn,
|
||||||
long revealDuration, int distributionType,
|
boolean viewOnce, int distributionType,
|
||||||
@Nullable QuoteModel outgoingQuote,
|
@Nullable QuoteModel outgoingQuote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> linkPreviews)
|
@NonNull List<LinkPreview> linkPreviews)
|
||||||
@ -68,7 +68,7 @@ public class OutgoingMediaMessage {
|
|||||||
buildMessage(slideDeck, message),
|
buildMessage(slideDeck, message),
|
||||||
slideDeck.asAttachments(),
|
slideDeck.asAttachments(),
|
||||||
sentTimeMillis, subscriptionId,
|
sentTimeMillis, subscriptionId,
|
||||||
expiresIn, revealDuration, distributionType, outgoingQuote,
|
expiresIn, viewOnce, distributionType, outgoingQuote,
|
||||||
contacts, linkPreviews, new LinkedList<>(), new LinkedList<>());
|
contacts, linkPreviews, new LinkedList<>(), new LinkedList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ public class OutgoingMediaMessage {
|
|||||||
this.sentTimeMillis = that.sentTimeMillis;
|
this.sentTimeMillis = that.sentTimeMillis;
|
||||||
this.subscriptionId = that.subscriptionId;
|
this.subscriptionId = that.subscriptionId;
|
||||||
this.expiresIn = that.expiresIn;
|
this.expiresIn = that.expiresIn;
|
||||||
this.revealDuration = that.revealDuration;
|
this.viewOnce = that.viewOnce;
|
||||||
this.outgoingQuote = that.outgoingQuote;
|
this.outgoingQuote = that.outgoingQuote;
|
||||||
|
|
||||||
this.identityKeyMismatches.addAll(that.identityKeyMismatches);
|
this.identityKeyMismatches.addAll(that.identityKeyMismatches);
|
||||||
@ -129,8 +129,8 @@ public class OutgoingMediaMessage {
|
|||||||
return expiresIn;
|
return expiresIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRevealDuration() {
|
public boolean isViewOnce() {
|
||||||
return revealDuration;
|
return viewOnce;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable QuoteModel getOutgoingQuote() {
|
public @Nullable QuoteModel getOutgoingQuote() {
|
||||||
|
@ -18,12 +18,12 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
|
|||||||
long sentTimeMillis,
|
long sentTimeMillis,
|
||||||
int distributionType,
|
int distributionType,
|
||||||
long expiresIn,
|
long expiresIn,
|
||||||
long revealDuration,
|
boolean viewOnce,
|
||||||
@Nullable QuoteModel quote,
|
@Nullable QuoteModel quote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> previews)
|
@NonNull List<LinkPreview> 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) {
|
public OutgoingSecureMediaMessage(OutgoingMediaMessage base) {
|
||||||
|
@ -76,7 +76,7 @@ public class AndroidAutoReplyReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
if (recipient.isGroupRecipient()) {
|
if (recipient.isGroupRecipient()) {
|
||||||
Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");
|
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);
|
replyThreadId = MessageSender.send(context, reply, threadId, false, null);
|
||||||
} else {
|
} else {
|
||||||
Log.w("AndroidAutoReplyReceiver", "Sending regular message ");
|
Log.w("AndroidAutoReplyReceiver", "Sending regular message ");
|
||||||
|
@ -465,7 +465,7 @@ public class MessageNotifier {
|
|||||||
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
|
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
|
||||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_sticker));
|
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_sticker));
|
||||||
slideDeck = ((MmsMessageRecord) record).getSlideDeck();
|
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));
|
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_disappearing_photo));
|
||||||
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
||||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
|
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
|
||||||
|
@ -76,7 +76,7 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
switch (replyMethod) {
|
switch (replyMethod) {
|
||||||
case GroupMessage: {
|
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);
|
threadId = MessageSender.send(context, reply, -1, false, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import java.io.OutputStream;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows for the creation and retrieval of blobs.
|
* Allows for the creation and retrieval of blobs.
|
||||||
@ -173,7 +175,34 @@ public class BlobProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@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<IOException> 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();
|
AttachmentSecret attachmentSecret = AttachmentSecretProvider.getInstance(context).getOrCreateAttachmentSecret();
|
||||||
String directory = getDirectory(blobSpec.getStorageType());
|
String directory = getDirectory(blobSpec.getStorageType());
|
||||||
File outputFile = new File(getOrCreateCacheDirectory(context, directory), buildFileName(blobSpec.id));
|
File outputFile = new File(getOrCreateCacheDirectory(context, directory), buildFileName(blobSpec.id));
|
||||||
@ -182,6 +211,10 @@ public class BlobProvider {
|
|||||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||||
try {
|
try {
|
||||||
Util.copy(blobSpec.getData(), outputStream);
|
Util.copy(blobSpec.getData(), outputStream);
|
||||||
|
|
||||||
|
if (successListener != null) {
|
||||||
|
successListener.onSuccess();
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (errorListener != null) {
|
if (errorListener != null) {
|
||||||
errorListener.onError(e);
|
errorListener.onError(e);
|
||||||
@ -258,8 +291,23 @@ public class BlobProvider {
|
|||||||
* period from one {@link Application#onCreate()} to the next.
|
* period from one {@link Application#onCreate()} to the next.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public Uri createForSingleSessionOnDisk(@NonNull Context context, @Nullable ErrorListener errorListener) throws IOException {
|
public Uri createForSingleSessionOnDisk(@NonNull Context context) throws IOException {
|
||||||
return writeBlobSpecToDisk(context, buildBlobSpec(StorageType.SINGLE_SESSION_DISK), errorListener);
|
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.
|
* eventually call {@link BlobProvider#delete(Context, Uri)} when the blob is no longer in use.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public Uri createForMultipleSessionsOnDisk(@NonNull Context context, @Nullable ErrorListener errorListener) throws IOException {
|
public Uri createForMultipleSessionsOnDisk(@NonNull Context context) throws IOException {
|
||||||
return writeBlobSpecToDisk(context, buildBlobSpec(StorageType.MULTI_SESSION_DISK), errorListener);
|
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 {
|
public interface ErrorListener {
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
void onError(IOException e);
|
void onError(IOException e);
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -20,14 +20,14 @@ import org.thoughtcrime.securesms.service.TimedEventManager;
|
|||||||
/**
|
/**
|
||||||
* Manages clearing removable message content after they're opened.
|
* Manages clearing removable message content after they're opened.
|
||||||
*/
|
*/
|
||||||
public class RevealableMessageManager extends TimedEventManager<RevealExpirationInfo> {
|
public class ViewOnceMessageManager extends TimedEventManager<ViewOnceExpirationInfo> {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(RevealableMessageManager.class);
|
private static final String TAG = Log.tag(ViewOnceMessageManager.class);
|
||||||
|
|
||||||
private final MmsDatabase mmsDatabase;
|
private final MmsDatabase mmsDatabase;
|
||||||
private final AttachmentDatabase attachmentDatabase;
|
private final AttachmentDatabase attachmentDatabase;
|
||||||
|
|
||||||
public RevealableMessageManager(@NonNull Application application) {
|
public ViewOnceMessageManager(@NonNull Application application) {
|
||||||
super(application, "RevealableMessageManager");
|
super(application, "RevealableMessageManager");
|
||||||
|
|
||||||
this.mmsDatabase = DatabaseFactory.getMmsDatabase(application);
|
this.mmsDatabase = DatabaseFactory.getMmsDatabase(application);
|
||||||
@ -38,8 +38,8 @@ public class RevealableMessageManager extends TimedEventManager<RevealExpiration
|
|||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable RevealExpirationInfo getNextClosestEvent() {
|
protected @Nullable ViewOnceExpirationInfo getNextClosestEvent() {
|
||||||
RevealExpirationInfo expirationInfo = mmsDatabase.getNearestExpiringRevealableMessage();
|
ViewOnceExpirationInfo expirationInfo = mmsDatabase.getNearestExpiringViewOnceMessage();
|
||||||
|
|
||||||
if (expirationInfo != null) {
|
if (expirationInfo != null) {
|
||||||
Log.i(TAG, "Next closest expiration is in " + getDelayForEvent(expirationInfo) + " ms for messsage " + expirationInfo.getMessageId() + ".");
|
Log.i(TAG, "Next closest expiration is in " + getDelayForEvent(expirationInfo) + " ms for messsage " + expirationInfo.getMessageId() + ".");
|
||||||
@ -52,41 +52,34 @@ public class RevealableMessageManager extends TimedEventManager<RevealExpiration
|
|||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@Override
|
@Override
|
||||||
protected void executeEvent(@NonNull RevealExpirationInfo event) {
|
protected void executeEvent(@NonNull ViewOnceExpirationInfo event) {
|
||||||
Log.i(TAG, "Deleting attachments for message " + event.getMessageId());
|
Log.i(TAG, "Deleting attachments for message " + event.getMessageId());
|
||||||
attachmentDatabase.deleteAttachmentFilesForMessage(event.getMessageId());
|
attachmentDatabase.deleteAttachmentFilesForMessage(event.getMessageId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@Override
|
@Override
|
||||||
protected long getDelayForEvent(@NonNull RevealExpirationInfo event) {
|
protected long getDelayForEvent(@NonNull ViewOnceExpirationInfo event) {
|
||||||
if (event.getRevealStartTime() == 0) {
|
long expiresAt = event.getReceiveTime() + ViewOnceUtil.MAX_LIFESPAN;
|
||||||
long expiresAt = event.getReceiveTime() + RevealableUtil.MAX_LIFESPAN;
|
|
||||||
long timeLeft = expiresAt - System.currentTimeMillis();
|
long timeLeft = expiresAt - System.currentTimeMillis();
|
||||||
|
|
||||||
return Math.max(0, timeLeft);
|
return Math.max(0, timeLeft);
|
||||||
} else {
|
|
||||||
long timeSinceStart = System.currentTimeMillis() - event.getRevealStartTime();
|
|
||||||
long timeLeft = event.getRevealDuration() - timeSinceStart;
|
|
||||||
|
|
||||||
return Math.max(0, timeLeft);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AnyThread
|
@AnyThread
|
||||||
@Override
|
@Override
|
||||||
protected void scheduleAlarm(@NonNull Application application, long delay) {
|
protected void scheduleAlarm(@NonNull Application application, long delay) {
|
||||||
setAlarm(application, delay, RevealAlarm.class);
|
setAlarm(application, delay, ViewOnceAlarm.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RevealAlarm extends BroadcastReceiver {
|
public static class ViewOnceAlarm extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(RevealAlarm.class);
|
private static final String TAG = Log.tag(ViewOnceAlarm.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Log.d(TAG, "onReceive()");
|
Log.d(TAG, "onReceive()");
|
||||||
ApplicationContext.getInstance(context).getRevealableMessageManager().scheduleIfNecessary();
|
ApplicationContext.getInstance(context).getViewOnceMessageManager().scheduleIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,6 @@ import android.content.Context;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
@ -12,13 +11,13 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
class RevealableMessageRepository {
|
class ViewOnceMessageRepository {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(RevealableMessageRepository.class);
|
private static final String TAG = Log.tag(ViewOnceMessageRepository.class);
|
||||||
|
|
||||||
private final MmsDatabase mmsDatabase;
|
private final MmsDatabase mmsDatabase;
|
||||||
|
|
||||||
RevealableMessageRepository(@NonNull Context context) {
|
ViewOnceMessageRepository(@NonNull Context context) {
|
||||||
this.mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
this.mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
}
|
}
|
||||||
|
|
@ -3,8 +3,6 @@ package org.thoughtcrime.securesms.revealable;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PorterDuff;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@ -26,9 +24,9 @@ import org.thoughtcrime.securesms.events.PartProgressEvent;
|
|||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
|
||||||
public class RevealableMessageView extends LinearLayout {
|
public class ViewOnceMessageView extends LinearLayout {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(RevealableMessageView.class);
|
private static final String TAG = Log.tag(ViewOnceMessageView.class);
|
||||||
|
|
||||||
private ImageView icon;
|
private ImageView icon;
|
||||||
private ProgressWheel progress;
|
private ProgressWheel progress;
|
||||||
@ -38,12 +36,12 @@ public class RevealableMessageView extends LinearLayout {
|
|||||||
private int openedForegroundColor;
|
private int openedForegroundColor;
|
||||||
private int foregroundColor;
|
private int foregroundColor;
|
||||||
|
|
||||||
public RevealableMessageView(Context context) {
|
public ViewOnceMessageView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
init(null);
|
init(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RevealableMessageView(Context context, @Nullable AttributeSet attrs) {
|
public ViewOnceMessageView(Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
init(attrs);
|
init(attrs);
|
||||||
}
|
}
|
||||||
@ -53,10 +51,10 @@ public class RevealableMessageView extends LinearLayout {
|
|||||||
setOrientation(LinearLayout.HORIZONTAL);
|
setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
if (attrs != null) {
|
if (attrs != null) {
|
||||||
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.RevealableMessageView, 0, 0);
|
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ViewOnceMessageView, 0, 0);
|
||||||
|
|
||||||
unopenedForegroundColor = typedArray.getColor(R.styleable.RevealableMessageView_revealable_unopenedForegroundColor, Color.BLACK);
|
unopenedForegroundColor = typedArray.getColor(R.styleable.ViewOnceMessageView_revealable_unopenedForegroundColor, Color.BLACK);
|
||||||
openedForegroundColor = typedArray.getColor(R.styleable.RevealableMessageView_revealable_openedForegroundColor, Color.BLACK);
|
openedForegroundColor = typedArray.getColor(R.styleable.ViewOnceMessageView_revealable_openedForegroundColor, Color.BLACK);
|
||||||
|
|
||||||
typedArray.recycle();
|
typedArray.recycle();
|
||||||
}
|
}
|
||||||
@ -101,12 +99,17 @@ public class RevealableMessageView extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void presentText(@NonNull MmsMessageRecord messageRecord) {
|
private void presentText(@NonNull MmsMessageRecord messageRecord) {
|
||||||
if (downloadInProgress(messageRecord) && messageRecord.isOutgoing()) {
|
if (messageRecord.isOutgoing()) {
|
||||||
|
foregroundColor = openedForegroundColor;
|
||||||
|
text.setText(R.string.RevealableMessageView_photo);
|
||||||
|
icon.setImageResource(R.drawable.ic_play_outline_24);
|
||||||
|
progress.setVisibility(GONE);
|
||||||
|
} else if (ViewOnceUtil.isViewable(messageRecord)) {
|
||||||
foregroundColor = unopenedForegroundColor;
|
foregroundColor = unopenedForegroundColor;
|
||||||
text.setText(R.string.RevealableMessageView_view_photo);
|
text.setText(R.string.RevealableMessageView_view_photo);
|
||||||
icon.setImageResource(0);
|
icon.setImageResource(R.drawable.ic_play_solid_24);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(GONE);
|
||||||
} else if (downloadInProgress(messageRecord)) {
|
} else if (networkInProgress(messageRecord)) {
|
||||||
foregroundColor = unopenedForegroundColor;
|
foregroundColor = unopenedForegroundColor;
|
||||||
text.setText("");
|
text.setText("");
|
||||||
icon.setImageResource(0);
|
icon.setImageResource(0);
|
||||||
@ -116,16 +119,6 @@ public class RevealableMessageView extends LinearLayout {
|
|||||||
text.setText(formatFileSize(messageRecord));
|
text.setText(formatFileSize(messageRecord));
|
||||||
icon.setImageResource(R.drawable.ic_arrow_down_circle_outline_24);
|
icon.setImageResource(R.drawable.ic_arrow_down_circle_outline_24);
|
||||||
progress.setVisibility(GONE);
|
progress.setVisibility(GONE);
|
||||||
} else if (RevealableUtil.isViewable(messageRecord)) {
|
|
||||||
foregroundColor = unopenedForegroundColor;
|
|
||||||
text.setText(R.string.RevealableMessageView_view_photo);
|
|
||||||
icon.setImageResource(R.drawable.ic_play_solid_24);
|
|
||||||
progress.setVisibility(GONE);
|
|
||||||
} else if (messageRecord.isOutgoing()) {
|
|
||||||
foregroundColor = openedForegroundColor;
|
|
||||||
text.setText(R.string.RevealableMessageView_photo);
|
|
||||||
icon.setImageResource(R.drawable.ic_play_outline_24);
|
|
||||||
progress.setVisibility(GONE);
|
|
||||||
} else {
|
} else {
|
||||||
foregroundColor = openedForegroundColor;
|
foregroundColor = openedForegroundColor;
|
||||||
text.setText(R.string.RevealableMessageView_viewed);
|
text.setText(R.string.RevealableMessageView_viewed);
|
||||||
@ -139,7 +132,7 @@ public class RevealableMessageView extends LinearLayout {
|
|||||||
progress.setRimColor(Color.TRANSPARENT);
|
progress.setRimColor(Color.TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean downloadInProgress(@NonNull MmsMessageRecord messageRecord) {
|
private boolean networkInProgress(@NonNull MmsMessageRecord messageRecord) {
|
||||||
if (messageRecord.getSlideDeck().getThumbnailSlide() == null) return false;
|
if (messageRecord.getSlideDeck().getThumbnailSlide() == null) return false;
|
||||||
|
|
||||||
Attachment attachment = messageRecord.getSlideDeck().getThumbnailSlide().asAttachment();
|
Attachment attachment = messageRecord.getSlideDeck().getThumbnailSlide().asAttachment();
|
@ -17,18 +17,18 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
class RevealableMessageViewModel extends ViewModel {
|
class ViewOnceMessageViewModel extends ViewModel {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(RevealableMessageViewModel.class);
|
private static final String TAG = Log.tag(ViewOnceMessageViewModel.class);
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
private final RevealableMessageRepository repository;
|
private final ViewOnceMessageRepository repository;
|
||||||
private final MutableLiveData<Optional<MmsMessageRecord>> message;
|
private final MutableLiveData<Optional<MmsMessageRecord>> message;
|
||||||
private final ContentObserver observer;
|
private final ContentObserver observer;
|
||||||
|
|
||||||
private RevealableMessageViewModel(@NonNull Application application,
|
private ViewOnceMessageViewModel(@NonNull Application application,
|
||||||
long messageId,
|
long messageId,
|
||||||
@NonNull RevealableMessageRepository repository)
|
@NonNull ViewOnceMessageRepository repository)
|
||||||
{
|
{
|
||||||
this.application = application;
|
this.application = application;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
@ -76,11 +76,11 @@ class RevealableMessageViewModel extends ViewModel {
|
|||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
private final RevealableMessageRepository repository;
|
private final ViewOnceMessageRepository repository;
|
||||||
|
|
||||||
Factory(@NonNull Application application,
|
Factory(@NonNull Application application,
|
||||||
long messageId,
|
long messageId,
|
||||||
@NonNull RevealableMessageRepository repository)
|
@NonNull ViewOnceMessageRepository repository)
|
||||||
{
|
{
|
||||||
this.application = application;
|
this.application = application;
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
@ -90,7 +90,7 @@ class RevealableMessageViewModel extends ViewModel {
|
|||||||
@Override
|
@Override
|
||||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
return modelClass.cast(new RevealableMessageViewModel(application, messageId, repository));
|
return modelClass.cast(new ViewOnceMessageViewModel(application, messageId, repository));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
69
src/org/thoughtcrime/securesms/revealable/ViewOnceUtil.java
Normal file
69
src/org/thoughtcrime/securesms/revealable/ViewOnceUtil.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
|||||||
public class IncomingJoinedMessage extends IncomingTextMessage {
|
public class IncomingJoinedMessage extends IncomingTextMessage {
|
||||||
|
|
||||||
public IncomingJoinedMessage(Address sender) {
|
public IncomingJoinedMessage(Address sender) {
|
||||||
super(sender, 1, System.currentTimeMillis(), null, Optional.<SignalServiceGroup>absent(), 0, 0, false);
|
super(sender, 1, System.currentTimeMillis(), null, Optional.<SignalServiceGroup>absent(), 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,7 +42,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
private final boolean push;
|
private final boolean push;
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresInMillis;
|
private final long expiresInMillis;
|
||||||
private final long revealDuration;
|
|
||||||
private final boolean unidentified;
|
private final boolean unidentified;
|
||||||
|
|
||||||
public IncomingTextMessage(@NonNull Context context, @NonNull SmsMessage message, int subscriptionId) {
|
public IncomingTextMessage(@NonNull Context context, @NonNull SmsMessage message, int subscriptionId) {
|
||||||
@ -56,7 +55,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.sentTimestampMillis = message.getTimestampMillis();
|
this.sentTimestampMillis = message.getTimestampMillis();
|
||||||
this.subscriptionId = subscriptionId;
|
this.subscriptionId = subscriptionId;
|
||||||
this.expiresInMillis = 0;
|
this.expiresInMillis = 0;
|
||||||
this.revealDuration = 0;
|
|
||||||
this.groupId = null;
|
this.groupId = null;
|
||||||
this.push = false;
|
this.push = false;
|
||||||
this.unidentified = false;
|
this.unidentified = false;
|
||||||
@ -64,7 +62,7 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
|
|
||||||
public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis,
|
public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis,
|
||||||
String encodedBody, Optional<SignalServiceGroup> group,
|
String encodedBody, Optional<SignalServiceGroup> group,
|
||||||
long expiresInMillis, long revealDuration, boolean unidentified)
|
long expiresInMillis, boolean unidentified)
|
||||||
{
|
{
|
||||||
this.message = encodedBody;
|
this.message = encodedBody;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
@ -77,7 +75,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.push = true;
|
this.push = true;
|
||||||
this.subscriptionId = -1;
|
this.subscriptionId = -1;
|
||||||
this.expiresInMillis = expiresInMillis;
|
this.expiresInMillis = expiresInMillis;
|
||||||
this.revealDuration = revealDuration;
|
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
|
|
||||||
if (group.isPresent()) {
|
if (group.isPresent()) {
|
||||||
@ -100,7 +97,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.push = (in.readInt() == 1);
|
this.push = (in.readInt() == 1);
|
||||||
this.subscriptionId = in.readInt();
|
this.subscriptionId = in.readInt();
|
||||||
this.expiresInMillis = in.readLong();
|
this.expiresInMillis = in.readLong();
|
||||||
this.revealDuration = in.readLong();
|
|
||||||
this.unidentified = in.readInt() == 1;
|
this.unidentified = in.readInt() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +113,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.push = base.isPush();
|
this.push = base.isPush();
|
||||||
this.subscriptionId = base.getSubscriptionId();
|
this.subscriptionId = base.getSubscriptionId();
|
||||||
this.expiresInMillis = base.getExpiresIn();
|
this.expiresInMillis = base.getExpiresIn();
|
||||||
this.revealDuration = base.getRevealDuration();
|
|
||||||
this.unidentified = base.isUnidentified();
|
this.unidentified = base.isUnidentified();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +135,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.push = fragments.get(0).isPush();
|
this.push = fragments.get(0).isPush();
|
||||||
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
||||||
this.expiresInMillis = fragments.get(0).getExpiresIn();
|
this.expiresInMillis = fragments.get(0).getExpiresIn();
|
||||||
this.revealDuration = fragments.get(0).getRevealDuration();
|
|
||||||
this.unidentified = fragments.get(0).isUnidentified();
|
this.unidentified = fragments.get(0).isUnidentified();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +152,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.push = true;
|
this.push = true;
|
||||||
this.subscriptionId = -1;
|
this.subscriptionId = -1;
|
||||||
this.expiresInMillis = 0;
|
this.expiresInMillis = 0;
|
||||||
this.revealDuration = 0;
|
|
||||||
this.unidentified = false;
|
this.unidentified = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,10 +163,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
return expiresInMillis;
|
return expiresInMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRevealDuration() {
|
|
||||||
return revealDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getSentTimestampMillis() {
|
public long getSentTimestampMillis() {
|
||||||
return sentTimestampMillis;
|
return sentTimestampMillis;
|
||||||
}
|
}
|
||||||
@ -281,7 +270,6 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
out.writeInt(push ? 1 : 0);
|
out.writeInt(push ? 1 : 0);
|
||||||
out.writeInt(subscriptionId);
|
out.writeInt(subscriptionId);
|
||||||
out.writeLong(expiresInMillis);
|
out.writeLong(expiresInMillis);
|
||||||
out.writeLong(revealDuration);
|
|
||||||
out.writeInt(unidentified ? 1 : 0);
|
out.writeInt(unidentified ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ public class GroupUtil {
|
|||||||
.setType(GroupContext.Type.QUIT)
|
.setType(GroupContext.Type.QUIT)
|
||||||
.build();
|
.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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ public class IdentityUtil {
|
|||||||
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
|
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
|
||||||
|
|
||||||
if (remote) {
|
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);
|
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||||
@ -98,7 +98,7 @@ public class IdentityUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (remote) {
|
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);
|
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||||
@ -128,14 +128,14 @@ public class IdentityUtil {
|
|||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive()) {
|
if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive()) {
|
||||||
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
|
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);
|
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
|
|
||||||
smsDatabase.insertMessageInbox(groupUpdate);
|
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);
|
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
|
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ public class TextSecurePreferences {
|
|||||||
|
|
||||||
private static final String MEDIA_KEYBOARD_MODE = "pref_media_keyboard_mode";
|
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";
|
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) {
|
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) {
|
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) {
|
public static void setHasSeenCameraFirstTooltip(Context context, boolean value) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user