diff --git a/README.md b/README.md
index 341fd42841..c509dd9566 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
Add the [F-Droid repo](https://fdroid.getsession.org/)
-[Download the APK from here](https://github.com/loki-project/session-android/releases/latest)
+[Download the APK from here](https://github.com/oxen-io/session-android/releases/latest)
## Summary
diff --git a/app/build.gradle b/app/build.gradle
index 8cc1f4146b..8a42419732 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -43,6 +43,7 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-process:$lifecycleVersion"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.paging:paging-runtime-ktx:$pagingVersion"
implementation 'androidx.activity:activity-ktx:1.5.1'
implementation 'androidx.fragment:fragment-ktx:1.5.3'
@@ -95,7 +96,8 @@ dependencies {
implementation 'com.takisoft.fix:colorpicker:1.0.1'
implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
- implementation 'org.signal:android-database-sqlcipher:3.5.9-S3'
+ implementation 'androidx.sqlite:sqlite-ktx:2.2.0'
+ implementation 'net.zetetic:sqlcipher-android:4.5.3@aar'
implementation ('com.googlecode.ez-vcard:ez-vcard:0.9.11') {
exclude group: 'com.fasterxml.jackson.core'
exclude group: 'org.freemarker'
@@ -158,8 +160,8 @@ dependencies {
testImplementation 'org.robolectric:shadows-multidex:4.4'
}
-def canonicalVersionCode = 321
-def canonicalVersionName = "1.16.3"
+def canonicalVersionCode = 338
+def canonicalVersionName = "1.16.9"
def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1,
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0ba2c62d0a..027dba87a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -410,12 +410,6 @@
-
-
-
-
-
@@ -449,17 +443,9 @@
-
-
diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
index 8fe65767b4..53141534af 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
@@ -47,6 +47,7 @@ import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.WindowDebouncer;
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper;
import org.session.libsession.utilities.dynamiclanguage.LocaleParser;
+import org.session.libsignal.utilities.HTTP;
import org.session.libsignal.utilities.JsonUtil;
import org.session.libsignal.utilities.Log;
import org.session.libsignal.utilities.ThreadUtils;
@@ -54,20 +55,16 @@ import org.signal.aesgcmprovider.AesGcmProvider;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
import org.thoughtcrime.securesms.database.EmojiSearchDatabase;
-import org.thoughtcrime.securesms.database.JobDatabase;
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.database.Storage;
+import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.EmojiSearchData;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
import org.thoughtcrime.securesms.dependencies.DatabaseModule;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.groups.OpenGroupManager;
-import org.thoughtcrime.securesms.groups.OpenGroupMigrator;
import org.thoughtcrime.securesms.home.HomeActivity;
-import org.thoughtcrime.securesms.jobmanager.JobManager;
-import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
-import org.thoughtcrime.securesms.jobs.FastJobStorage;
-import org.thoughtcrime.securesms.jobs.JobManagerFactories;
+import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.logging.AndroidLogger;
import org.thoughtcrime.securesms.logging.PersistentLogger;
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
@@ -80,7 +77,6 @@ import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.KeyCachingService;
-import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.sskenvironment.ProfileManager;
import org.thoughtcrime.securesms.sskenvironment.ReadReceiptManager;
import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository;
@@ -110,7 +106,6 @@ import dagger.hilt.EntryPoints;
import dagger.hilt.android.HiltAndroidApp;
import kotlin.Unit;
import kotlinx.coroutines.Job;
-import network.loki.messenger.BuildConfig;
/**
* Will be called once when the TextSecure process is created.
@@ -130,7 +125,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
private ExpiringMessageManager expiringMessageManager;
private TypingStatusRepository typingStatusRepository;
private TypingStatusSender typingStatusSender;
- private JobManager jobManager;
private ReadReceiptManager readReceiptManager;
private ProfileManager profileManager;
public MessageNotifier messageNotifier = null;
@@ -145,7 +139,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
@Inject LokiAPIDatabase lokiAPIDatabase;
@Inject Storage storage;
@Inject MessageDataProvider messageDataProvider;
- @Inject JobDatabase jobDatabase;
@Inject TextSecurePreferences textSecurePreferences;
CallMessageProcessor callMessageProcessor;
MessagingModuleConfiguration messagingModuleConfiguration;
@@ -164,10 +157,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
return (ApplicationContext) context.getApplicationContext();
}
- public TextSecurePreferences getPrefs() {
- return textSecurePreferences;
- }
-
public DatabaseComponent getDatabaseComponent() {
return EntryPoints.get(getApplicationContext(), DatabaseComponent.class);
}
@@ -203,9 +192,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
storage,
messageDataProvider,
()-> KeyPairUtilities.INSTANCE.getUserED25519KeyPair(this));
- // migrate session open group data
- OpenGroupMigrator.migrate(getDatabaseComponent());
- // end migration
callMessageProcessor = new CallMessageProcessor(this, textSecurePreferences, ProcessLifecycleOwner.get().getLifecycle(), storage);
Log.i(TAG, "onCreate()");
startKovenant();
@@ -230,12 +216,14 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
initializeProfileManager();
initializePeriodicTasks();
SSKEnvironment.Companion.configure(getTypingStatusRepository(), getReadReceiptManager(), getProfileManager(), messageNotifier, getExpiringMessageManager());
- initializeJobManager();
initializeWebRtc();
initializeBlobProvider();
resubmitProfilePictureIfNeeded();
loadEmojiSearchIndexIfNeeded();
EmojiSource.refresh();
+
+ NetworkConstraint networkConstraint = new NetworkConstraint.Factory(this).create();
+ HTTP.INSTANCE.setConnectedToNetwork(networkConstraint::isMet);
}
@Override
@@ -244,6 +232,12 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
Log.i(TAG, "App is now visible.");
KeyCachingService.onAppForegrounded(this);
+ // If the user account hasn't been created or onboarding wasn't finished then don't start
+ // the pollers
+ if (TextSecurePreferences.getLocalNumber(this) == null || !TextSecurePreferences.hasSeenWelcomeScreen(this)) {
+ return;
+ }
+
ThreadUtils.queue(()->{
if (poller != null) {
poller.setCaughtUp(false);
@@ -264,7 +258,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
if (poller != null) {
poller.stopIfNeeded();
}
- ClosedGroupPollerV2.getShared().stop();
+ ClosedGroupPollerV2.getShared().stopAll();
}
@Override
@@ -278,10 +272,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
LocaleParser.Companion.configure(new LocaleParseHelper());
}
- public JobManager getJobManager() {
- return jobManager;
- }
-
public ExpiringMessageManager getExpiringMessageManager() {
return expiringMessageManager;
}
@@ -344,16 +334,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger(originalHandler));
}
- private void initializeJobManager() {
- this.jobManager = new JobManager(this, new JobManager.Configuration.Builder()
- .setDataSerializer(new JsonDataSerializer())
- .setJobFactories(JobManagerFactories.getJobFactories(this))
- .setConstraintFactories(JobManagerFactories.getConstraintFactories(this))
- .setConstraintObservers(JobManagerFactories.getConstraintObservers(this))
- .setJobStorage(new FastJobStorage(jobDatabase))
- .build());
- }
-
private void initializeExpiringMessageManager() {
this.expiringMessageManager = new ExpiringMessageManager(this);
}
@@ -376,10 +356,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
private void initializePeriodicTasks() {
BackgroundPollWorker.schedulePeriodic(this);
-
- if (BuildConfig.PLAY_STORE_DISABLED) {
- UpdateApkRefreshListener.schedule(this);
- }
}
private void initializeWebRtc() {
@@ -444,11 +420,15 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
String token = task.getResult().getToken();
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null) return Unit.INSTANCE;
- if (TextSecurePreferences.isUsingFCM(this)) {
- LokiPushNotificationManager.register(token, userPublicKey, this, force);
- } else {
- LokiPushNotificationManager.unregister(token, this);
- }
+
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
+ if (TextSecurePreferences.isUsingFCM(this)) {
+ LokiPushNotificationManager.register(token, userPublicKey, this, force);
+ } else {
+ LokiPushNotificationManager.unregister(token, this);
+ }
+ });
+
return Unit.INSTANCE;
});
}
@@ -537,7 +517,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
TextSecurePreferences.setProfileName(this, displayName);
}
getSharedPreferences(PREFERENCES_NAME, 0).edit().clear().commit();
- if (!deleteDatabase("signal.db")) {
+ if (!deleteDatabase(SQLCipherOpenHelper.DATABASE_NAME)) {
Log.d("Loki", "Failed to delete database.");
}
Util.runOnMain(() -> new Handler().postDelayed(ApplicationContext.this::restartApplication, 200));
diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java
index 7d82c760cc..51f66ec323 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/BaseActionBarActivity.java
@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms;
+import static android.os.Build.VERSION.SDK_INT;
import static org.session.libsession.utilities.TextSecurePreferences.SELECTED_ACCENT_COLOR;
import android.app.ActivityManager;
@@ -18,6 +19,7 @@ import androidx.appcompat.app.AppCompatActivity;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageActivityHelper;
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper;
+import org.thoughtcrime.securesms.conversation.v2.WindowUtil;
import org.thoughtcrime.securesms.util.ActivityUtilitiesKt;
import org.thoughtcrime.securesms.util.ThemeState;
import org.thoughtcrime.securesms.util.UiModeUtilities;
@@ -92,6 +94,11 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
if (!currentThemeState.equals(ActivityUtilitiesKt.themeState(getPreferences()))) {
recreate();
}
+
+ // apply lightStatusBar manually as API 26 does not update properly via applyTheme
+ // https://issuetracker.google.com/issues/65883460?pli=1
+ if (SDK_INT >= 26 && SDK_INT <= 27) WindowUtil.setLightStatusBarFromTheme(this);
+ if (SDK_INT == 27) WindowUtil.setLightNavigationBarFromTheme(this);
}
@Override
diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java
index aad4c17008..0fd813cf4b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/MediaGalleryAdapter.java
@@ -114,7 +114,7 @@ class MediaGalleryAdapter extends StickyHeaderGridAdapter {
Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment());
if (slide != null) {
- thumbnailView.setImageResource(glideRequests, slide, false, false);
+ thumbnailView.setImageResource(glideRequests, slide, false, null);
}
thumbnailView.setOnClickListener(view -> itemClickListener.onMediaClicked(mediaRecord));
diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java
index 53a909c5ac..b36fdb3ca1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/MediaOverviewActivity.java
@@ -54,6 +54,7 @@ import com.google.android.material.tabs.TabLayout;
import org.session.libsession.messaging.messages.control.DataExtractionNotification;
import org.session.libsession.messaging.sending_receiving.MessageSender;
+import org.session.libsession.snode.SnodeAPI;
import org.session.libsession.utilities.Address;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.MediaDatabase;
@@ -366,7 +367,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
private void sendMediaSavedNotificationIfNeeded() {
if (recipient.isGroupRecipient()) return;
- DataExtractionNotification message = new DataExtractionNotification(new DataExtractionNotification.Kind.MediaSaved(System.currentTimeMillis()));
+ DataExtractionNotification message = new DataExtractionNotification(new DataExtractionNotification.Kind.MediaSaved(SnodeAPI.getNowWithOffset()));
MessageSender.send(message, recipient.getAddress());
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
index b21c7dac8c..6544c2ab89 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
@@ -60,6 +60,7 @@ import androidx.viewpager.widget.ViewPager;
import org.session.libsession.messaging.messages.control.DataExtractionNotification;
import org.session.libsession.messaging.sending_receiving.MessageSender;
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment;
+import org.session.libsession.snode.SnodeAPI;
import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.recipients.Recipient;
@@ -423,7 +424,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
.onAnyDenied(() -> Toast.makeText(this, R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, Toast.LENGTH_LONG).show())
.onAllGranted(() -> {
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
- long saveDate = (mediaItem.date > 0) ? mediaItem.date : System.currentTimeMillis();
+ long saveDate = (mediaItem.date > 0) ? mediaItem.date : SnodeAPI.getNowWithOffset();
saveTask.executeOnExecutor(
AsyncTask.THREAD_POOL_EXECUTOR,
new Attachment(mediaItem.uri, mediaItem.type, saveDate, null));
@@ -437,7 +438,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
private void sendMediaSavedNotificationIfNeeded() {
if (conversationRecipient.isGroupRecipient()) return;
- DataExtractionNotification message = new DataExtractionNotification(new DataExtractionNotification.Kind.MediaSaved(System.currentTimeMillis()));
+ DataExtractionNotification message = new DataExtractionNotification(new DataExtractionNotification.Kind.MediaSaved(SnodeAPI.getNowWithOffset()));
MessageSender.send(message, conversationRecipient.getAddress());
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java b/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java
index 63b42c4936..afc993df8a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java
@@ -210,8 +210,7 @@ public class PassphrasePromptActivity extends BaseActionBarActivity {
try {
signature = biometricSecretProvider.getOrCreateBiometricSignature(this);
hasSignatureObject = true;
- throw new InvalidKeyException("e");
- } catch (InvalidKeyException e) {
+ } catch (Exception e) {
signature = null;
hasSignatureObject = false;
Log.e(TAG, "Error getting / creating signature", e);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
index fa0fce7bd3..b00ed7d2ee 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
@@ -74,10 +74,10 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
attachmentDatabase.setTransferState(messageID, attachmentId, attachmentState.value)
}
- override fun getMessageForQuote(timestamp: Long, author: Address): Pair? {
+ override fun getMessageForQuote(timestamp: Long, author: Address): Triple? {
val messagingDatabase = DatabaseComponent.get(context).mmsSmsDatabase()
val message = messagingDatabase.getMessageFor(timestamp, author)
- return if (message != null) Pair(message.id, message.isMms) else null
+ return if (message != null) Triple(message.id, message.isMms, message.body) else null
}
override fun getAttachmentsAndLinkPreviewFor(mmsId: Long): List {
@@ -176,6 +176,11 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return messageDB.getMessageID(serverId, threadId)
}
+ override fun getMessageIDs(serverIds: List, threadId: Long): Pair, List> {
+ val messageDB = DatabaseComponent.get(context).lokiMessageDatabase()
+ return messageDB.getMessageIDs(serverIds, threadId)
+ }
+
override fun deleteMessage(messageID: Long, isSms: Boolean) {
val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
else DatabaseComponent.get(context).mmsDatabase()
@@ -184,16 +189,27 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHash(messageID)
}
- override fun updateMessageAsDeleted(timestamp: Long, author: String) {
+ override fun deleteMessages(messageIDs: List, threadId: Long, isSms: Boolean) {
+ val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
+ else DatabaseComponent.get(context).mmsDatabase()
+
+ messagingDatabase.deleteMessages(messageIDs.toLongArray(), threadId)
+ DatabaseComponent.get(context).lokiMessageDatabase().deleteMessages(messageIDs)
+ DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHashes(messageIDs)
+ }
+
+ override fun updateMessageAsDeleted(timestamp: Long, author: String): Long? {
val database = DatabaseComponent.get(context).mmsSmsDatabase()
val address = Address.fromSerialized(author)
- val message = database.getMessageFor(timestamp, address) ?: return
+ val message = database.getMessageFor(timestamp, address) ?: return null
val messagingDatabase: MessagingDatabase = if (message.isMms) DatabaseComponent.get(context).mmsDatabase()
else DatabaseComponent.get(context).smsDatabase()
- messagingDatabase.markAsDeleted(message.id, message.isRead)
+ messagingDatabase.markAsDeleted(message.id, message.isRead, message.hasMention)
if (message.isOutgoing) {
messagingDatabase.deleteMessage(message.id)
}
+
+ return message.id
}
override fun getServerHashForMessage(messageID: Long): String? {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt
index 94c7517eb0..9c7ca21e8b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/ScreenshotObserver.kt
@@ -7,12 +7,21 @@ import android.os.Build
import android.os.Handler
import android.provider.MediaStore
import androidx.annotation.RequiresApi
+import org.session.libsignal.utilities.Log
+import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer
+
+private const val TAG = "ScreenshotObserver"
class ScreenshotObserver(private val context: Context, handler: Handler, private val screenshotTriggered: ()->Unit): ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri)
uri ?: return
+
+ // There is an odd bug where we can get notified for changes to 'content://media/external'
+ // directly which is a protected folder, this code is to prevent that crash
+ if (uri.scheme == "content" && uri.host == "media" && uri.path == "/external") { return }
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
queryRelativeDataColumn(uri)
} else {
@@ -26,22 +35,26 @@ class ScreenshotObserver(private val context: Context, handler: Handler, private
val projection = arrayOf(
MediaStore.Images.Media.DATA
)
- context.contentResolver.query(
- uri,
- projection,
- null,
- null,
- null
- )?.use { cursor ->
- val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
- while (cursor.moveToNext()) {
- val path = cursor.getString(dataColumn)
- if (path.contains("screenshot", true)) {
- if (cache.add(uri.hashCode())) {
- screenshotTriggered()
+ try {
+ context.contentResolver.query(
+ uri,
+ projection,
+ null,
+ null,
+ null
+ )?.use { cursor ->
+ val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
+ while (cursor.moveToNext()) {
+ val path = cursor.getString(dataColumn)
+ if (path.contains("screenshot", true)) {
+ if (cache.add(uri.hashCode())) {
+ screenshotTriggered()
+ }
}
}
}
+ } catch (e: SecurityException) {
+ Log.e(TAG, e)
}
}
@@ -51,28 +64,32 @@ class ScreenshotObserver(private val context: Context, handler: Handler, private
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.RELATIVE_PATH
)
- context.contentResolver.query(
- uri,
- projection,
- null,
- null,
- null
- )?.use { cursor ->
- val relativePathColumn =
- cursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH)
- val displayNameColumn =
- cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
- while (cursor.moveToNext()) {
- val name = cursor.getString(displayNameColumn)
- val relativePath = cursor.getString(relativePathColumn)
- if (name.contains("screenshot", true) or
- relativePath.contains("screenshot", true)) {
- if (cache.add(uri.hashCode())) {
- screenshotTriggered()
+
+ try {
+ context.contentResolver.query(
+ uri,
+ projection,
+ null,
+ null,
+ null
+ )?.use { cursor ->
+ val relativePathColumn =
+ cursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH)
+ val displayNameColumn =
+ cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
+ while (cursor.moveToNext()) {
+ val name = cursor.getString(displayNameColumn)
+ val relativePath = cursor.getString(relativePathColumn)
+ if (name.contains("screenshot", true) or
+ relativePath.contains("screenshot", true)) {
+ if (cache.add(uri.hashCode())) {
+ screenshotTriggered()
+ }
}
}
}
+ } catch (e: IllegalStateException) {
+ Log.e(TAG, e)
}
}
-
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt
deleted file mode 100644
index 614dc30bba..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupEvent.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.thoughtcrime.securesms.backup
-
-data class BackupEvent constructor(val type: Type, val count: Int, val exception: Exception?) {
-
- enum class Type {
- PROGRESS, FINISHED
- }
-
- companion object {
- @JvmStatic fun createProgress(count: Int) = BackupEvent(Type.PROGRESS, count, null)
- @JvmStatic fun createFinished() = BackupEvent(Type.FINISHED, 0, null)
- @JvmStatic fun createFinished(e: Exception?) = BackupEvent(Type.FINISHED, 0, e)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java
deleted file mode 100644
index eec2a2e588..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPassphrase.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.thoughtcrime.securesms.backup;
-
-import android.content.Context;
-import android.os.Build;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.thoughtcrime.securesms.crypto.KeyStoreHelper;
-import org.session.libsignal.utilities.Log;
-import org.session.libsession.utilities.TextSecurePreferences;
-
-/**
- * Allows the getting and setting of the backup passphrase, which is stored encrypted on API >= 23.
- */
-public class BackupPassphrase {
-
- private static final String TAG = BackupPassphrase.class.getSimpleName();
-
- public static @Nullable String get(@NonNull Context context) {
- String passphrase = TextSecurePreferences.getBackupPassphrase(context);
- String encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context);
-
- if (Build.VERSION.SDK_INT < 23 || (passphrase == null && encryptedPassphrase == null)) {
- return passphrase;
- }
-
- if (encryptedPassphrase == null) {
- Log.i(TAG, "Migrating to encrypted passphrase.");
- set(context, passphrase);
- encryptedPassphrase = TextSecurePreferences.getEncryptedBackupPassphrase(context);
- }
-
- KeyStoreHelper.SealedData data = KeyStoreHelper.SealedData.fromString(encryptedPassphrase);
- return new String(KeyStoreHelper.unseal(data));
- }
-
- public static void set(@NonNull Context context, @Nullable String passphrase) {
- if (passphrase == null || Build.VERSION.SDK_INT < 23) {
- TextSecurePreferences.setBackupPassphrase(context, passphrase);
- TextSecurePreferences.setEncryptedBackupPassphrase(context, null);
- } else {
- KeyStoreHelper.SealedData encryptedPassphrase = KeyStoreHelper.seal(passphrase.getBytes());
- TextSecurePreferences.setEncryptedBackupPassphrase(context, encryptedPassphrase.serialize());
- TextSecurePreferences.setBackupPassphrase(context, null);
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt
deleted file mode 100644
index 8ddfc23a8b..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupPreferences.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.thoughtcrime.securesms.backup
-
-import android.content.Context
-import android.content.SharedPreferences
-import android.os.Build
-import android.preference.PreferenceManager
-import android.preference.PreferenceManager.getDefaultSharedPreferencesName
-import org.session.libsession.utilities.TextSecurePreferences
-import org.session.libsignal.utilities.Log
-import org.thoughtcrime.securesms.backup.FullBackupImporter.PREF_PREFIX_TYPE_BOOLEAN
-import org.thoughtcrime.securesms.backup.FullBackupImporter.PREF_PREFIX_TYPE_INT
-import java.util.*
-
-object BackupPreferences {
- // region Backup related
- fun getBackupRecords(context: Context): List {
- val preferences = PreferenceManager.getDefaultSharedPreferences(context)
- val prefsFileName: String
- prefsFileName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- getDefaultSharedPreferencesName(context)
- } else {
- context.packageName + "_preferences"
- }
- val prefList: LinkedList = LinkedList()
- addBackupEntryInt(prefList, preferences, prefsFileName, TextSecurePreferences.LOCAL_REGISTRATION_ID_PREF)
- addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.LOCAL_NUMBER_PREF)
- addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_NAME_PREF)
- addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_AVATAR_URL_PREF)
- addBackupEntryInt(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_AVATAR_ID_PREF)
- addBackupEntryString(prefList, preferences, prefsFileName, TextSecurePreferences.PROFILE_KEY_PREF)
- addBackupEntryBoolean(prefList, preferences, prefsFileName, TextSecurePreferences.IS_USING_FCM)
- return prefList
- }
-
- private fun addBackupEntryString(
- outPrefList: MutableList,
- prefs: SharedPreferences,
- prefFileName: String,
- prefKey: String,
- ) {
- val value = prefs.getString(prefKey, null)
- if (value == null) {
- logBackupEntry(prefKey, false)
- return
- }
- outPrefList.add(BackupProtos.SharedPreference.newBuilder()
- .setFile(prefFileName)
- .setKey(prefKey)
- .setValue(value)
- .build())
- logBackupEntry(prefKey, true)
- }
-
- private fun addBackupEntryInt(
- outPrefList: MutableList,
- prefs: SharedPreferences,
- prefFileName: String,
- prefKey: String,
- ) {
- val value = prefs.getInt(prefKey, -1)
- if (value == -1) {
- logBackupEntry(prefKey, false)
- return
- }
- outPrefList.add(BackupProtos.SharedPreference.newBuilder()
- .setFile(prefFileName)
- .setKey(PREF_PREFIX_TYPE_INT + prefKey) // The prefix denotes the type of the preference.
- .setValue(value.toString())
- .build())
- logBackupEntry(prefKey, true)
- }
-
- private fun addBackupEntryBoolean(
- outPrefList: MutableList,
- prefs: SharedPreferences,
- prefFileName: String,
- prefKey: String,
- ) {
- if (!prefs.contains(prefKey)) {
- logBackupEntry(prefKey, false)
- return
- }
- outPrefList.add(BackupProtos.SharedPreference.newBuilder()
- .setFile(prefFileName)
- .setKey(PREF_PREFIX_TYPE_BOOLEAN + prefKey) // The prefix denotes the type of the preference.
- .setValue(prefs.getBoolean(prefKey, false).toString())
- .build())
- logBackupEntry(prefKey, true)
- }
-
- private fun logBackupEntry(prefName: String, wasIncluded: Boolean) {
- val sb = StringBuilder()
- sb.append("Backup preference ")
- sb.append(if (wasIncluded) "+ " else "- ")
- sb.append('\"').append(prefName).append("\" ")
- if (!wasIncluded) {
- sb.append("(is empty and not included)")
- }
- Log.d("Loki", sb.toString())
- } // endregion
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java b/app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java
deleted file mode 100644
index f3b78606f4..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/BackupProtos.java
+++ /dev/null
@@ -1,6778 +0,0 @@
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: Backups.proto
-
-package org.thoughtcrime.securesms.backup;
-
-public final class BackupProtos {
- private BackupProtos() {}
- public static void registerAllExtensions(
- com.google.protobuf.ExtensionRegistry registry) {
- }
- public interface SqlStatementOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional string statement = 1;
- /**
- * optional string statement = 1;
- */
- boolean hasStatement();
- /**
- * optional string statement = 1;
- */
- java.lang.String getStatement();
- /**
- * optional string statement = 1;
- */
- com.google.protobuf.ByteString
- getStatementBytes();
-
- // repeated .signal.SqlStatement.SqlParameter parameters = 2;
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- java.util.List
- getParametersList();
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getParameters(int index);
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- int getParametersCount();
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- java.util.List extends org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder>
- getParametersOrBuilderList();
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder getParametersOrBuilder(
- int index);
- }
- /**
- * Protobuf type {@code signal.SqlStatement}
- */
- public static final class SqlStatement extends
- com.google.protobuf.GeneratedMessage
- implements SqlStatementOrBuilder {
- // Use SqlStatement.newBuilder() to construct.
- private SqlStatement(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private SqlStatement(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final SqlStatement defaultInstance;
- public static SqlStatement getDefaultInstance() {
- return defaultInstance;
- }
-
- public SqlStatement getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private SqlStatement(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- bitField0_ |= 0x00000001;
- statement_ = input.readBytes();
- break;
- }
- case 18: {
- if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
- parameters_ = new java.util.ArrayList();
- mutable_bitField0_ |= 0x00000002;
- }
- parameters_.add(input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.PARSER, extensionRegistry));
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
- parameters_ = java.util.Collections.unmodifiableList(parameters_);
- }
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public SqlStatement parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new SqlStatement(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- public interface SqlParameterOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional string stringParamter = 1;
- /**
- * optional string stringParamter = 1;
- */
- boolean hasStringParamter();
- /**
- * optional string stringParamter = 1;
- */
- java.lang.String getStringParamter();
- /**
- * optional string stringParamter = 1;
- */
- com.google.protobuf.ByteString
- getStringParamterBytes();
-
- // optional uint64 integerParameter = 2;
- /**
- * optional uint64 integerParameter = 2;
- */
- boolean hasIntegerParameter();
- /**
- * optional uint64 integerParameter = 2;
- */
- long getIntegerParameter();
-
- // optional double doubleParameter = 3;
- /**
- * optional double doubleParameter = 3;
- */
- boolean hasDoubleParameter();
- /**
- * optional double doubleParameter = 3;
- */
- double getDoubleParameter();
-
- // optional bytes blobParameter = 4;
- /**
- * optional bytes blobParameter = 4;
- */
- boolean hasBlobParameter();
- /**
- * optional bytes blobParameter = 4;
- */
- com.google.protobuf.ByteString getBlobParameter();
-
- // optional bool nullparameter = 5;
- /**
- * optional bool nullparameter = 5;
- */
- boolean hasNullparameter();
- /**
- * optional bool nullparameter = 5;
- */
- boolean getNullparameter();
- }
- /**
- * Protobuf type {@code signal.SqlStatement.SqlParameter}
- */
- public static final class SqlParameter extends
- com.google.protobuf.GeneratedMessage
- implements SqlParameterOrBuilder {
- // Use SqlParameter.newBuilder() to construct.
- private SqlParameter(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private SqlParameter(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final SqlParameter defaultInstance;
- public static SqlParameter getDefaultInstance() {
- return defaultInstance;
- }
-
- public SqlParameter getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private SqlParameter(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- bitField0_ |= 0x00000001;
- stringParamter_ = input.readBytes();
- break;
- }
- case 16: {
- bitField0_ |= 0x00000002;
- integerParameter_ = input.readUInt64();
- break;
- }
- case 25: {
- bitField0_ |= 0x00000004;
- doubleParameter_ = input.readDouble();
- break;
- }
- case 34: {
- bitField0_ |= 0x00000008;
- blobParameter_ = input.readBytes();
- break;
- }
- case 40: {
- bitField0_ |= 0x00000010;
- nullparameter_ = input.readBool();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public SqlParameter parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new SqlParameter(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional string stringParamter = 1;
- public static final int STRINGPARAMTER_FIELD_NUMBER = 1;
- private java.lang.Object stringParamter_;
- /**
- * optional string stringParamter = 1;
- */
- public boolean hasStringParamter() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string stringParamter = 1;
- */
- public java.lang.String getStringParamter() {
- java.lang.Object ref = stringParamter_;
- if (ref instanceof java.lang.String) {
- return (java.lang.String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- java.lang.String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- stringParamter_ = s;
- }
- return s;
- }
- }
- /**
- * optional string stringParamter = 1;
- */
- public com.google.protobuf.ByteString
- getStringParamterBytes() {
- java.lang.Object ref = stringParamter_;
- if (ref instanceof java.lang.String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- stringParamter_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- // optional uint64 integerParameter = 2;
- public static final int INTEGERPARAMETER_FIELD_NUMBER = 2;
- private long integerParameter_;
- /**
- * optional uint64 integerParameter = 2;
- */
- public boolean hasIntegerParameter() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint64 integerParameter = 2;
- */
- public long getIntegerParameter() {
- return integerParameter_;
- }
-
- // optional double doubleParameter = 3;
- public static final int DOUBLEPARAMETER_FIELD_NUMBER = 3;
- private double doubleParameter_;
- /**
- * optional double doubleParameter = 3;
- */
- public boolean hasDoubleParameter() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional double doubleParameter = 3;
- */
- public double getDoubleParameter() {
- return doubleParameter_;
- }
-
- // optional bytes blobParameter = 4;
- public static final int BLOBPARAMETER_FIELD_NUMBER = 4;
- private com.google.protobuf.ByteString blobParameter_;
- /**
- * optional bytes blobParameter = 4;
- */
- public boolean hasBlobParameter() {
- return ((bitField0_ & 0x00000008) == 0x00000008);
- }
- /**
- * optional bytes blobParameter = 4;
- */
- public com.google.protobuf.ByteString getBlobParameter() {
- return blobParameter_;
- }
-
- // optional bool nullparameter = 5;
- public static final int NULLPARAMETER_FIELD_NUMBER = 5;
- private boolean nullparameter_;
- /**
- * optional bool nullparameter = 5;
- */
- public boolean hasNullparameter() {
- return ((bitField0_ & 0x00000010) == 0x00000010);
- }
- /**
- * optional bool nullparameter = 5;
- */
- public boolean getNullparameter() {
- return nullparameter_;
- }
-
- private void initFields() {
- stringParamter_ = "";
- integerParameter_ = 0L;
- doubleParameter_ = 0D;
- blobParameter_ = com.google.protobuf.ByteString.EMPTY;
- nullparameter_ = false;
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeBytes(1, getStringParamterBytes());
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeUInt64(2, integerParameter_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeDouble(3, doubleParameter_);
- }
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
- output.writeBytes(4, blobParameter_);
- }
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
- output.writeBool(5, nullparameter_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(1, getStringParamterBytes());
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt64Size(2, integerParameter_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- size += com.google.protobuf.CodedOutputStream
- .computeDoubleSize(3, doubleParameter_);
- }
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(4, blobParameter_);
- }
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBoolSize(5, nullparameter_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.SqlStatement.SqlParameter}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- stringParamter_ = "";
- bitField0_ = (bitField0_ & ~0x00000001);
- integerParameter_ = 0L;
- bitField0_ = (bitField0_ & ~0x00000002);
- doubleParameter_ = 0D;
- bitField0_ = (bitField0_ & ~0x00000004);
- blobParameter_ = com.google.protobuf.ByteString.EMPTY;
- bitField0_ = (bitField0_ & ~0x00000008);
- nullparameter_ = false;
- bitField0_ = (bitField0_ & ~0x00000010);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_SqlParameter_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter build() {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter result = new org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.stringParamter_ = stringParamter_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.integerParameter_ = integerParameter_;
- if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
- to_bitField0_ |= 0x00000004;
- }
- result.doubleParameter_ = doubleParameter_;
- if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
- to_bitField0_ |= 0x00000008;
- }
- result.blobParameter_ = blobParameter_;
- if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
- to_bitField0_ |= 0x00000010;
- }
- result.nullparameter_ = nullparameter_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance()) return this;
- if (other.hasStringParamter()) {
- bitField0_ |= 0x00000001;
- stringParamter_ = other.stringParamter_;
- onChanged();
- }
- if (other.hasIntegerParameter()) {
- setIntegerParameter(other.getIntegerParameter());
- }
- if (other.hasDoubleParameter()) {
- setDoubleParameter(other.getDoubleParameter());
- }
- if (other.hasBlobParameter()) {
- setBlobParameter(other.getBlobParameter());
- }
- if (other.hasNullparameter()) {
- setNullparameter(other.getNullparameter());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional string stringParamter = 1;
- private java.lang.Object stringParamter_ = "";
- /**
- * optional string stringParamter = 1;
- */
- public boolean hasStringParamter() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string stringParamter = 1;
- */
- public java.lang.String getStringParamter() {
- java.lang.Object ref = stringParamter_;
- if (!(ref instanceof java.lang.String)) {
- java.lang.String s = ((com.google.protobuf.ByteString) ref)
- .toStringUtf8();
- stringParamter_ = s;
- return s;
- } else {
- return (java.lang.String) ref;
- }
- }
- /**
- * optional string stringParamter = 1;
- */
- public com.google.protobuf.ByteString
- getStringParamterBytes() {
- java.lang.Object ref = stringParamter_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- stringParamter_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * optional string stringParamter = 1;
- */
- public Builder setStringParamter(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- stringParamter_ = value;
- onChanged();
- return this;
- }
- /**
- * optional string stringParamter = 1;
- */
- public Builder clearStringParamter() {
- bitField0_ = (bitField0_ & ~0x00000001);
- stringParamter_ = getDefaultInstance().getStringParamter();
- onChanged();
- return this;
- }
- /**
- * optional string stringParamter = 1;
- */
- public Builder setStringParamterBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- stringParamter_ = value;
- onChanged();
- return this;
- }
-
- // optional uint64 integerParameter = 2;
- private long integerParameter_ ;
- /**
- * optional uint64 integerParameter = 2;
- */
- public boolean hasIntegerParameter() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint64 integerParameter = 2;
- */
- public long getIntegerParameter() {
- return integerParameter_;
- }
- /**
- * optional uint64 integerParameter = 2;
- */
- public Builder setIntegerParameter(long value) {
- bitField0_ |= 0x00000002;
- integerParameter_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint64 integerParameter = 2;
- */
- public Builder clearIntegerParameter() {
- bitField0_ = (bitField0_ & ~0x00000002);
- integerParameter_ = 0L;
- onChanged();
- return this;
- }
-
- // optional double doubleParameter = 3;
- private double doubleParameter_ ;
- /**
- * optional double doubleParameter = 3;
- */
- public boolean hasDoubleParameter() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional double doubleParameter = 3;
- */
- public double getDoubleParameter() {
- return doubleParameter_;
- }
- /**
- * optional double doubleParameter = 3;
- */
- public Builder setDoubleParameter(double value) {
- bitField0_ |= 0x00000004;
- doubleParameter_ = value;
- onChanged();
- return this;
- }
- /**
- * optional double doubleParameter = 3;
- */
- public Builder clearDoubleParameter() {
- bitField0_ = (bitField0_ & ~0x00000004);
- doubleParameter_ = 0D;
- onChanged();
- return this;
- }
-
- // optional bytes blobParameter = 4;
- private com.google.protobuf.ByteString blobParameter_ = com.google.protobuf.ByteString.EMPTY;
- /**
- * optional bytes blobParameter = 4;
- */
- public boolean hasBlobParameter() {
- return ((bitField0_ & 0x00000008) == 0x00000008);
- }
- /**
- * optional bytes blobParameter = 4;
- */
- public com.google.protobuf.ByteString getBlobParameter() {
- return blobParameter_;
- }
- /**
- * optional bytes blobParameter = 4;
- */
- public Builder setBlobParameter(com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000008;
- blobParameter_ = value;
- onChanged();
- return this;
- }
- /**
- * optional bytes blobParameter = 4;
- */
- public Builder clearBlobParameter() {
- bitField0_ = (bitField0_ & ~0x00000008);
- blobParameter_ = getDefaultInstance().getBlobParameter();
- onChanged();
- return this;
- }
-
- // optional bool nullparameter = 5;
- private boolean nullparameter_ ;
- /**
- * optional bool nullparameter = 5;
- */
- public boolean hasNullparameter() {
- return ((bitField0_ & 0x00000010) == 0x00000010);
- }
- /**
- * optional bool nullparameter = 5;
- */
- public boolean getNullparameter() {
- return nullparameter_;
- }
- /**
- * optional bool nullparameter = 5;
- */
- public Builder setNullparameter(boolean value) {
- bitField0_ |= 0x00000010;
- nullparameter_ = value;
- onChanged();
- return this;
- }
- /**
- * optional bool nullparameter = 5;
- */
- public Builder clearNullparameter() {
- bitField0_ = (bitField0_ & ~0x00000010);
- nullparameter_ = false;
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.SqlStatement.SqlParameter)
- }
-
- static {
- defaultInstance = new SqlParameter(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.SqlStatement.SqlParameter)
- }
-
- private int bitField0_;
- // optional string statement = 1;
- public static final int STATEMENT_FIELD_NUMBER = 1;
- private java.lang.Object statement_;
- /**
- * optional string statement = 1;
- */
- public boolean hasStatement() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string statement = 1;
- */
- public java.lang.String getStatement() {
- java.lang.Object ref = statement_;
- if (ref instanceof java.lang.String) {
- return (java.lang.String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- java.lang.String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- statement_ = s;
- }
- return s;
- }
- }
- /**
- * optional string statement = 1;
- */
- public com.google.protobuf.ByteString
- getStatementBytes() {
- java.lang.Object ref = statement_;
- if (ref instanceof java.lang.String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- statement_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- // repeated .signal.SqlStatement.SqlParameter parameters = 2;
- public static final int PARAMETERS_FIELD_NUMBER = 2;
- private java.util.List parameters_;
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public java.util.List getParametersList() {
- return parameters_;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public java.util.List extends org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder>
- getParametersOrBuilderList() {
- return parameters_;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public int getParametersCount() {
- return parameters_.size();
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getParameters(int index) {
- return parameters_.get(index);
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder getParametersOrBuilder(
- int index) {
- return parameters_.get(index);
- }
-
- private void initFields() {
- statement_ = "";
- parameters_ = java.util.Collections.emptyList();
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeBytes(1, getStatementBytes());
- }
- for (int i = 0; i < parameters_.size(); i++) {
- output.writeMessage(2, parameters_.get(i));
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(1, getStatementBytes());
- }
- for (int i = 0; i < parameters_.size(); i++) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(2, parameters_.get(i));
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.SqlStatement}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.class, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- getParametersFieldBuilder();
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- statement_ = "";
- bitField0_ = (bitField0_ & ~0x00000001);
- if (parametersBuilder_ == null) {
- parameters_ = java.util.Collections.emptyList();
- bitField0_ = (bitField0_ & ~0x00000002);
- } else {
- parametersBuilder_.clear();
- }
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SqlStatement_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement build() {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement result = new org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.statement_ = statement_;
- if (parametersBuilder_ == null) {
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- parameters_ = java.util.Collections.unmodifiableList(parameters_);
- bitField0_ = (bitField0_ & ~0x00000002);
- }
- result.parameters_ = parameters_;
- } else {
- result.parameters_ = parametersBuilder_.build();
- }
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance()) return this;
- if (other.hasStatement()) {
- bitField0_ |= 0x00000001;
- statement_ = other.statement_;
- onChanged();
- }
- if (parametersBuilder_ == null) {
- if (!other.parameters_.isEmpty()) {
- if (parameters_.isEmpty()) {
- parameters_ = other.parameters_;
- bitField0_ = (bitField0_ & ~0x00000002);
- } else {
- ensureParametersIsMutable();
- parameters_.addAll(other.parameters_);
- }
- onChanged();
- }
- } else {
- if (!other.parameters_.isEmpty()) {
- if (parametersBuilder_.isEmpty()) {
- parametersBuilder_.dispose();
- parametersBuilder_ = null;
- parameters_ = other.parameters_;
- bitField0_ = (bitField0_ & ~0x00000002);
- parametersBuilder_ =
- com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
- getParametersFieldBuilder() : null;
- } else {
- parametersBuilder_.addAllMessages(other.parameters_);
- }
- }
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional string statement = 1;
- private java.lang.Object statement_ = "";
- /**
- * optional string statement = 1;
- */
- public boolean hasStatement() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string statement = 1;
- */
- public java.lang.String getStatement() {
- java.lang.Object ref = statement_;
- if (!(ref instanceof java.lang.String)) {
- java.lang.String s = ((com.google.protobuf.ByteString) ref)
- .toStringUtf8();
- statement_ = s;
- return s;
- } else {
- return (java.lang.String) ref;
- }
- }
- /**
- * optional string statement = 1;
- */
- public com.google.protobuf.ByteString
- getStatementBytes() {
- java.lang.Object ref = statement_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- statement_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * optional string statement = 1;
- */
- public Builder setStatement(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- statement_ = value;
- onChanged();
- return this;
- }
- /**
- * optional string statement = 1;
- */
- public Builder clearStatement() {
- bitField0_ = (bitField0_ & ~0x00000001);
- statement_ = getDefaultInstance().getStatement();
- onChanged();
- return this;
- }
- /**
- * optional string statement = 1;
- */
- public Builder setStatementBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- statement_ = value;
- onChanged();
- return this;
- }
-
- // repeated .signal.SqlStatement.SqlParameter parameters = 2;
- private java.util.List parameters_ =
- java.util.Collections.emptyList();
- private void ensureParametersIsMutable() {
- if (!((bitField0_ & 0x00000002) == 0x00000002)) {
- parameters_ = new java.util.ArrayList(parameters_);
- bitField0_ |= 0x00000002;
- }
- }
-
- private com.google.protobuf.RepeatedFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder> parametersBuilder_;
-
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public java.util.List getParametersList() {
- if (parametersBuilder_ == null) {
- return java.util.Collections.unmodifiableList(parameters_);
- } else {
- return parametersBuilder_.getMessageList();
- }
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public int getParametersCount() {
- if (parametersBuilder_ == null) {
- return parameters_.size();
- } else {
- return parametersBuilder_.getCount();
- }
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter getParameters(int index) {
- if (parametersBuilder_ == null) {
- return parameters_.get(index);
- } else {
- return parametersBuilder_.getMessage(index);
- }
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder setParameters(
- int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter value) {
- if (parametersBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- ensureParametersIsMutable();
- parameters_.set(index, value);
- onChanged();
- } else {
- parametersBuilder_.setMessage(index, value);
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder setParameters(
- int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder builderForValue) {
- if (parametersBuilder_ == null) {
- ensureParametersIsMutable();
- parameters_.set(index, builderForValue.build());
- onChanged();
- } else {
- parametersBuilder_.setMessage(index, builderForValue.build());
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder addParameters(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter value) {
- if (parametersBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- ensureParametersIsMutable();
- parameters_.add(value);
- onChanged();
- } else {
- parametersBuilder_.addMessage(value);
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder addParameters(
- int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter value) {
- if (parametersBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- ensureParametersIsMutable();
- parameters_.add(index, value);
- onChanged();
- } else {
- parametersBuilder_.addMessage(index, value);
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder addParameters(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder builderForValue) {
- if (parametersBuilder_ == null) {
- ensureParametersIsMutable();
- parameters_.add(builderForValue.build());
- onChanged();
- } else {
- parametersBuilder_.addMessage(builderForValue.build());
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder addParameters(
- int index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder builderForValue) {
- if (parametersBuilder_ == null) {
- ensureParametersIsMutable();
- parameters_.add(index, builderForValue.build());
- onChanged();
- } else {
- parametersBuilder_.addMessage(index, builderForValue.build());
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder addAllParameters(
- java.lang.Iterable extends org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter> values) {
- if (parametersBuilder_ == null) {
- ensureParametersIsMutable();
- super.addAll(values, parameters_);
- onChanged();
- } else {
- parametersBuilder_.addAllMessages(values);
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder clearParameters() {
- if (parametersBuilder_ == null) {
- parameters_ = java.util.Collections.emptyList();
- bitField0_ = (bitField0_ & ~0x00000002);
- onChanged();
- } else {
- parametersBuilder_.clear();
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public Builder removeParameters(int index) {
- if (parametersBuilder_ == null) {
- ensureParametersIsMutable();
- parameters_.remove(index);
- onChanged();
- } else {
- parametersBuilder_.remove(index);
- }
- return this;
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder getParametersBuilder(
- int index) {
- return getParametersFieldBuilder().getBuilder(index);
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder getParametersOrBuilder(
- int index) {
- if (parametersBuilder_ == null) {
- return parameters_.get(index); } else {
- return parametersBuilder_.getMessageOrBuilder(index);
- }
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public java.util.List extends org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder>
- getParametersOrBuilderList() {
- if (parametersBuilder_ != null) {
- return parametersBuilder_.getMessageOrBuilderList();
- } else {
- return java.util.Collections.unmodifiableList(parameters_);
- }
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder addParametersBuilder() {
- return getParametersFieldBuilder().addBuilder(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance());
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder addParametersBuilder(
- int index) {
- return getParametersFieldBuilder().addBuilder(
- index, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.getDefaultInstance());
- }
- /**
- * repeated .signal.SqlStatement.SqlParameter parameters = 2;
- */
- public java.util.List
- getParametersBuilderList() {
- return getParametersFieldBuilder().getBuilderList();
- }
- private com.google.protobuf.RepeatedFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder>
- getParametersFieldBuilder() {
- if (parametersBuilder_ == null) {
- parametersBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameter.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.SqlParameterOrBuilder>(
- parameters_,
- ((bitField0_ & 0x00000002) == 0x00000002),
- getParentForChildren(),
- isClean());
- parameters_ = null;
- }
- return parametersBuilder_;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.SqlStatement)
- }
-
- static {
- defaultInstance = new SqlStatement(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.SqlStatement)
- }
-
- public interface SharedPreferenceOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional string file = 1;
- /**
- * optional string file = 1;
- */
- boolean hasFile();
- /**
- * optional string file = 1;
- */
- java.lang.String getFile();
- /**
- * optional string file = 1;
- */
- com.google.protobuf.ByteString
- getFileBytes();
-
- // optional string key = 2;
- /**
- * optional string key = 2;
- */
- boolean hasKey();
- /**
- * optional string key = 2;
- */
- java.lang.String getKey();
- /**
- * optional string key = 2;
- */
- com.google.protobuf.ByteString
- getKeyBytes();
-
- // optional string value = 3;
- /**
- * optional string value = 3;
- */
- boolean hasValue();
- /**
- * optional string value = 3;
- */
- java.lang.String getValue();
- /**
- * optional string value = 3;
- */
- com.google.protobuf.ByteString
- getValueBytes();
- }
- /**
- * Protobuf type {@code signal.SharedPreference}
- */
- public static final class SharedPreference extends
- com.google.protobuf.GeneratedMessage
- implements SharedPreferenceOrBuilder {
- // Use SharedPreference.newBuilder() to construct.
- private SharedPreference(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private SharedPreference(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final SharedPreference defaultInstance;
- public static SharedPreference getDefaultInstance() {
- return defaultInstance;
- }
-
- public SharedPreference getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private SharedPreference(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- bitField0_ |= 0x00000001;
- file_ = input.readBytes();
- break;
- }
- case 18: {
- bitField0_ |= 0x00000002;
- key_ = input.readBytes();
- break;
- }
- case 26: {
- bitField0_ |= 0x00000004;
- value_ = input.readBytes();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.class, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public SharedPreference parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new SharedPreference(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional string file = 1;
- public static final int FILE_FIELD_NUMBER = 1;
- private java.lang.Object file_;
- /**
- * optional string file = 1;
- */
- public boolean hasFile() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string file = 1;
- */
- public java.lang.String getFile() {
- java.lang.Object ref = file_;
- if (ref instanceof java.lang.String) {
- return (java.lang.String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- java.lang.String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- file_ = s;
- }
- return s;
- }
- }
- /**
- * optional string file = 1;
- */
- public com.google.protobuf.ByteString
- getFileBytes() {
- java.lang.Object ref = file_;
- if (ref instanceof java.lang.String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- file_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- // optional string key = 2;
- public static final int KEY_FIELD_NUMBER = 2;
- private java.lang.Object key_;
- /**
- * optional string key = 2;
- */
- public boolean hasKey() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional string key = 2;
- */
- public java.lang.String getKey() {
- java.lang.Object ref = key_;
- if (ref instanceof java.lang.String) {
- return (java.lang.String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- java.lang.String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- key_ = s;
- }
- return s;
- }
- }
- /**
- * optional string key = 2;
- */
- public com.google.protobuf.ByteString
- getKeyBytes() {
- java.lang.Object ref = key_;
- if (ref instanceof java.lang.String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- key_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- // optional string value = 3;
- public static final int VALUE_FIELD_NUMBER = 3;
- private java.lang.Object value_;
- /**
- * optional string value = 3;
- */
- public boolean hasValue() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional string value = 3;
- */
- public java.lang.String getValue() {
- java.lang.Object ref = value_;
- if (ref instanceof java.lang.String) {
- return (java.lang.String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- java.lang.String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- value_ = s;
- }
- return s;
- }
- }
- /**
- * optional string value = 3;
- */
- public com.google.protobuf.ByteString
- getValueBytes() {
- java.lang.Object ref = value_;
- if (ref instanceof java.lang.String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- value_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- private void initFields() {
- file_ = "";
- key_ = "";
- value_ = "";
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeBytes(1, getFileBytes());
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeBytes(2, getKeyBytes());
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeBytes(3, getValueBytes());
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(1, getFileBytes());
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(2, getKeyBytes());
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(3, getValueBytes());
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.SharedPreference}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.class, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- file_ = "";
- bitField0_ = (bitField0_ & ~0x00000001);
- key_ = "";
- bitField0_ = (bitField0_ & ~0x00000002);
- value_ = "";
- bitField0_ = (bitField0_ & ~0x00000004);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_SharedPreference_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference build() {
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference result = new org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.file_ = file_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.key_ = key_;
- if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
- to_bitField0_ |= 0x00000004;
- }
- result.value_ = value_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance()) return this;
- if (other.hasFile()) {
- bitField0_ |= 0x00000001;
- file_ = other.file_;
- onChanged();
- }
- if (other.hasKey()) {
- bitField0_ |= 0x00000002;
- key_ = other.key_;
- onChanged();
- }
- if (other.hasValue()) {
- bitField0_ |= 0x00000004;
- value_ = other.value_;
- onChanged();
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional string file = 1;
- private java.lang.Object file_ = "";
- /**
- * optional string file = 1;
- */
- public boolean hasFile() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string file = 1;
- */
- public java.lang.String getFile() {
- java.lang.Object ref = file_;
- if (!(ref instanceof java.lang.String)) {
- java.lang.String s = ((com.google.protobuf.ByteString) ref)
- .toStringUtf8();
- file_ = s;
- return s;
- } else {
- return (java.lang.String) ref;
- }
- }
- /**
- * optional string file = 1;
- */
- public com.google.protobuf.ByteString
- getFileBytes() {
- java.lang.Object ref = file_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- file_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * optional string file = 1;
- */
- public Builder setFile(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- file_ = value;
- onChanged();
- return this;
- }
- /**
- * optional string file = 1;
- */
- public Builder clearFile() {
- bitField0_ = (bitField0_ & ~0x00000001);
- file_ = getDefaultInstance().getFile();
- onChanged();
- return this;
- }
- /**
- * optional string file = 1;
- */
- public Builder setFileBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- file_ = value;
- onChanged();
- return this;
- }
-
- // optional string key = 2;
- private java.lang.Object key_ = "";
- /**
- * optional string key = 2;
- */
- public boolean hasKey() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional string key = 2;
- */
- public java.lang.String getKey() {
- java.lang.Object ref = key_;
- if (!(ref instanceof java.lang.String)) {
- java.lang.String s = ((com.google.protobuf.ByteString) ref)
- .toStringUtf8();
- key_ = s;
- return s;
- } else {
- return (java.lang.String) ref;
- }
- }
- /**
- * optional string key = 2;
- */
- public com.google.protobuf.ByteString
- getKeyBytes() {
- java.lang.Object ref = key_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- key_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * optional string key = 2;
- */
- public Builder setKey(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- key_ = value;
- onChanged();
- return this;
- }
- /**
- * optional string key = 2;
- */
- public Builder clearKey() {
- bitField0_ = (bitField0_ & ~0x00000002);
- key_ = getDefaultInstance().getKey();
- onChanged();
- return this;
- }
- /**
- * optional string key = 2;
- */
- public Builder setKeyBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- key_ = value;
- onChanged();
- return this;
- }
-
- // optional string value = 3;
- private java.lang.Object value_ = "";
- /**
- * optional string value = 3;
- */
- public boolean hasValue() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional string value = 3;
- */
- public java.lang.String getValue() {
- java.lang.Object ref = value_;
- if (!(ref instanceof java.lang.String)) {
- java.lang.String s = ((com.google.protobuf.ByteString) ref)
- .toStringUtf8();
- value_ = s;
- return s;
- } else {
- return (java.lang.String) ref;
- }
- }
- /**
- * optional string value = 3;
- */
- public com.google.protobuf.ByteString
- getValueBytes() {
- java.lang.Object ref = value_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- value_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * optional string value = 3;
- */
- public Builder setValue(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000004;
- value_ = value;
- onChanged();
- return this;
- }
- /**
- * optional string value = 3;
- */
- public Builder clearValue() {
- bitField0_ = (bitField0_ & ~0x00000004);
- value_ = getDefaultInstance().getValue();
- onChanged();
- return this;
- }
- /**
- * optional string value = 3;
- */
- public Builder setValueBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000004;
- value_ = value;
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.SharedPreference)
- }
-
- static {
- defaultInstance = new SharedPreference(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.SharedPreference)
- }
-
- public interface AttachmentOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional uint64 rowId = 1;
- /**
- * optional uint64 rowId = 1;
- */
- boolean hasRowId();
- /**
- * optional uint64 rowId = 1;
- */
- long getRowId();
-
- // optional uint64 attachmentId = 2;
- /**
- * optional uint64 attachmentId = 2;
- */
- boolean hasAttachmentId();
- /**
- * optional uint64 attachmentId = 2;
- */
- long getAttachmentId();
-
- // optional uint32 length = 3;
- /**
- * optional uint32 length = 3;
- */
- boolean hasLength();
- /**
- * optional uint32 length = 3;
- */
- int getLength();
- }
- /**
- * Protobuf type {@code signal.Attachment}
- */
- public static final class Attachment extends
- com.google.protobuf.GeneratedMessage
- implements AttachmentOrBuilder {
- // Use Attachment.newBuilder() to construct.
- private Attachment(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private Attachment(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final Attachment defaultInstance;
- public static Attachment getDefaultInstance() {
- return defaultInstance;
- }
-
- public Attachment getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private Attachment(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 8: {
- bitField0_ |= 0x00000001;
- rowId_ = input.readUInt64();
- break;
- }
- case 16: {
- bitField0_ |= 0x00000002;
- attachmentId_ = input.readUInt64();
- break;
- }
- case 24: {
- bitField0_ |= 0x00000004;
- length_ = input.readUInt32();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment.class, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public Attachment parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new Attachment(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional uint64 rowId = 1;
- public static final int ROWID_FIELD_NUMBER = 1;
- private long rowId_;
- /**
- * optional uint64 rowId = 1;
- */
- public boolean hasRowId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional uint64 rowId = 1;
- */
- public long getRowId() {
- return rowId_;
- }
-
- // optional uint64 attachmentId = 2;
- public static final int ATTACHMENTID_FIELD_NUMBER = 2;
- private long attachmentId_;
- /**
- * optional uint64 attachmentId = 2;
- */
- public boolean hasAttachmentId() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint64 attachmentId = 2;
- */
- public long getAttachmentId() {
- return attachmentId_;
- }
-
- // optional uint32 length = 3;
- public static final int LENGTH_FIELD_NUMBER = 3;
- private int length_;
- /**
- * optional uint32 length = 3;
- */
- public boolean hasLength() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional uint32 length = 3;
- */
- public int getLength() {
- return length_;
- }
-
- private void initFields() {
- rowId_ = 0L;
- attachmentId_ = 0L;
- length_ = 0;
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeUInt64(1, rowId_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeUInt64(2, attachmentId_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeUInt32(3, length_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt64Size(1, rowId_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt64Size(2, attachmentId_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt32Size(3, length_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Attachment parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Attachment prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.Attachment}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment.class, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Attachment.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- rowId_ = 0L;
- bitField0_ = (bitField0_ & ~0x00000001);
- attachmentId_ = 0L;
- bitField0_ = (bitField0_ & ~0x00000002);
- length_ = 0;
- bitField0_ = (bitField0_ & ~0x00000004);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Attachment_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Attachment getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Attachment build() {
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Attachment buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment result = new org.thoughtcrime.securesms.backup.BackupProtos.Attachment(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.rowId_ = rowId_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.attachmentId_ = attachmentId_;
- if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
- to_bitField0_ |= 0x00000004;
- }
- result.length_ = length_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Attachment) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Attachment)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Attachment other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance()) return this;
- if (other.hasRowId()) {
- setRowId(other.getRowId());
- }
- if (other.hasAttachmentId()) {
- setAttachmentId(other.getAttachmentId());
- }
- if (other.hasLength()) {
- setLength(other.getLength());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Attachment) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional uint64 rowId = 1;
- private long rowId_ ;
- /**
- * optional uint64 rowId = 1;
- */
- public boolean hasRowId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional uint64 rowId = 1;
- */
- public long getRowId() {
- return rowId_;
- }
- /**
- * optional uint64 rowId = 1;
- */
- public Builder setRowId(long value) {
- bitField0_ |= 0x00000001;
- rowId_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint64 rowId = 1;
- */
- public Builder clearRowId() {
- bitField0_ = (bitField0_ & ~0x00000001);
- rowId_ = 0L;
- onChanged();
- return this;
- }
-
- // optional uint64 attachmentId = 2;
- private long attachmentId_ ;
- /**
- * optional uint64 attachmentId = 2;
- */
- public boolean hasAttachmentId() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint64 attachmentId = 2;
- */
- public long getAttachmentId() {
- return attachmentId_;
- }
- /**
- * optional uint64 attachmentId = 2;
- */
- public Builder setAttachmentId(long value) {
- bitField0_ |= 0x00000002;
- attachmentId_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint64 attachmentId = 2;
- */
- public Builder clearAttachmentId() {
- bitField0_ = (bitField0_ & ~0x00000002);
- attachmentId_ = 0L;
- onChanged();
- return this;
- }
-
- // optional uint32 length = 3;
- private int length_ ;
- /**
- * optional uint32 length = 3;
- */
- public boolean hasLength() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional uint32 length = 3;
- */
- public int getLength() {
- return length_;
- }
- /**
- * optional uint32 length = 3;
- */
- public Builder setLength(int value) {
- bitField0_ |= 0x00000004;
- length_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint32 length = 3;
- */
- public Builder clearLength() {
- bitField0_ = (bitField0_ & ~0x00000004);
- length_ = 0;
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.Attachment)
- }
-
- static {
- defaultInstance = new Attachment(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.Attachment)
- }
-
- public interface StickerOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional uint64 rowId = 1;
- /**
- * optional uint64 rowId = 1;
- */
- boolean hasRowId();
- /**
- * optional uint64 rowId = 1;
- */
- long getRowId();
-
- // optional uint32 length = 2;
- /**
- * optional uint32 length = 2;
- */
- boolean hasLength();
- /**
- * optional uint32 length = 2;
- */
- int getLength();
- }
- /**
- * Protobuf type {@code signal.Sticker}
- */
- public static final class Sticker extends
- com.google.protobuf.GeneratedMessage
- implements StickerOrBuilder {
- // Use Sticker.newBuilder() to construct.
- private Sticker(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private Sticker(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final Sticker defaultInstance;
- public static Sticker getDefaultInstance() {
- return defaultInstance;
- }
-
- public Sticker getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private Sticker(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 8: {
- bitField0_ |= 0x00000001;
- rowId_ = input.readUInt64();
- break;
- }
- case 16: {
- bitField0_ |= 0x00000002;
- length_ = input.readUInt32();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker.class, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public Sticker parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new Sticker(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional uint64 rowId = 1;
- public static final int ROWID_FIELD_NUMBER = 1;
- private long rowId_;
- /**
- * optional uint64 rowId = 1;
- */
- public boolean hasRowId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional uint64 rowId = 1;
- */
- public long getRowId() {
- return rowId_;
- }
-
- // optional uint32 length = 2;
- public static final int LENGTH_FIELD_NUMBER = 2;
- private int length_;
- /**
- * optional uint32 length = 2;
- */
- public boolean hasLength() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint32 length = 2;
- */
- public int getLength() {
- return length_;
- }
-
- private void initFields() {
- rowId_ = 0L;
- length_ = 0;
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeUInt64(1, rowId_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeUInt32(2, length_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt64Size(1, rowId_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt32Size(2, length_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Sticker parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Sticker prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.Sticker}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker.class, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Sticker.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- rowId_ = 0L;
- bitField0_ = (bitField0_ & ~0x00000001);
- length_ = 0;
- bitField0_ = (bitField0_ & ~0x00000002);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Sticker_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Sticker getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Sticker build() {
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Sticker buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker result = new org.thoughtcrime.securesms.backup.BackupProtos.Sticker(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.rowId_ = rowId_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.length_ = length_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Sticker) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Sticker)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Sticker other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance()) return this;
- if (other.hasRowId()) {
- setRowId(other.getRowId());
- }
- if (other.hasLength()) {
- setLength(other.getLength());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Sticker) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional uint64 rowId = 1;
- private long rowId_ ;
- /**
- * optional uint64 rowId = 1;
- */
- public boolean hasRowId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional uint64 rowId = 1;
- */
- public long getRowId() {
- return rowId_;
- }
- /**
- * optional uint64 rowId = 1;
- */
- public Builder setRowId(long value) {
- bitField0_ |= 0x00000001;
- rowId_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint64 rowId = 1;
- */
- public Builder clearRowId() {
- bitField0_ = (bitField0_ & ~0x00000001);
- rowId_ = 0L;
- onChanged();
- return this;
- }
-
- // optional uint32 length = 2;
- private int length_ ;
- /**
- * optional uint32 length = 2;
- */
- public boolean hasLength() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint32 length = 2;
- */
- public int getLength() {
- return length_;
- }
- /**
- * optional uint32 length = 2;
- */
- public Builder setLength(int value) {
- bitField0_ |= 0x00000002;
- length_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint32 length = 2;
- */
- public Builder clearLength() {
- bitField0_ = (bitField0_ & ~0x00000002);
- length_ = 0;
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.Sticker)
- }
-
- static {
- defaultInstance = new Sticker(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.Sticker)
- }
-
- public interface AvatarOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional string name = 1;
- /**
- * optional string name = 1;
- */
- boolean hasName();
- /**
- * optional string name = 1;
- */
- java.lang.String getName();
- /**
- * optional string name = 1;
- */
- com.google.protobuf.ByteString
- getNameBytes();
-
- // optional uint32 length = 2;
- /**
- * optional uint32 length = 2;
- */
- boolean hasLength();
- /**
- * optional uint32 length = 2;
- */
- int getLength();
- }
- /**
- * Protobuf type {@code signal.Avatar}
- */
- public static final class Avatar extends
- com.google.protobuf.GeneratedMessage
- implements AvatarOrBuilder {
- // Use Avatar.newBuilder() to construct.
- private Avatar(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private Avatar(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final Avatar defaultInstance;
- public static Avatar getDefaultInstance() {
- return defaultInstance;
- }
-
- public Avatar getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private Avatar(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- bitField0_ |= 0x00000001;
- name_ = input.readBytes();
- break;
- }
- case 16: {
- bitField0_ |= 0x00000002;
- length_ = input.readUInt32();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar.class, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public Avatar parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new Avatar(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional string name = 1;
- public static final int NAME_FIELD_NUMBER = 1;
- private java.lang.Object name_;
- /**
- * optional string name = 1;
- */
- public boolean hasName() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string name = 1;
- */
- public java.lang.String getName() {
- java.lang.Object ref = name_;
- if (ref instanceof java.lang.String) {
- return (java.lang.String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- java.lang.String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- name_ = s;
- }
- return s;
- }
- }
- /**
- * optional string name = 1;
- */
- public com.google.protobuf.ByteString
- getNameBytes() {
- java.lang.Object ref = name_;
- if (ref instanceof java.lang.String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- name_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- // optional uint32 length = 2;
- public static final int LENGTH_FIELD_NUMBER = 2;
- private int length_;
- /**
- * optional uint32 length = 2;
- */
- public boolean hasLength() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint32 length = 2;
- */
- public int getLength() {
- return length_;
- }
-
- private void initFields() {
- name_ = "";
- length_ = 0;
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeBytes(1, getNameBytes());
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeUInt32(2, length_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(1, getNameBytes());
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt32Size(2, length_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Avatar parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Avatar prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.Avatar}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar.class, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Avatar.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- name_ = "";
- bitField0_ = (bitField0_ & ~0x00000001);
- length_ = 0;
- bitField0_ = (bitField0_ & ~0x00000002);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Avatar_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Avatar getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Avatar build() {
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Avatar buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar result = new org.thoughtcrime.securesms.backup.BackupProtos.Avatar(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.name_ = name_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.length_ = length_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Avatar) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Avatar)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Avatar other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance()) return this;
- if (other.hasName()) {
- bitField0_ |= 0x00000001;
- name_ = other.name_;
- onChanged();
- }
- if (other.hasLength()) {
- setLength(other.getLength());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Avatar) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional string name = 1;
- private java.lang.Object name_ = "";
- /**
- * optional string name = 1;
- */
- public boolean hasName() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional string name = 1;
- */
- public java.lang.String getName() {
- java.lang.Object ref = name_;
- if (!(ref instanceof java.lang.String)) {
- java.lang.String s = ((com.google.protobuf.ByteString) ref)
- .toStringUtf8();
- name_ = s;
- return s;
- } else {
- return (java.lang.String) ref;
- }
- }
- /**
- * optional string name = 1;
- */
- public com.google.protobuf.ByteString
- getNameBytes() {
- java.lang.Object ref = name_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (java.lang.String) ref);
- name_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * optional string name = 1;
- */
- public Builder setName(
- java.lang.String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- name_ = value;
- onChanged();
- return this;
- }
- /**
- * optional string name = 1;
- */
- public Builder clearName() {
- bitField0_ = (bitField0_ & ~0x00000001);
- name_ = getDefaultInstance().getName();
- onChanged();
- return this;
- }
- /**
- * optional string name = 1;
- */
- public Builder setNameBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- name_ = value;
- onChanged();
- return this;
- }
-
- // optional uint32 length = 2;
- private int length_ ;
- /**
- * optional uint32 length = 2;
- */
- public boolean hasLength() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional uint32 length = 2;
- */
- public int getLength() {
- return length_;
- }
- /**
- * optional uint32 length = 2;
- */
- public Builder setLength(int value) {
- bitField0_ |= 0x00000002;
- length_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint32 length = 2;
- */
- public Builder clearLength() {
- bitField0_ = (bitField0_ & ~0x00000002);
- length_ = 0;
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.Avatar)
- }
-
- static {
- defaultInstance = new Avatar(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.Avatar)
- }
-
- public interface DatabaseVersionOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional uint32 version = 1;
- /**
- * optional uint32 version = 1;
- */
- boolean hasVersion();
- /**
- * optional uint32 version = 1;
- */
- int getVersion();
- }
- /**
- * Protobuf type {@code signal.DatabaseVersion}
- */
- public static final class DatabaseVersion extends
- com.google.protobuf.GeneratedMessage
- implements DatabaseVersionOrBuilder {
- // Use DatabaseVersion.newBuilder() to construct.
- private DatabaseVersion(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private DatabaseVersion(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final DatabaseVersion defaultInstance;
- public static DatabaseVersion getDefaultInstance() {
- return defaultInstance;
- }
-
- public DatabaseVersion getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private DatabaseVersion(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 8: {
- bitField0_ |= 0x00000001;
- version_ = input.readUInt32();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.class, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public DatabaseVersion parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new DatabaseVersion(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional uint32 version = 1;
- public static final int VERSION_FIELD_NUMBER = 1;
- private int version_;
- /**
- * optional uint32 version = 1;
- */
- public boolean hasVersion() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional uint32 version = 1;
- */
- public int getVersion() {
- return version_;
- }
-
- private void initFields() {
- version_ = 0;
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeUInt32(1, version_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeUInt32Size(1, version_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.DatabaseVersion}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.class, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- version_ = 0;
- bitField0_ = (bitField0_ & ~0x00000001);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_DatabaseVersion_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion build() {
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion result = new org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.version_ = version_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance()) return this;
- if (other.hasVersion()) {
- setVersion(other.getVersion());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional uint32 version = 1;
- private int version_ ;
- /**
- * optional uint32 version = 1;
- */
- public boolean hasVersion() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional uint32 version = 1;
- */
- public int getVersion() {
- return version_;
- }
- /**
- * optional uint32 version = 1;
- */
- public Builder setVersion(int value) {
- bitField0_ |= 0x00000001;
- version_ = value;
- onChanged();
- return this;
- }
- /**
- * optional uint32 version = 1;
- */
- public Builder clearVersion() {
- bitField0_ = (bitField0_ & ~0x00000001);
- version_ = 0;
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.DatabaseVersion)
- }
-
- static {
- defaultInstance = new DatabaseVersion(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.DatabaseVersion)
- }
-
- public interface HeaderOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional bytes iv = 1;
- /**
- * optional bytes iv = 1;
- */
- boolean hasIv();
- /**
- * optional bytes iv = 1;
- */
- com.google.protobuf.ByteString getIv();
-
- // optional bytes salt = 2;
- /**
- * optional bytes salt = 2;
- */
- boolean hasSalt();
- /**
- * optional bytes salt = 2;
- */
- com.google.protobuf.ByteString getSalt();
- }
- /**
- * Protobuf type {@code signal.Header}
- */
- public static final class Header extends
- com.google.protobuf.GeneratedMessage
- implements HeaderOrBuilder {
- // Use Header.newBuilder() to construct.
- private Header(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private Header(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final Header defaultInstance;
- public static Header getDefaultInstance() {
- return defaultInstance;
- }
-
- public Header getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private Header(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- bitField0_ |= 0x00000001;
- iv_ = input.readBytes();
- break;
- }
- case 18: {
- bitField0_ |= 0x00000002;
- salt_ = input.readBytes();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Header.class, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public Header parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new Header(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional bytes iv = 1;
- public static final int IV_FIELD_NUMBER = 1;
- private com.google.protobuf.ByteString iv_;
- /**
- * optional bytes iv = 1;
- */
- public boolean hasIv() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional bytes iv = 1;
- */
- public com.google.protobuf.ByteString getIv() {
- return iv_;
- }
-
- // optional bytes salt = 2;
- public static final int SALT_FIELD_NUMBER = 2;
- private com.google.protobuf.ByteString salt_;
- /**
- * optional bytes salt = 2;
- */
- public boolean hasSalt() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional bytes salt = 2;
- */
- public com.google.protobuf.ByteString getSalt() {
- return salt_;
- }
-
- private void initFields() {
- iv_ = com.google.protobuf.ByteString.EMPTY;
- salt_ = com.google.protobuf.ByteString.EMPTY;
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeBytes(1, iv_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeBytes(2, salt_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(1, iv_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(2, salt_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.Header parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.Header prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.Header}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.Header.class, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.Header.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- iv_ = com.google.protobuf.ByteString.EMPTY;
- bitField0_ = (bitField0_ & ~0x00000001);
- salt_ = com.google.protobuf.ByteString.EMPTY;
- bitField0_ = (bitField0_ & ~0x00000002);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_Header_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Header getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Header build() {
- org.thoughtcrime.securesms.backup.BackupProtos.Header result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.Header buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.Header result = new org.thoughtcrime.securesms.backup.BackupProtos.Header(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.iv_ = iv_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.salt_ = salt_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.Header) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.Header)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.Header other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance()) return this;
- if (other.hasIv()) {
- setIv(other.getIv());
- }
- if (other.hasSalt()) {
- setSalt(other.getSalt());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.Header parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.Header) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional bytes iv = 1;
- private com.google.protobuf.ByteString iv_ = com.google.protobuf.ByteString.EMPTY;
- /**
- * optional bytes iv = 1;
- */
- public boolean hasIv() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional bytes iv = 1;
- */
- public com.google.protobuf.ByteString getIv() {
- return iv_;
- }
- /**
- * optional bytes iv = 1;
- */
- public Builder setIv(com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000001;
- iv_ = value;
- onChanged();
- return this;
- }
- /**
- * optional bytes iv = 1;
- */
- public Builder clearIv() {
- bitField0_ = (bitField0_ & ~0x00000001);
- iv_ = getDefaultInstance().getIv();
- onChanged();
- return this;
- }
-
- // optional bytes salt = 2;
- private com.google.protobuf.ByteString salt_ = com.google.protobuf.ByteString.EMPTY;
- /**
- * optional bytes salt = 2;
- */
- public boolean hasSalt() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional bytes salt = 2;
- */
- public com.google.protobuf.ByteString getSalt() {
- return salt_;
- }
- /**
- * optional bytes salt = 2;
- */
- public Builder setSalt(com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- salt_ = value;
- onChanged();
- return this;
- }
- /**
- * optional bytes salt = 2;
- */
- public Builder clearSalt() {
- bitField0_ = (bitField0_ & ~0x00000002);
- salt_ = getDefaultInstance().getSalt();
- onChanged();
- return this;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.Header)
- }
-
- static {
- defaultInstance = new Header(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.Header)
- }
-
- public interface BackupFrameOrBuilder
- extends com.google.protobuf.MessageOrBuilder {
-
- // optional .signal.Header header = 1;
- /**
- * optional .signal.Header header = 1;
- */
- boolean hasHeader();
- /**
- * optional .signal.Header header = 1;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.Header getHeader();
- /**
- * optional .signal.Header header = 1;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder getHeaderOrBuilder();
-
- // optional .signal.SqlStatement statement = 2;
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- boolean hasStatement();
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getStatement();
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder getStatementOrBuilder();
-
- // optional .signal.SharedPreference preference = 3;
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- boolean hasPreference();
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getPreference();
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder getPreferenceOrBuilder();
-
- // optional .signal.Attachment attachment = 4;
- /**
- * optional .signal.Attachment attachment = 4;
- */
- boolean hasAttachment();
- /**
- * optional .signal.Attachment attachment = 4;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment getAttachment();
- /**
- * optional .signal.Attachment attachment = 4;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder getAttachmentOrBuilder();
-
- // optional .signal.DatabaseVersion version = 5;
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- boolean hasVersion();
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getVersion();
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder getVersionOrBuilder();
-
- // optional bool end = 6;
- /**
- * optional bool end = 6;
- */
- boolean hasEnd();
- /**
- * optional bool end = 6;
- */
- boolean getEnd();
-
- // optional .signal.Avatar avatar = 7;
- /**
- * optional .signal.Avatar avatar = 7;
- */
- boolean hasAvatar();
- /**
- * optional .signal.Avatar avatar = 7;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar getAvatar();
- /**
- * optional .signal.Avatar avatar = 7;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder getAvatarOrBuilder();
-
- // optional .signal.Sticker sticker = 8;
- /**
- * optional .signal.Sticker sticker = 8;
- */
- boolean hasSticker();
- /**
- * optional .signal.Sticker sticker = 8;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker getSticker();
- /**
- * optional .signal.Sticker sticker = 8;
- */
- org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder getStickerOrBuilder();
- }
- /**
- * Protobuf type {@code signal.BackupFrame}
- */
- public static final class BackupFrame extends
- com.google.protobuf.GeneratedMessage
- implements BackupFrameOrBuilder {
- // Use BackupFrame.newBuilder() to construct.
- private BackupFrame(com.google.protobuf.GeneratedMessage.Builder> builder) {
- super(builder);
- this.unknownFields = builder.getUnknownFields();
- }
- private BackupFrame(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
- private static final BackupFrame defaultInstance;
- public static BackupFrame getDefaultInstance() {
- return defaultInstance;
- }
-
- public BackupFrame getDefaultInstanceForType() {
- return defaultInstance;
- }
-
- private final com.google.protobuf.UnknownFieldSet unknownFields;
- @java.lang.Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private BackupFrame(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- initFields();
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(input, unknownFields,
- extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder subBuilder = null;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- subBuilder = header_.toBuilder();
- }
- header_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Header.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(header_);
- header_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000001;
- break;
- }
- case 18: {
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder subBuilder = null;
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- subBuilder = statement_.toBuilder();
- }
- statement_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(statement_);
- statement_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000002;
- break;
- }
- case 26: {
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder subBuilder = null;
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- subBuilder = preference_.toBuilder();
- }
- preference_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(preference_);
- preference_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000004;
- break;
- }
- case 34: {
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder subBuilder = null;
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
- subBuilder = attachment_.toBuilder();
- }
- attachment_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Attachment.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(attachment_);
- attachment_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000008;
- break;
- }
- case 42: {
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder subBuilder = null;
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
- subBuilder = version_.toBuilder();
- }
- version_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(version_);
- version_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000010;
- break;
- }
- case 48: {
- bitField0_ |= 0x00000020;
- end_ = input.readBool();
- break;
- }
- case 58: {
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder subBuilder = null;
- if (((bitField0_ & 0x00000040) == 0x00000040)) {
- subBuilder = avatar_.toBuilder();
- }
- avatar_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Avatar.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(avatar_);
- avatar_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000040;
- break;
- }
- case 66: {
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder subBuilder = null;
- if (((bitField0_ & 0x00000080) == 0x00000080)) {
- subBuilder = sticker_.toBuilder();
- }
- sticker_ = input.readMessage(org.thoughtcrime.securesms.backup.BackupProtos.Sticker.PARSER, extensionRegistry);
- if (subBuilder != null) {
- subBuilder.mergeFrom(sticker_);
- sticker_ = subBuilder.buildPartial();
- }
- bitField0_ |= 0x00000080;
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e.getMessage()).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.class, org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.Builder.class);
- }
-
- public static com.google.protobuf.Parser PARSER =
- new com.google.protobuf.AbstractParser() {
- public BackupFrame parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new BackupFrame(input, extensionRegistry);
- }
- };
-
- @java.lang.Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- private int bitField0_;
- // optional .signal.Header header = 1;
- public static final int HEADER_FIELD_NUMBER = 1;
- private org.thoughtcrime.securesms.backup.BackupProtos.Header header_;
- /**
- * optional .signal.Header header = 1;
- */
- public boolean hasHeader() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional .signal.Header header = 1;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Header getHeader() {
- return header_;
- }
- /**
- * optional .signal.Header header = 1;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder getHeaderOrBuilder() {
- return header_;
- }
-
- // optional .signal.SqlStatement statement = 2;
- public static final int STATEMENT_FIELD_NUMBER = 2;
- private org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement statement_;
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public boolean hasStatement() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getStatement() {
- return statement_;
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder getStatementOrBuilder() {
- return statement_;
- }
-
- // optional .signal.SharedPreference preference = 3;
- public static final int PREFERENCE_FIELD_NUMBER = 3;
- private org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference preference_;
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public boolean hasPreference() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getPreference() {
- return preference_;
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder getPreferenceOrBuilder() {
- return preference_;
- }
-
- // optional .signal.Attachment attachment = 4;
- public static final int ATTACHMENT_FIELD_NUMBER = 4;
- private org.thoughtcrime.securesms.backup.BackupProtos.Attachment attachment_;
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public boolean hasAttachment() {
- return ((bitField0_ & 0x00000008) == 0x00000008);
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Attachment getAttachment() {
- return attachment_;
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder getAttachmentOrBuilder() {
- return attachment_;
- }
-
- // optional .signal.DatabaseVersion version = 5;
- public static final int VERSION_FIELD_NUMBER = 5;
- private org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion version_;
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public boolean hasVersion() {
- return ((bitField0_ & 0x00000010) == 0x00000010);
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getVersion() {
- return version_;
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder getVersionOrBuilder() {
- return version_;
- }
-
- // optional bool end = 6;
- public static final int END_FIELD_NUMBER = 6;
- private boolean end_;
- /**
- * optional bool end = 6;
- */
- public boolean hasEnd() {
- return ((bitField0_ & 0x00000020) == 0x00000020);
- }
- /**
- * optional bool end = 6;
- */
- public boolean getEnd() {
- return end_;
- }
-
- // optional .signal.Avatar avatar = 7;
- public static final int AVATAR_FIELD_NUMBER = 7;
- private org.thoughtcrime.securesms.backup.BackupProtos.Avatar avatar_;
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public boolean hasAvatar() {
- return ((bitField0_ & 0x00000040) == 0x00000040);
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Avatar getAvatar() {
- return avatar_;
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder getAvatarOrBuilder() {
- return avatar_;
- }
-
- // optional .signal.Sticker sticker = 8;
- public static final int STICKER_FIELD_NUMBER = 8;
- private org.thoughtcrime.securesms.backup.BackupProtos.Sticker sticker_;
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public boolean hasSticker() {
- return ((bitField0_ & 0x00000080) == 0x00000080);
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Sticker getSticker() {
- return sticker_;
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder getStickerOrBuilder() {
- return sticker_;
- }
-
- private void initFields() {
- header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance();
- statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance();
- preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance();
- attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance();
- version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance();
- end_ = false;
- avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance();
- sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance();
- }
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized != -1) return isInitialized == 1;
-
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- getSerializedSize();
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeMessage(1, header_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- output.writeMessage(2, statement_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeMessage(3, preference_);
- }
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
- output.writeMessage(4, attachment_);
- }
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
- output.writeMessage(5, version_);
- }
- if (((bitField0_ & 0x00000020) == 0x00000020)) {
- output.writeBool(6, end_);
- }
- if (((bitField0_ & 0x00000040) == 0x00000040)) {
- output.writeMessage(7, avatar_);
- }
- if (((bitField0_ & 0x00000080) == 0x00000080)) {
- output.writeMessage(8, sticker_);
- }
- getUnknownFields().writeTo(output);
- }
-
- private int memoizedSerializedSize = -1;
- public int getSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(1, header_);
- }
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(2, statement_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(3, preference_);
- }
- if (((bitField0_ & 0x00000008) == 0x00000008)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(4, attachment_);
- }
- if (((bitField0_ & 0x00000010) == 0x00000010)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(5, version_);
- }
- if (((bitField0_ & 0x00000020) == 0x00000020)) {
- size += com.google.protobuf.CodedOutputStream
- .computeBoolSize(6, end_);
- }
- if (((bitField0_ & 0x00000040) == 0x00000040)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(7, avatar_);
- }
- if (((bitField0_ & 0x00000080) == 0x00000080)) {
- size += com.google.protobuf.CodedOutputStream
- .computeMessageSize(8, sticker_);
- }
- size += getUnknownFields().getSerializedSize();
- memoizedSerializedSize = size;
- return size;
- }
-
- private static final long serialVersionUID = 0L;
- @java.lang.Override
- protected java.lang.Object writeReplace()
- throws java.io.ObjectStreamException {
- return super.writeReplace();
- }
-
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseDelimitedFrom(input, extensionRegistry);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return PARSER.parseFrom(input);
- }
- public static org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return PARSER.parseFrom(input, extensionRegistry);
- }
-
- public static Builder newBuilder() { return Builder.create(); }
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder(org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame prototype) {
- return newBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() { return newBuilder(this); }
-
- @java.lang.Override
- protected Builder newBuilderForType(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code signal.BackupFrame}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessage.Builder
- implements org.thoughtcrime.securesms.backup.BackupProtos.BackupFrameOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_descriptor;
- }
-
- protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internalGetFieldAccessorTable() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.class, org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.Builder.class);
- }
-
- // Construct using org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- com.google.protobuf.GeneratedMessage.BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
- getHeaderFieldBuilder();
- getStatementFieldBuilder();
- getPreferenceFieldBuilder();
- getAttachmentFieldBuilder();
- getVersionFieldBuilder();
- getAvatarFieldBuilder();
- getStickerFieldBuilder();
- }
- }
- private static Builder create() {
- return new Builder();
- }
-
- public Builder clear() {
- super.clear();
- if (headerBuilder_ == null) {
- header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance();
- } else {
- headerBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000001);
- if (statementBuilder_ == null) {
- statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance();
- } else {
- statementBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000002);
- if (preferenceBuilder_ == null) {
- preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance();
- } else {
- preferenceBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000004);
- if (attachmentBuilder_ == null) {
- attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance();
- } else {
- attachmentBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000008);
- if (versionBuilder_ == null) {
- version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance();
- } else {
- versionBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000010);
- end_ = false;
- bitField0_ = (bitField0_ & ~0x00000020);
- if (avatarBuilder_ == null) {
- avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance();
- } else {
- avatarBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000040);
- if (stickerBuilder_ == null) {
- sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance();
- } else {
- stickerBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000080);
- return this;
- }
-
- public Builder clone() {
- return create().mergeFrom(buildPartial());
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.internal_static_signal_BackupFrame_descriptor;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame getDefaultInstanceForType() {
- return org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.getDefaultInstance();
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame build() {
- org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame buildPartial() {
- org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame result = new org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- if (headerBuilder_ == null) {
- result.header_ = header_;
- } else {
- result.header_ = headerBuilder_.build();
- }
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- if (statementBuilder_ == null) {
- result.statement_ = statement_;
- } else {
- result.statement_ = statementBuilder_.build();
- }
- if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
- to_bitField0_ |= 0x00000004;
- }
- if (preferenceBuilder_ == null) {
- result.preference_ = preference_;
- } else {
- result.preference_ = preferenceBuilder_.build();
- }
- if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
- to_bitField0_ |= 0x00000008;
- }
- if (attachmentBuilder_ == null) {
- result.attachment_ = attachment_;
- } else {
- result.attachment_ = attachmentBuilder_.build();
- }
- if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
- to_bitField0_ |= 0x00000010;
- }
- if (versionBuilder_ == null) {
- result.version_ = version_;
- } else {
- result.version_ = versionBuilder_.build();
- }
- if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
- to_bitField0_ |= 0x00000020;
- }
- result.end_ = end_;
- if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
- to_bitField0_ |= 0x00000040;
- }
- if (avatarBuilder_ == null) {
- result.avatar_ = avatar_;
- } else {
- result.avatar_ = avatarBuilder_.build();
- }
- if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
- to_bitField0_ |= 0x00000080;
- }
- if (stickerBuilder_ == null) {
- result.sticker_ = sticker_;
- } else {
- result.sticker_ = stickerBuilder_.build();
- }
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame) {
- return mergeFrom((org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame other) {
- if (other == org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame.getDefaultInstance()) return this;
- if (other.hasHeader()) {
- mergeHeader(other.getHeader());
- }
- if (other.hasStatement()) {
- mergeStatement(other.getStatement());
- }
- if (other.hasPreference()) {
- mergePreference(other.getPreference());
- }
- if (other.hasAttachment()) {
- mergeAttachment(other.getAttachment());
- }
- if (other.hasVersion()) {
- mergeVersion(other.getVersion());
- }
- if (other.hasEnd()) {
- setEnd(other.getEnd());
- }
- if (other.hasAvatar()) {
- mergeAvatar(other.getAvatar());
- }
- if (other.hasSticker()) {
- mergeSticker(other.getSticker());
- }
- this.mergeUnknownFields(other.getUnknownFields());
- return this;
- }
-
- public final boolean isInitialized() {
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame) e.getUnfinishedMessage();
- throw e;
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- // optional .signal.Header header = 1;
- private org.thoughtcrime.securesms.backup.BackupProtos.Header header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Header, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder, org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder> headerBuilder_;
- /**
- * optional .signal.Header header = 1;
- */
- public boolean hasHeader() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * optional .signal.Header header = 1;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Header getHeader() {
- if (headerBuilder_ == null) {
- return header_;
- } else {
- return headerBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.Header header = 1;
- */
- public Builder setHeader(org.thoughtcrime.securesms.backup.BackupProtos.Header value) {
- if (headerBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- header_ = value;
- onChanged();
- } else {
- headerBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000001;
- return this;
- }
- /**
- * optional .signal.Header header = 1;
- */
- public Builder setHeader(
- org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder builderForValue) {
- if (headerBuilder_ == null) {
- header_ = builderForValue.build();
- onChanged();
- } else {
- headerBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000001;
- return this;
- }
- /**
- * optional .signal.Header header = 1;
- */
- public Builder mergeHeader(org.thoughtcrime.securesms.backup.BackupProtos.Header value) {
- if (headerBuilder_ == null) {
- if (((bitField0_ & 0x00000001) == 0x00000001) &&
- header_ != org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance()) {
- header_ =
- org.thoughtcrime.securesms.backup.BackupProtos.Header.newBuilder(header_).mergeFrom(value).buildPartial();
- } else {
- header_ = value;
- }
- onChanged();
- } else {
- headerBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000001;
- return this;
- }
- /**
- * optional .signal.Header header = 1;
- */
- public Builder clearHeader() {
- if (headerBuilder_ == null) {
- header_ = org.thoughtcrime.securesms.backup.BackupProtos.Header.getDefaultInstance();
- onChanged();
- } else {
- headerBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000001);
- return this;
- }
- /**
- * optional .signal.Header header = 1;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder getHeaderBuilder() {
- bitField0_ |= 0x00000001;
- onChanged();
- return getHeaderFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.Header header = 1;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder getHeaderOrBuilder() {
- if (headerBuilder_ != null) {
- return headerBuilder_.getMessageOrBuilder();
- } else {
- return header_;
- }
- }
- /**
- * optional .signal.Header header = 1;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Header, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder, org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder>
- getHeaderFieldBuilder() {
- if (headerBuilder_ == null) {
- headerBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Header, org.thoughtcrime.securesms.backup.BackupProtos.Header.Builder, org.thoughtcrime.securesms.backup.BackupProtos.HeaderOrBuilder>(
- header_,
- getParentForChildren(),
- isClean());
- header_ = null;
- }
- return headerBuilder_;
- }
-
- // optional .signal.SqlStatement statement = 2;
- private org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder> statementBuilder_;
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public boolean hasStatement() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement getStatement() {
- if (statementBuilder_ == null) {
- return statement_;
- } else {
- return statementBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public Builder setStatement(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement value) {
- if (statementBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- statement_ = value;
- onChanged();
- } else {
- statementBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000002;
- return this;
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public Builder setStatement(
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder builderForValue) {
- if (statementBuilder_ == null) {
- statement_ = builderForValue.build();
- onChanged();
- } else {
- statementBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000002;
- return this;
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public Builder mergeStatement(org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement value) {
- if (statementBuilder_ == null) {
- if (((bitField0_ & 0x00000002) == 0x00000002) &&
- statement_ != org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance()) {
- statement_ =
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.newBuilder(statement_).mergeFrom(value).buildPartial();
- } else {
- statement_ = value;
- }
- onChanged();
- } else {
- statementBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000002;
- return this;
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public Builder clearStatement() {
- if (statementBuilder_ == null) {
- statement_ = org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.getDefaultInstance();
- onChanged();
- } else {
- statementBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000002);
- return this;
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder getStatementBuilder() {
- bitField0_ |= 0x00000002;
- onChanged();
- return getStatementFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder getStatementOrBuilder() {
- if (statementBuilder_ != null) {
- return statementBuilder_.getMessageOrBuilder();
- } else {
- return statement_;
- }
- }
- /**
- * optional .signal.SqlStatement statement = 2;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder>
- getStatementFieldBuilder() {
- if (statementBuilder_ == null) {
- statementBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SqlStatementOrBuilder>(
- statement_,
- getParentForChildren(),
- isClean());
- statement_ = null;
- }
- return statementBuilder_;
- }
-
- // optional .signal.SharedPreference preference = 3;
- private org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder> preferenceBuilder_;
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public boolean hasPreference() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference getPreference() {
- if (preferenceBuilder_ == null) {
- return preference_;
- } else {
- return preferenceBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public Builder setPreference(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference value) {
- if (preferenceBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- preference_ = value;
- onChanged();
- } else {
- preferenceBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000004;
- return this;
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public Builder setPreference(
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder builderForValue) {
- if (preferenceBuilder_ == null) {
- preference_ = builderForValue.build();
- onChanged();
- } else {
- preferenceBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000004;
- return this;
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public Builder mergePreference(org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference value) {
- if (preferenceBuilder_ == null) {
- if (((bitField0_ & 0x00000004) == 0x00000004) &&
- preference_ != org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance()) {
- preference_ =
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.newBuilder(preference_).mergeFrom(value).buildPartial();
- } else {
- preference_ = value;
- }
- onChanged();
- } else {
- preferenceBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000004;
- return this;
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public Builder clearPreference() {
- if (preferenceBuilder_ == null) {
- preference_ = org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.getDefaultInstance();
- onChanged();
- } else {
- preferenceBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000004);
- return this;
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder getPreferenceBuilder() {
- bitField0_ |= 0x00000004;
- onChanged();
- return getPreferenceFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder getPreferenceOrBuilder() {
- if (preferenceBuilder_ != null) {
- return preferenceBuilder_.getMessageOrBuilder();
- } else {
- return preference_;
- }
- }
- /**
- * optional .signal.SharedPreference preference = 3;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder>
- getPreferenceFieldBuilder() {
- if (preferenceBuilder_ == null) {
- preferenceBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference.Builder, org.thoughtcrime.securesms.backup.BackupProtos.SharedPreferenceOrBuilder>(
- preference_,
- getParentForChildren(),
- isClean());
- preference_ = null;
- }
- return preferenceBuilder_;
- }
-
- // optional .signal.Attachment attachment = 4;
- private org.thoughtcrime.securesms.backup.BackupProtos.Attachment attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder> attachmentBuilder_;
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public boolean hasAttachment() {
- return ((bitField0_ & 0x00000008) == 0x00000008);
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Attachment getAttachment() {
- if (attachmentBuilder_ == null) {
- return attachment_;
- } else {
- return attachmentBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public Builder setAttachment(org.thoughtcrime.securesms.backup.BackupProtos.Attachment value) {
- if (attachmentBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- attachment_ = value;
- onChanged();
- } else {
- attachmentBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000008;
- return this;
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public Builder setAttachment(
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder builderForValue) {
- if (attachmentBuilder_ == null) {
- attachment_ = builderForValue.build();
- onChanged();
- } else {
- attachmentBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000008;
- return this;
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public Builder mergeAttachment(org.thoughtcrime.securesms.backup.BackupProtos.Attachment value) {
- if (attachmentBuilder_ == null) {
- if (((bitField0_ & 0x00000008) == 0x00000008) &&
- attachment_ != org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance()) {
- attachment_ =
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment.newBuilder(attachment_).mergeFrom(value).buildPartial();
- } else {
- attachment_ = value;
- }
- onChanged();
- } else {
- attachmentBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000008;
- return this;
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public Builder clearAttachment() {
- if (attachmentBuilder_ == null) {
- attachment_ = org.thoughtcrime.securesms.backup.BackupProtos.Attachment.getDefaultInstance();
- onChanged();
- } else {
- attachmentBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000008);
- return this;
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder getAttachmentBuilder() {
- bitField0_ |= 0x00000008;
- onChanged();
- return getAttachmentFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder getAttachmentOrBuilder() {
- if (attachmentBuilder_ != null) {
- return attachmentBuilder_.getMessageOrBuilder();
- } else {
- return attachment_;
- }
- }
- /**
- * optional .signal.Attachment attachment = 4;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder>
- getAttachmentFieldBuilder() {
- if (attachmentBuilder_ == null) {
- attachmentBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Attachment, org.thoughtcrime.securesms.backup.BackupProtos.Attachment.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AttachmentOrBuilder>(
- attachment_,
- getParentForChildren(),
- isClean());
- attachment_ = null;
- }
- return attachmentBuilder_;
- }
-
- // optional .signal.DatabaseVersion version = 5;
- private org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder> versionBuilder_;
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public boolean hasVersion() {
- return ((bitField0_ & 0x00000010) == 0x00000010);
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion getVersion() {
- if (versionBuilder_ == null) {
- return version_;
- } else {
- return versionBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public Builder setVersion(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion value) {
- if (versionBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- version_ = value;
- onChanged();
- } else {
- versionBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000010;
- return this;
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public Builder setVersion(
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder builderForValue) {
- if (versionBuilder_ == null) {
- version_ = builderForValue.build();
- onChanged();
- } else {
- versionBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000010;
- return this;
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public Builder mergeVersion(org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion value) {
- if (versionBuilder_ == null) {
- if (((bitField0_ & 0x00000010) == 0x00000010) &&
- version_ != org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance()) {
- version_ =
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.newBuilder(version_).mergeFrom(value).buildPartial();
- } else {
- version_ = value;
- }
- onChanged();
- } else {
- versionBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000010;
- return this;
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public Builder clearVersion() {
- if (versionBuilder_ == null) {
- version_ = org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.getDefaultInstance();
- onChanged();
- } else {
- versionBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000010);
- return this;
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder getVersionBuilder() {
- bitField0_ |= 0x00000010;
- onChanged();
- return getVersionFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder getVersionOrBuilder() {
- if (versionBuilder_ != null) {
- return versionBuilder_.getMessageOrBuilder();
- } else {
- return version_;
- }
- }
- /**
- * optional .signal.DatabaseVersion version = 5;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder>
- getVersionFieldBuilder() {
- if (versionBuilder_ == null) {
- versionBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion.Builder, org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersionOrBuilder>(
- version_,
- getParentForChildren(),
- isClean());
- version_ = null;
- }
- return versionBuilder_;
- }
-
- // optional bool end = 6;
- private boolean end_ ;
- /**
- * optional bool end = 6;
- */
- public boolean hasEnd() {
- return ((bitField0_ & 0x00000020) == 0x00000020);
- }
- /**
- * optional bool end = 6;
- */
- public boolean getEnd() {
- return end_;
- }
- /**
- * optional bool end = 6;
- */
- public Builder setEnd(boolean value) {
- bitField0_ |= 0x00000020;
- end_ = value;
- onChanged();
- return this;
- }
- /**
- * optional bool end = 6;
- */
- public Builder clearEnd() {
- bitField0_ = (bitField0_ & ~0x00000020);
- end_ = false;
- onChanged();
- return this;
- }
-
- // optional .signal.Avatar avatar = 7;
- private org.thoughtcrime.securesms.backup.BackupProtos.Avatar avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder> avatarBuilder_;
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public boolean hasAvatar() {
- return ((bitField0_ & 0x00000040) == 0x00000040);
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Avatar getAvatar() {
- if (avatarBuilder_ == null) {
- return avatar_;
- } else {
- return avatarBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public Builder setAvatar(org.thoughtcrime.securesms.backup.BackupProtos.Avatar value) {
- if (avatarBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- avatar_ = value;
- onChanged();
- } else {
- avatarBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000040;
- return this;
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public Builder setAvatar(
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder builderForValue) {
- if (avatarBuilder_ == null) {
- avatar_ = builderForValue.build();
- onChanged();
- } else {
- avatarBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000040;
- return this;
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public Builder mergeAvatar(org.thoughtcrime.securesms.backup.BackupProtos.Avatar value) {
- if (avatarBuilder_ == null) {
- if (((bitField0_ & 0x00000040) == 0x00000040) &&
- avatar_ != org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance()) {
- avatar_ =
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar.newBuilder(avatar_).mergeFrom(value).buildPartial();
- } else {
- avatar_ = value;
- }
- onChanged();
- } else {
- avatarBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000040;
- return this;
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public Builder clearAvatar() {
- if (avatarBuilder_ == null) {
- avatar_ = org.thoughtcrime.securesms.backup.BackupProtos.Avatar.getDefaultInstance();
- onChanged();
- } else {
- avatarBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000040);
- return this;
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder getAvatarBuilder() {
- bitField0_ |= 0x00000040;
- onChanged();
- return getAvatarFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder getAvatarOrBuilder() {
- if (avatarBuilder_ != null) {
- return avatarBuilder_.getMessageOrBuilder();
- } else {
- return avatar_;
- }
- }
- /**
- * optional .signal.Avatar avatar = 7;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder>
- getAvatarFieldBuilder() {
- if (avatarBuilder_ == null) {
- avatarBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Avatar, org.thoughtcrime.securesms.backup.BackupProtos.Avatar.Builder, org.thoughtcrime.securesms.backup.BackupProtos.AvatarOrBuilder>(
- avatar_,
- getParentForChildren(),
- isClean());
- avatar_ = null;
- }
- return avatarBuilder_;
- }
-
- // optional .signal.Sticker sticker = 8;
- private org.thoughtcrime.securesms.backup.BackupProtos.Sticker sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance();
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder, org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder> stickerBuilder_;
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public boolean hasSticker() {
- return ((bitField0_ & 0x00000080) == 0x00000080);
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Sticker getSticker() {
- if (stickerBuilder_ == null) {
- return sticker_;
- } else {
- return stickerBuilder_.getMessage();
- }
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public Builder setSticker(org.thoughtcrime.securesms.backup.BackupProtos.Sticker value) {
- if (stickerBuilder_ == null) {
- if (value == null) {
- throw new NullPointerException();
- }
- sticker_ = value;
- onChanged();
- } else {
- stickerBuilder_.setMessage(value);
- }
- bitField0_ |= 0x00000080;
- return this;
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public Builder setSticker(
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder builderForValue) {
- if (stickerBuilder_ == null) {
- sticker_ = builderForValue.build();
- onChanged();
- } else {
- stickerBuilder_.setMessage(builderForValue.build());
- }
- bitField0_ |= 0x00000080;
- return this;
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public Builder mergeSticker(org.thoughtcrime.securesms.backup.BackupProtos.Sticker value) {
- if (stickerBuilder_ == null) {
- if (((bitField0_ & 0x00000080) == 0x00000080) &&
- sticker_ != org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance()) {
- sticker_ =
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker.newBuilder(sticker_).mergeFrom(value).buildPartial();
- } else {
- sticker_ = value;
- }
- onChanged();
- } else {
- stickerBuilder_.mergeFrom(value);
- }
- bitField0_ |= 0x00000080;
- return this;
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public Builder clearSticker() {
- if (stickerBuilder_ == null) {
- sticker_ = org.thoughtcrime.securesms.backup.BackupProtos.Sticker.getDefaultInstance();
- onChanged();
- } else {
- stickerBuilder_.clear();
- }
- bitField0_ = (bitField0_ & ~0x00000080);
- return this;
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder getStickerBuilder() {
- bitField0_ |= 0x00000080;
- onChanged();
- return getStickerFieldBuilder().getBuilder();
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- public org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder getStickerOrBuilder() {
- if (stickerBuilder_ != null) {
- return stickerBuilder_.getMessageOrBuilder();
- } else {
- return sticker_;
- }
- }
- /**
- * optional .signal.Sticker sticker = 8;
- */
- private com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder, org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder>
- getStickerFieldBuilder() {
- if (stickerBuilder_ == null) {
- stickerBuilder_ = new com.google.protobuf.SingleFieldBuilder<
- org.thoughtcrime.securesms.backup.BackupProtos.Sticker, org.thoughtcrime.securesms.backup.BackupProtos.Sticker.Builder, org.thoughtcrime.securesms.backup.BackupProtos.StickerOrBuilder>(
- sticker_,
- getParentForChildren(),
- isClean());
- sticker_ = null;
- }
- return stickerBuilder_;
- }
-
- // @@protoc_insertion_point(builder_scope:signal.BackupFrame)
- }
-
- static {
- defaultInstance = new BackupFrame(true);
- defaultInstance.initFields();
- }
-
- // @@protoc_insertion_point(class_scope:signal.BackupFrame)
- }
-
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_SqlStatement_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_SqlStatement_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_SqlStatement_SqlParameter_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_SharedPreference_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_SharedPreference_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_Attachment_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_Attachment_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_Sticker_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_Sticker_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_Avatar_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_Avatar_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_DatabaseVersion_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_DatabaseVersion_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_Header_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_Header_fieldAccessorTable;
- private static com.google.protobuf.Descriptors.Descriptor
- internal_static_signal_BackupFrame_descriptor;
- private static
- com.google.protobuf.GeneratedMessage.FieldAccessorTable
- internal_static_signal_BackupFrame_fieldAccessorTable;
-
- public static com.google.protobuf.Descriptors.FileDescriptor
- getDescriptor() {
- return descriptor;
- }
- private static com.google.protobuf.Descriptors.FileDescriptor
- descriptor;
- static {
- java.lang.String[] descriptorData = {
- "\n\rBackups.proto\022\006signal\"\342\001\n\014SqlStatement" +
- "\022\021\n\tstatement\030\001 \001(\t\0225\n\nparameters\030\002 \003(\0132" +
- "!.signal.SqlStatement.SqlParameter\032\207\001\n\014S" +
- "qlParameter\022\026\n\016stringParamter\030\001 \001(\t\022\030\n\020i" +
- "ntegerParameter\030\002 \001(\004\022\027\n\017doubleParameter" +
- "\030\003 \001(\001\022\025\n\rblobParameter\030\004 \001(\014\022\025\n\rnullpar" +
- "ameter\030\005 \001(\010\"<\n\020SharedPreference\022\014\n\004file" +
- "\030\001 \001(\t\022\013\n\003key\030\002 \001(\t\022\r\n\005value\030\003 \001(\t\"A\n\nAt" +
- "tachment\022\r\n\005rowId\030\001 \001(\004\022\024\n\014attachmentId\030" +
- "\002 \001(\004\022\016\n\006length\030\003 \001(\r\"(\n\007Sticker\022\r\n\005rowI",
- "d\030\001 \001(\004\022\016\n\006length\030\002 \001(\r\"&\n\006Avatar\022\014\n\004nam" +
- "e\030\001 \001(\t\022\016\n\006length\030\002 \001(\r\"\"\n\017DatabaseVersi" +
- "on\022\017\n\007version\030\001 \001(\r\"\"\n\006Header\022\n\n\002iv\030\001 \001(" +
- "\014\022\014\n\004salt\030\002 \001(\014\"\245\002\n\013BackupFrame\022\036\n\006heade" +
- "r\030\001 \001(\0132\016.signal.Header\022\'\n\tstatement\030\002 \001" +
- "(\0132\024.signal.SqlStatement\022,\n\npreference\030\003" +
- " \001(\0132\030.signal.SharedPreference\022&\n\nattach" +
- "ment\030\004 \001(\0132\022.signal.Attachment\022(\n\007versio" +
- "n\030\005 \001(\0132\027.signal.DatabaseVersion\022\013\n\003end\030" +
- "\006 \001(\010\022\036\n\006avatar\030\007 \001(\0132\016.signal.Avatar\022 \n",
- "\007sticker\030\010 \001(\0132\017.signal.StickerB1\n!org.t" +
- "houghtcrime.securesms.backupB\014BackupProt" +
- "os"
- };
- com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
- new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
- public com.google.protobuf.ExtensionRegistry assignDescriptors(
- com.google.protobuf.Descriptors.FileDescriptor root) {
- descriptor = root;
- internal_static_signal_SqlStatement_descriptor =
- getDescriptor().getMessageTypes().get(0);
- internal_static_signal_SqlStatement_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_SqlStatement_descriptor,
- new java.lang.String[] { "Statement", "Parameters", });
- internal_static_signal_SqlStatement_SqlParameter_descriptor =
- internal_static_signal_SqlStatement_descriptor.getNestedTypes().get(0);
- internal_static_signal_SqlStatement_SqlParameter_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_SqlStatement_SqlParameter_descriptor,
- new java.lang.String[] { "StringParamter", "IntegerParameter", "DoubleParameter", "BlobParameter", "Nullparameter", });
- internal_static_signal_SharedPreference_descriptor =
- getDescriptor().getMessageTypes().get(1);
- internal_static_signal_SharedPreference_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_SharedPreference_descriptor,
- new java.lang.String[] { "File", "Key", "Value", });
- internal_static_signal_Attachment_descriptor =
- getDescriptor().getMessageTypes().get(2);
- internal_static_signal_Attachment_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_Attachment_descriptor,
- new java.lang.String[] { "RowId", "AttachmentId", "Length", });
- internal_static_signal_Sticker_descriptor =
- getDescriptor().getMessageTypes().get(3);
- internal_static_signal_Sticker_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_Sticker_descriptor,
- new java.lang.String[] { "RowId", "Length", });
- internal_static_signal_Avatar_descriptor =
- getDescriptor().getMessageTypes().get(4);
- internal_static_signal_Avatar_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_Avatar_descriptor,
- new java.lang.String[] { "Name", "Length", });
- internal_static_signal_DatabaseVersion_descriptor =
- getDescriptor().getMessageTypes().get(5);
- internal_static_signal_DatabaseVersion_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_DatabaseVersion_descriptor,
- new java.lang.String[] { "Version", });
- internal_static_signal_Header_descriptor =
- getDescriptor().getMessageTypes().get(6);
- internal_static_signal_Header_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_Header_descriptor,
- new java.lang.String[] { "Iv", "Salt", });
- internal_static_signal_BackupFrame_descriptor =
- getDescriptor().getMessageTypes().get(7);
- internal_static_signal_BackupFrame_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessage.FieldAccessorTable(
- internal_static_signal_BackupFrame_descriptor,
- new java.lang.String[] { "Header", "Statement", "Preference", "Attachment", "Version", "End", "Avatar", "Sticker", });
- return null;
- }
- };
- com.google.protobuf.Descriptors.FileDescriptor
- .internalBuildGeneratedFileFrom(descriptorData,
- new com.google.protobuf.Descriptors.FileDescriptor[] {
- }, assigner);
- }
-
- // @@protoc_insertion_point(outer_class_scope)
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt
deleted file mode 100644
index 33b8b67258..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.kt
+++ /dev/null
@@ -1,447 +0,0 @@
-package org.thoughtcrime.securesms.backup
-
-import android.content.Context
-import android.database.Cursor
-import android.net.Uri
-import android.text.TextUtils
-import androidx.annotation.WorkerThread
-import com.annimon.stream.function.Consumer
-import com.annimon.stream.function.Predicate
-import com.google.protobuf.ByteString
-import net.sqlcipher.database.SQLiteDatabase
-import org.greenrobot.eventbus.EventBus
-import org.session.libsession.avatars.AvatarHelper
-import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
-import org.session.libsession.utilities.Conversions
-import org.session.libsession.utilities.Util
-import org.session.libsignal.crypto.kdf.HKDFv3
-import org.session.libsignal.utilities.ByteUtil
-import org.session.libsignal.utilities.Log
-import org.thoughtcrime.securesms.backup.BackupProtos.Attachment
-import org.thoughtcrime.securesms.backup.BackupProtos.Avatar
-import org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame
-import org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion
-import org.thoughtcrime.securesms.backup.BackupProtos.Header
-import org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference
-import org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement
-import org.thoughtcrime.securesms.backup.BackupProtos.Sticker
-import org.thoughtcrime.securesms.crypto.AttachmentSecret
-import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream
-import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream
-import org.thoughtcrime.securesms.database.AttachmentDatabase
-import org.thoughtcrime.securesms.database.GroupReceiptDatabase
-import org.thoughtcrime.securesms.database.JobDatabase
-import org.thoughtcrime.securesms.database.LokiAPIDatabase
-import org.thoughtcrime.securesms.database.LokiBackupFilesDatabase
-import org.thoughtcrime.securesms.database.MmsDatabase
-import org.thoughtcrime.securesms.database.MmsSmsColumns
-import org.thoughtcrime.securesms.database.PushDatabase
-import org.thoughtcrime.securesms.database.SearchDatabase
-import org.thoughtcrime.securesms.database.SmsDatabase
-import org.thoughtcrime.securesms.util.BackupUtil
-import java.io.Closeable
-import java.io.File
-import java.io.FileInputStream
-import java.io.Flushable
-import java.io.IOException
-import java.io.InputStream
-import java.io.OutputStream
-import java.security.InvalidAlgorithmParameterException
-import java.security.InvalidKeyException
-import java.security.NoSuchAlgorithmException
-import java.util.LinkedList
-import javax.crypto.BadPaddingException
-import javax.crypto.Cipher
-import javax.crypto.IllegalBlockSizeException
-import javax.crypto.Mac
-import javax.crypto.NoSuchPaddingException
-import javax.crypto.spec.IvParameterSpec
-import javax.crypto.spec.SecretKeySpec
-
-object FullBackupExporter {
- private val TAG = FullBackupExporter::class.java.simpleName
-
- @JvmStatic
- @WorkerThread
- @Throws(IOException::class)
- fun export(context: Context,
- attachmentSecret: AttachmentSecret,
- input: SQLiteDatabase,
- fileUri: Uri,
- passphrase: String) {
-
- val baseOutputStream = context.contentResolver.openOutputStream(fileUri)
- ?: throw IOException("Cannot open an output stream for the file URI: $fileUri")
-
- var count = 0
- try {
- BackupFrameOutputStream(baseOutputStream, passphrase).use { outputStream ->
- outputStream.writeDatabaseVersion(input.version)
- val tables = exportSchema(input, outputStream)
- for (table in tables) if (shouldExportTable(table)) {
- count = when (table) {
- SmsDatabase.TABLE_NAME, MmsDatabase.TABLE_NAME -> {
- exportTable(table, input, outputStream,
- { cursor: Cursor ->
- cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0
- },
- null,
- count)
- }
- GroupReceiptDatabase.TABLE_NAME -> {
- exportTable(table, input, outputStream,
- { cursor: Cursor ->
- isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID)))
- },
- null,
- count)
- }
- AttachmentDatabase.TABLE_NAME -> {
- exportTable(table, input, outputStream,
- { cursor: Cursor ->
- isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID)))
- },
- { cursor: Cursor ->
- exportAttachment(attachmentSecret, cursor, outputStream)
- },
- count)
- }
- else -> {
- exportTable(table, input, outputStream, null, null, count)
- }
- }
- }
- for (preference in BackupUtil.getBackupRecords(context)) {
- EventBus.getDefault().post(BackupEvent.createProgress(++count))
- outputStream.writePreferenceEntry(preference)
- }
- for (preference in BackupPreferences.getBackupRecords(context)) {
- EventBus.getDefault().post(BackupEvent.createProgress(++count))
- outputStream.writePreferenceEntry(preference)
- }
- for (avatar in AvatarHelper.getAvatarFiles(context)) {
- EventBus.getDefault().post(BackupEvent.createProgress(++count))
- outputStream.writeAvatar(avatar.name, FileInputStream(avatar), avatar.length())
- }
- outputStream.writeEnd()
- }
- EventBus.getDefault().post(BackupEvent.createFinished())
- } catch (e: Exception) {
- Log.e(TAG, "Failed to make full backup.", e)
- EventBus.getDefault().post(BackupEvent.createFinished(e))
- throw e
- }
- }
-
- private inline fun shouldExportTable(table: String): Boolean {
- return table != PushDatabase.TABLE_NAME &&
-
- table != LokiBackupFilesDatabase.TABLE_NAME &&
- table != LokiAPIDatabase.openGroupProfilePictureTable &&
-
- table != JobDatabase.Jobs.TABLE_NAME &&
- table != JobDatabase.Constraints.TABLE_NAME &&
- table != JobDatabase.Dependencies.TABLE_NAME &&
-
- !table.startsWith(SearchDatabase.SMS_FTS_TABLE_NAME) &&
- !table.startsWith(SearchDatabase.MMS_FTS_TABLE_NAME) &&
- !table.startsWith("sqlite_")
- }
-
- @Throws(IOException::class)
- private fun exportSchema(input: SQLiteDatabase, outputStream: BackupFrameOutputStream): List {
- val tables: MutableList = LinkedList()
- input.rawQuery("SELECT sql, name, type FROM sqlite_master", null).use { cursor ->
- while (cursor != null && cursor.moveToNext()) {
- val sql = cursor.getString(0)
- val name = cursor.getString(1)
- val type = cursor.getString(2)
- if (sql != null) {
- val isSmsFtsSecretTable = name != null && name != SearchDatabase.SMS_FTS_TABLE_NAME && name.startsWith(SearchDatabase.SMS_FTS_TABLE_NAME)
- val isMmsFtsSecretTable = name != null && name != SearchDatabase.MMS_FTS_TABLE_NAME && name.startsWith(SearchDatabase.MMS_FTS_TABLE_NAME)
- if (!isSmsFtsSecretTable && !isMmsFtsSecretTable) {
- if ("table" == type) {
- tables.add(name)
- }
- outputStream.writeSql(SqlStatement.newBuilder().setStatement(cursor.getString(0)).build())
- }
- }
- }
- }
- return tables
- }
-
- @Throws(IOException::class)
- private fun exportTable(table: String,
- input: SQLiteDatabase,
- outputStream: BackupFrameOutputStream,
- predicate: Predicate?,
- postProcess: Consumer?,
- count: Int): Int {
- var count = count
- val template = "INSERT INTO $table VALUES "
- input.rawQuery("SELECT * FROM $table", null).use { cursor ->
- while (cursor != null && cursor.moveToNext()) {
- EventBus.getDefault().post(BackupEvent.createProgress(++count))
- if (predicate != null && !predicate.test(cursor)) continue
-
- val statement = StringBuilder(template)
- val statementBuilder = SqlStatement.newBuilder()
- statement.append('(')
- for (i in 0 until cursor.columnCount) {
- statement.append('?')
- when (cursor.getType(i)) {
- Cursor.FIELD_TYPE_STRING -> {
- statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder()
- .setStringParamter(cursor.getString(i)))
- }
- Cursor.FIELD_TYPE_FLOAT -> {
- statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder()
- .setDoubleParameter(cursor.getDouble(i)))
- }
- Cursor.FIELD_TYPE_INTEGER -> {
- statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder()
- .setIntegerParameter(cursor.getLong(i)))
- }
- Cursor.FIELD_TYPE_BLOB -> {
- statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder()
- .setBlobParameter(ByteString.copyFrom(cursor.getBlob(i))))
- }
- Cursor.FIELD_TYPE_NULL -> {
- statementBuilder.addParameters(SqlStatement.SqlParameter.newBuilder()
- .setNullparameter(true))
- }
- else -> {
- throw AssertionError("unknown type?" + cursor.getType(i))
- }
- }
- if (i < cursor.columnCount - 1) {
- statement.append(',')
- }
- }
- statement.append(')')
- outputStream.writeSql(statementBuilder.setStatement(statement.toString()).build())
- postProcess?.accept(cursor)
- }
- }
- return count
- }
-
- private fun exportAttachment(attachmentSecret: AttachmentSecret, cursor: Cursor, outputStream: BackupFrameOutputStream) {
- try {
- val rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID))
- val uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID))
- var size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.SIZE))
- val data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA))
- val random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM))
- if (!TextUtils.isEmpty(data) && size <= 0) {
- size = calculateVeryOldStreamLength(attachmentSecret, random, data)
- }
- if (!TextUtils.isEmpty(data) && size > 0) {
- val inputStream: InputStream = if (random != null && random.size == 32) {
- ModernDecryptingPartInputStream.createFor(attachmentSecret, random, File(data), 0)
- } else {
- ClassicDecryptingPartInputStream.createFor(attachmentSecret, File(data))
- }
- outputStream.writeAttachment(AttachmentId(rowId, uniqueId), inputStream, size)
- }
- } catch (e: IOException) {
- Log.w(TAG, e)
- }
- }
-
- @Throws(IOException::class)
- private fun calculateVeryOldStreamLength(attachmentSecret: AttachmentSecret, random: ByteArray?, data: String): Long {
- var result: Long = 0
- val inputStream: InputStream = if (random != null && random.size == 32) {
- ModernDecryptingPartInputStream.createFor(attachmentSecret, random, File(data), 0)
- } else {
- ClassicDecryptingPartInputStream.createFor(attachmentSecret, File(data))
- }
- var read: Int
- val buffer = ByteArray(8192)
- while (inputStream.read(buffer, 0, buffer.size).also { read = it } != -1) {
- result += read.toLong()
- }
- return result
- }
-
- private fun isForNonExpiringMessage(db: SQLiteDatabase, mmsId: Long): Boolean {
- val columns = arrayOf(MmsSmsColumns.EXPIRES_IN)
- val where = MmsSmsColumns.ID + " = ?"
- val args = arrayOf(mmsId.toString())
- db.query(MmsDatabase.TABLE_NAME, columns, where, args, null, null, null).use { mmsCursor ->
- if (mmsCursor != null && mmsCursor.moveToFirst()) {
- return mmsCursor.getLong(0) == 0L
- }
- }
- return false
- }
-
- private class BackupFrameOutputStream : Closeable, Flushable {
-
- private val outputStream: OutputStream
- private var cipher: Cipher
- private var mac: Mac
- private val cipherKey: ByteArray
- private val macKey: ByteArray
- private val iv: ByteArray
-
- private var counter: Int = 0
-
- constructor(outputStream: OutputStream, passphrase: String) : super() {
- try {
- val salt = Util.getSecretBytes(32)
- val key = BackupUtil.computeBackupKey(passphrase, salt)
- val derived = HKDFv3().deriveSecrets(key, "Backup Export".toByteArray(), 64)
- val split = ByteUtil.split(derived, 32, 32)
- cipherKey = split[0]
- macKey = split[1]
- cipher = Cipher.getInstance("AES/CTR/NoPadding")
- mac = Mac.getInstance("HmacSHA256")
- this.outputStream = outputStream
- iv = Util.getSecretBytes(16)
- counter = Conversions.byteArrayToInt(iv)
- mac.init(SecretKeySpec(macKey, "HmacSHA256"))
- val header = BackupFrame.newBuilder().setHeader(Header.newBuilder()
- .setIv(ByteString.copyFrom(iv))
- .setSalt(ByteString.copyFrom(salt)))
- .build().toByteArray()
- outputStream.write(Conversions.intToByteArray(header.size))
- outputStream.write(header)
- } catch (e: Exception) {
- when (e) {
- is NoSuchAlgorithmException,
- is NoSuchPaddingException,
- is InvalidKeyException -> {
- throw AssertionError(e)
- }
- else -> throw e
- }
- }
- }
-
- @Throws(IOException::class)
- fun writeSql(statement: SqlStatement) {
- write(outputStream, BackupFrame.newBuilder().setStatement(statement).build())
- }
-
- @Throws(IOException::class)
- fun writePreferenceEntry(preference: SharedPreference?) {
- write(outputStream, BackupFrame.newBuilder().setPreference(preference).build())
- }
-
- @Throws(IOException::class)
- fun writeAvatar(avatarName: String, inputStream: InputStream, size: Long) {
- write(outputStream, BackupFrame.newBuilder()
- .setAvatar(Avatar.newBuilder()
- .setName(avatarName)
- .setLength(Util.toIntExact(size))
- .build())
- .build())
- writeStream(inputStream)
- }
-
- @Throws(IOException::class)
- fun writeAttachment(attachmentId: AttachmentId, inputStream: InputStream, size: Long) {
- write(outputStream, BackupFrame.newBuilder()
- .setAttachment(Attachment.newBuilder()
- .setRowId(attachmentId.rowId)
- .setAttachmentId(attachmentId.uniqueId)
- .setLength(Util.toIntExact(size))
- .build())
- .build())
- writeStream(inputStream)
- }
-
- @Throws(IOException::class)
- fun writeSticker(rowId: Long, inputStream: InputStream, size: Long) {
- write(outputStream, BackupFrame.newBuilder()
- .setSticker(Sticker.newBuilder()
- .setRowId(rowId)
- .setLength(Util.toIntExact(size))
- .build())
- .build())
- writeStream(inputStream)
- }
-
- @Throws(IOException::class)
- fun writeDatabaseVersion(version: Int) {
- write(outputStream, BackupFrame.newBuilder()
- .setVersion(DatabaseVersion.newBuilder().setVersion(version))
- .build())
- }
-
- @Throws(IOException::class)
- fun writeEnd() {
- write(outputStream, BackupFrame.newBuilder().setEnd(true).build())
- }
-
- @Throws(IOException::class)
- private fun writeStream(inputStream: InputStream) {
- try {
- Conversions.intToByteArray(iv, 0, counter++)
- cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
- mac.update(iv)
- val buffer = ByteArray(8192)
- var read: Int
- while (inputStream.read(buffer).also { read = it } != -1) {
- val ciphertext = cipher.update(buffer, 0, read)
- if (ciphertext != null) {
- outputStream.write(ciphertext)
- mac.update(ciphertext)
- }
- }
- val remainder = cipher.doFinal()
- outputStream.write(remainder)
- mac.update(remainder)
- val attachmentDigest = mac.doFinal()
- outputStream.write(attachmentDigest, 0, 10)
- } catch (e: Exception) {
- when (e) {
- is InvalidKeyException,
- is InvalidAlgorithmParameterException,
- is IllegalBlockSizeException,
- is BadPaddingException -> {
- throw AssertionError(e)
- }
- else -> throw e
- }
- }
- }
-
- @Throws(IOException::class)
- private fun write(out: OutputStream, frame: BackupFrame) {
- try {
- Conversions.intToByteArray(iv, 0, counter++)
- cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
- val frameCiphertext = cipher.doFinal(frame.toByteArray())
- val frameMac = mac.doFinal(frameCiphertext)
- val length = Conversions.intToByteArray(frameCiphertext.size + 10)
- out.write(length)
- out.write(frameCiphertext)
- out.write(frameMac, 0, 10)
- } catch (e: Exception) {
- when (e) {
- is InvalidKeyException,
- is InvalidAlgorithmParameterException,
- is IllegalBlockSizeException,
- is BadPaddingException -> {
- throw AssertionError(e)
- }
- else -> throw e
- }
- }
- }
-
- @Throws(IOException::class)
- override fun flush() {
- outputStream.flush()
- }
-
- @Throws(IOException::class)
- override fun close() {
- outputStream.close()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt
deleted file mode 100644
index ba1df97d56..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupImporter.kt
+++ /dev/null
@@ -1,352 +0,0 @@
-package org.thoughtcrime.securesms.backup
-
-import android.annotation.SuppressLint
-import android.content.ContentValues
-import android.content.Context
-import android.net.Uri
-import androidx.annotation.WorkerThread
-import net.sqlcipher.database.SQLiteDatabase
-import org.greenrobot.eventbus.EventBus
-import org.session.libsession.avatars.AvatarHelper
-import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
-import org.session.libsession.utilities.Address
-import org.session.libsession.utilities.Conversions
-import org.session.libsession.utilities.Util
-import org.session.libsignal.crypto.kdf.HKDFv3
-import org.session.libsignal.utilities.ByteUtil
-import org.session.libsignal.utilities.Log
-import org.thoughtcrime.securesms.backup.BackupProtos.Attachment
-import org.thoughtcrime.securesms.backup.BackupProtos.Avatar
-import org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame
-import org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion
-import org.thoughtcrime.securesms.backup.BackupProtos.SharedPreference
-import org.thoughtcrime.securesms.backup.BackupProtos.SqlStatement
-import org.thoughtcrime.securesms.crypto.AttachmentSecret
-import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream
-import org.thoughtcrime.securesms.database.AttachmentDatabase
-import org.thoughtcrime.securesms.database.GroupReceiptDatabase
-import org.thoughtcrime.securesms.database.MmsDatabase
-import org.thoughtcrime.securesms.database.MmsSmsColumns
-import org.thoughtcrime.securesms.database.SearchDatabase
-import org.thoughtcrime.securesms.database.ThreadDatabase
-import org.thoughtcrime.securesms.dependencies.DatabaseComponent
-import org.thoughtcrime.securesms.util.BackupUtil
-import java.io.Closeable
-import java.io.File
-import java.io.FileOutputStream
-import java.io.IOException
-import java.io.InputStream
-import java.io.OutputStream
-import java.security.InvalidAlgorithmParameterException
-import java.security.InvalidKeyException
-import java.security.MessageDigest
-import java.security.NoSuchAlgorithmException
-import java.util.LinkedList
-import java.util.Locale
-import javax.crypto.BadPaddingException
-import javax.crypto.Cipher
-import javax.crypto.IllegalBlockSizeException
-import javax.crypto.Mac
-import javax.crypto.NoSuchPaddingException
-import javax.crypto.spec.IvParameterSpec
-import javax.crypto.spec.SecretKeySpec
-
-object FullBackupImporter {
- /**
- * Because BackupProtos.SharedPreference was made only to serialize string values,
- * we use these 3-char prefixes to explicitly cast the values before inserting to a preference file.
- */
- const val PREF_PREFIX_TYPE_INT = "i__"
- const val PREF_PREFIX_TYPE_BOOLEAN = "b__"
-
- private val TAG = FullBackupImporter::class.java.simpleName
-
- @JvmStatic
- @WorkerThread
- @Throws(IOException::class)
- fun importFromUri(context: Context,
- attachmentSecret: AttachmentSecret,
- db: SQLiteDatabase,
- fileUri: Uri,
- passphrase: String) {
-
- val baseInputStream = context.contentResolver.openInputStream(fileUri)
- ?: throw IOException("Cannot open an input stream for the file URI: $fileUri")
-
- var count = 0
- try {
- BackupRecordInputStream(baseInputStream, passphrase).use { inputStream ->
- db.beginTransaction()
- dropAllTables(db)
- var frame: BackupFrame
- while (!inputStream.readFrame().also { frame = it }.end) {
- if (count++ % 100 == 0) EventBus.getDefault().post(BackupEvent.createProgress(count))
- when {
- frame.hasVersion() -> processVersion(db, frame.version)
- frame.hasStatement() -> processStatement(db, frame.statement)
- frame.hasPreference() -> processPreference(context, frame.preference)
- frame.hasAttachment() -> processAttachment(context, attachmentSecret, db, frame.attachment, inputStream)
- frame.hasAvatar() -> processAvatar(context, frame.avatar, inputStream)
- }
- }
- trimEntriesForExpiredMessages(context, db)
- db.setTransactionSuccessful()
- }
- } finally {
- if (db.inTransaction()) {
- db.endTransaction()
- }
- }
- EventBus.getDefault().post(BackupEvent.createFinished())
- }
-
- @Throws(IOException::class)
- private fun processVersion(db: SQLiteDatabase, version: DatabaseVersion) {
- if (version.version > db.version) {
- throw DatabaseDowngradeException(db.version, version.version)
- }
- db.version = version.version
- }
-
- private fun processStatement(db: SQLiteDatabase, statement: SqlStatement) {
- val isForSmsFtsSecretTable = statement.statement.contains(SearchDatabase.SMS_FTS_TABLE_NAME + "_")
- val isForMmsFtsSecretTable = statement.statement.contains(SearchDatabase.MMS_FTS_TABLE_NAME + "_")
- val isForSqliteSecretTable = statement.statement.toLowerCase(Locale.ENGLISH).startsWith("create table sqlite_")
- if (isForSmsFtsSecretTable || isForMmsFtsSecretTable || isForSqliteSecretTable) {
- Log.i(TAG, "Ignoring import for statement: " + statement.statement)
- return
- }
- val parameters: MutableList = LinkedList()
- for (parameter in statement.parametersList) {
- when {
- parameter.hasStringParamter() -> parameters.add(parameter.stringParamter)
- parameter.hasDoubleParameter() -> parameters.add(parameter.doubleParameter)
- parameter.hasIntegerParameter() -> parameters.add(parameter.integerParameter)
- parameter.hasBlobParameter() -> parameters.add(parameter.blobParameter.toByteArray())
- parameter.hasNullparameter() -> parameters.add(null)
- }
- }
- if (parameters.size > 0) {
- db.execSQL(statement.statement, parameters.toTypedArray())
- } else {
- db.execSQL(statement.statement)
- }
- }
-
- @Throws(IOException::class)
- private fun processAttachment(context: Context, attachmentSecret: AttachmentSecret,
- db: SQLiteDatabase, attachment: Attachment,
- inputStream: BackupRecordInputStream) {
- val partsDirectory = context.getDir(AttachmentDatabase.DIRECTORY, Context.MODE_PRIVATE)
- val dataFile = File.createTempFile("part", ".mms", partsDirectory)
- val output = ModernEncryptingPartOutputStream.createFor(attachmentSecret, dataFile, false)
- inputStream.readAttachmentTo(output.second, attachment.length)
- val contentValues = ContentValues()
- contentValues.put(AttachmentDatabase.DATA, dataFile.absolutePath)
- contentValues.put(AttachmentDatabase.THUMBNAIL, null as String?)
- contentValues.put(AttachmentDatabase.DATA_RANDOM, output.first)
- db.update(AttachmentDatabase.TABLE_NAME, contentValues,
- "${AttachmentDatabase.ROW_ID} = ? AND ${AttachmentDatabase.UNIQUE_ID} = ?",
- arrayOf(attachment.rowId.toString(), attachment.attachmentId.toString()))
- }
-
- @Throws(IOException::class)
- private fun processAvatar(context: Context, avatar: Avatar, inputStream: BackupRecordInputStream) {
- inputStream.readAttachmentTo(FileOutputStream(
- AvatarHelper.getAvatarFile(context, Address.fromExternal(context, avatar.name))), avatar.length)
- }
-
- @SuppressLint("ApplySharedPref")
- private fun processPreference(context: Context, preference: SharedPreference) {
- val preferences = context.getSharedPreferences(preference.file, 0)
- val key = preference.key
- val value = preference.value
-
- // See the comment next to PREF_PREFIX_TYPE_* constants.
- when {
- key.startsWith(PREF_PREFIX_TYPE_INT) ->
- preferences.edit().putInt(
- key.substring(PREF_PREFIX_TYPE_INT.length),
- value.toInt()
- ).commit()
- key.startsWith(PREF_PREFIX_TYPE_BOOLEAN) ->
- preferences.edit().putBoolean(
- key.substring(PREF_PREFIX_TYPE_BOOLEAN.length),
- value.toBoolean()
- ).commit()
- else ->
- preferences.edit().putString(key, value).commit()
- }
- }
-
- private fun dropAllTables(db: SQLiteDatabase) {
- db.rawQuery("SELECT name, type FROM sqlite_master", null).use { cursor ->
- while (cursor != null && cursor.moveToNext()) {
- val name = cursor.getString(0)
- val type = cursor.getString(1)
- if ("table" == type && !name.startsWith("sqlite_")) {
- db.execSQL("DROP TABLE IF EXISTS $name")
- }
- }
- }
- }
-
- private fun trimEntriesForExpiredMessages(context: Context, db: SQLiteDatabase) {
- val trimmedCondition = " NOT IN (SELECT ${MmsSmsColumns.ID} FROM ${MmsDatabase.TABLE_NAME})"
- db.delete(GroupReceiptDatabase.TABLE_NAME, GroupReceiptDatabase.MMS_ID + trimmedCondition, null)
- val columns = arrayOf(AttachmentDatabase.ROW_ID, AttachmentDatabase.UNIQUE_ID)
- val where = AttachmentDatabase.MMS_ID + trimmedCondition
- db.query(AttachmentDatabase.TABLE_NAME, columns, where, null, null, null, null).use { cursor ->
- while (cursor != null && cursor.moveToNext()) {
- DatabaseComponent.get(context).attachmentDatabase()
- .deleteAttachment(AttachmentId(cursor.getLong(0), cursor.getLong(1)))
- }
- }
- db.query(ThreadDatabase.TABLE_NAME, arrayOf(ThreadDatabase.ID),
- ThreadDatabase.EXPIRES_IN + " > 0", null, null, null, null).use { cursor ->
- while (cursor != null && cursor.moveToNext()) {
- DatabaseComponent.get(context).threadDatabase().update(cursor.getLong(0), false)
- }
- }
- }
-
- private class BackupRecordInputStream : Closeable {
- private val inputStream: InputStream
- private val cipher: Cipher
- private val mac: Mac
- private val cipherKey: ByteArray
- private val macKey: ByteArray
- private val iv: ByteArray
-
- private var counter = 0
-
- @Throws(IOException::class)
- constructor(inputStream: InputStream, passphrase: String) : super() {
- try {
- this.inputStream = inputStream
- val headerLengthBytes = ByteArray(4)
- Util.readFully(this.inputStream, headerLengthBytes)
- val headerLength = Conversions.byteArrayToInt(headerLengthBytes)
- val headerFrame = ByteArray(headerLength)
- Util.readFully(this.inputStream, headerFrame)
- val frame = BackupFrame.parseFrom(headerFrame)
- if (!frame.hasHeader()) {
- throw IOException("Backup stream does not start with header!")
- }
- val header = frame.header
- iv = header.iv.toByteArray()
- if (iv.size != 16) {
- throw IOException("Invalid IV length!")
- }
- val key = BackupUtil.computeBackupKey(passphrase, if (header.hasSalt()) header.salt.toByteArray() else null)
- val derived = HKDFv3().deriveSecrets(key, "Backup Export".toByteArray(), 64)
- val split = ByteUtil.split(derived, 32, 32)
- cipherKey = split[0]
- macKey = split[1]
- cipher = Cipher.getInstance("AES/CTR/NoPadding")
- mac = Mac.getInstance("HmacSHA256")
- mac.init(SecretKeySpec(macKey, "HmacSHA256"))
- counter = Conversions.byteArrayToInt(iv)
- } catch (e: Exception) {
- when (e) {
- is NoSuchAlgorithmException,
- is NoSuchPaddingException,
- is InvalidKeyException -> {
- throw AssertionError(e)
- }
- else -> throw e
- }
- }
- }
-
- @Throws(IOException::class)
- fun readFrame(): BackupFrame {
- return readFrame(inputStream)
- }
-
- @Throws(IOException::class)
- fun readAttachmentTo(out: OutputStream, length: Int) {
- var length = length
- try {
- Conversions.intToByteArray(iv, 0, counter++)
- cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
- mac.update(iv)
- val buffer = ByteArray(8192)
- while (length > 0) {
- val read = inputStream.read(buffer, 0, Math.min(buffer.size, length))
- if (read == -1) throw IOException("File ended early!")
- mac.update(buffer, 0, read)
- val plaintext = cipher.update(buffer, 0, read)
- if (plaintext != null) {
- out.write(plaintext, 0, plaintext.size)
- }
- length -= read
- }
- val plaintext = cipher.doFinal()
- if (plaintext != null) {
- out.write(plaintext, 0, plaintext.size)
- }
- out.close()
- val ourMac = ByteUtil.trim(mac.doFinal(), 10)
- val theirMac = ByteArray(10)
- try {
- Util.readFully(inputStream, theirMac)
- } catch (e: IOException) {
- throw IOException(e)
- }
- if (!MessageDigest.isEqual(ourMac, theirMac)) {
- throw IOException("Bad MAC")
- }
- } catch (e: Exception) {
- when (e) {
- is InvalidKeyException,
- is InvalidAlgorithmParameterException,
- is IllegalBlockSizeException,
- is BadPaddingException -> {
- throw AssertionError(e)
- }
- else -> throw e
- }
- }
- }
-
- @Throws(IOException::class)
- private fun readFrame(`in`: InputStream?): BackupFrame {
- return try {
- val length = ByteArray(4)
- Util.readFully(`in`, length)
- val frame = ByteArray(Conversions.byteArrayToInt(length))
- Util.readFully(`in`, frame)
- val theirMac = ByteArray(10)
- System.arraycopy(frame, frame.size - 10, theirMac, 0, theirMac.size)
- mac.update(frame, 0, frame.size - 10)
- val ourMac = ByteUtil.trim(mac.doFinal(), 10)
- if (!MessageDigest.isEqual(ourMac, theirMac)) {
- throw IOException("Bad MAC")
- }
- Conversions.intToByteArray(iv, 0, counter++)
- cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
- val plaintext = cipher.doFinal(frame, 0, frame.size - 10)
- BackupFrame.parseFrom(plaintext)
- } catch (e: Exception) {
- when (e) {
- is InvalidKeyException,
- is InvalidAlgorithmParameterException,
- is IllegalBlockSizeException,
- is BadPaddingException -> {
- throw AssertionError(e)
- }
- else -> throw e
- }
- }
- }
-
- @Throws(IOException::class)
- override fun close() {
- inputStream.close()
- }
- }
-
- class DatabaseDowngradeException internal constructor(currentVersion: Int, backupVersion: Int) :
- IOException("Tried to import a backup with version $backupVersion into a database with version $currentVersion")
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java
index 195c066d45..1ac4f8442b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java
@@ -13,6 +13,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import org.session.libsession.snode.SnodeAPI;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.conversation.v2.components.ExpirationTimerView;
import org.thoughtcrime.securesms.database.model.MessageRecord;
@@ -106,7 +107,7 @@ public class ConversationItemFooter extends LinearLayout {
messageRecord.getExpiresIn());
this.timerView.startAnimation();
- if (messageRecord.getExpireStarted() + messageRecord.getExpiresIn() <= System.currentTimeMillis()) {
+ if (messageRecord.getExpireStarted() + messageRecord.getExpiresIn() <= SnodeAPI.getNowWithOffset()) {
ApplicationContext.getInstance(getContext()).getExpiringMessageManager().checkSchedule();
}
} else if (!messageRecord.isOutgoing() && !messageRecord.isMediaPending()) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/GlideBitmapListeningTarget.java b/app/src/main/java/org/thoughtcrime/securesms/components/GlideBitmapListeningTarget.java
index 61094fb7df..157bc215e6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/GlideBitmapListeningTarget.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/GlideBitmapListeningTarget.java
@@ -4,30 +4,48 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+
+import android.view.View;
import android.widget.ImageView;
import com.bumptech.glide.request.target.BitmapImageViewTarget;
import org.session.libsignal.utilities.SettableFuture;
+import java.lang.ref.WeakReference;
+
public class GlideBitmapListeningTarget extends BitmapImageViewTarget {
private final SettableFuture loaded;
+ private final WeakReference loadingView;
- public GlideBitmapListeningTarget(@NonNull ImageView view, @NonNull SettableFuture loaded) {
+ public GlideBitmapListeningTarget(@NonNull ImageView view, @Nullable View loadingView, @NonNull SettableFuture loaded) {
super(view);
this.loaded = loaded;
+ this.loadingView = new WeakReference(loadingView);
}
@Override
protected void setResource(@Nullable Bitmap resource) {
super.setResource(resource);
loaded.set(true);
+
+ View loadingViewInstance = loadingView.get();
+
+ if (loadingViewInstance != null) {
+ loadingViewInstance.setVisibility(View.GONE);
+ }
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
loaded.set(true);
+
+ View loadingViewInstance = loadingView.get();
+
+ if (loadingViewInstance != null) {
+ loadingViewInstance.setVisibility(View.GONE);
+ }
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/GlideDrawableListeningTarget.java b/app/src/main/java/org/thoughtcrime/securesms/components/GlideDrawableListeningTarget.java
index d177900124..406c878ec9 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/GlideDrawableListeningTarget.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/GlideDrawableListeningTarget.java
@@ -3,30 +3,48 @@ package org.thoughtcrime.securesms.components;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+
+import android.view.View;
import android.widget.ImageView;
import com.bumptech.glide.request.target.DrawableImageViewTarget;
import org.session.libsignal.utilities.SettableFuture;
+import java.lang.ref.WeakReference;
+
public class GlideDrawableListeningTarget extends DrawableImageViewTarget {
private final SettableFuture loaded;
+ private final WeakReference loadingView;
- public GlideDrawableListeningTarget(@NonNull ImageView view, @NonNull SettableFuture loaded) {
+ public GlideDrawableListeningTarget(@NonNull ImageView view, @Nullable View loadingView, @NonNull SettableFuture loaded) {
super(view);
this.loaded = loaded;
+ this.loadingView = new WeakReference(loadingView);
}
@Override
protected void setResource(@Nullable Drawable resource) {
super.setResource(resource);
loaded.set(true);
+
+ View loadingViewInstance = loadingView.get();
+
+ if (loadingViewInstance != null) {
+ loadingViewInstance.setVisibility(View.GONE);
+ }
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
loaded.set(true);
+
+ View loadingViewInstance = loadingView.get();
+
+ if (loadingViewInstance != null) {
+ loadingViewInstance.setVisibility(View.GONE);
+ }
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/LabeledSeparatorView.kt b/app/src/main/java/org/thoughtcrime/securesms/components/LabeledSeparatorView.kt
deleted file mode 100644
index df36719db2..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/components/LabeledSeparatorView.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.thoughtcrime.securesms.components
-
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Paint
-import android.graphics.Path
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.widget.RelativeLayout
-import network.loki.messenger.R
-import network.loki.messenger.databinding.ViewSeparatorBinding
-import org.thoughtcrime.securesms.util.toPx
-import org.session.libsession.utilities.ThemeUtil
-
-class LabeledSeparatorView : RelativeLayout {
-
- private lateinit var binding: ViewSeparatorBinding
- private val path = Path()
-
- private val paint: Paint by lazy {
- val result = Paint()
- result.style = Paint.Style.STROKE
- result.color = ThemeUtil.getThemedColor(context, R.attr.dividerHorizontal)
- result.strokeWidth = toPx(1, resources).toFloat()
- result.isAntiAlias = true
- result
- }
-
- // region Lifecycle
- constructor(context: Context) : super(context) {
- setUpViewHierarchy()
- }
-
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- setUpViewHierarchy()
- }
-
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
- setUpViewHierarchy()
- }
-
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
- setUpViewHierarchy()
- }
-
- private fun setUpViewHierarchy() {
- binding = ViewSeparatorBinding.inflate(LayoutInflater.from(context))
- val layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
- addView(binding.root, layoutParams)
- setWillNotDraw(false)
- }
- // endregion
-
- // region Updating
- override fun onDraw(c: Canvas) {
- super.onDraw(c)
- val w = width.toFloat()
- val h = height.toFloat()
- val hMargin = toPx(16, resources).toFloat()
- path.reset()
- path.moveTo(0.0f, h / 2)
- path.lineTo(binding.titleTextView.left - hMargin, h / 2)
- path.addRoundRect(binding.titleTextView.left - hMargin, toPx(1, resources).toFloat(), binding.titleTextView.right + hMargin, h - toPx(1, resources).toFloat(), h / 2, h / 2, Path.Direction.CCW)
- path.moveTo(binding.titleTextView.right + hMargin, h / 2)
- path.lineTo(w, h / 2)
- path.close()
- c.drawPath(path, paint)
- }
- // endregion
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/LinkPreviewView.java b/app/src/main/java/org/thoughtcrime/securesms/components/LinkPreviewView.java
deleted file mode 100644
index 5b2199896a..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/components/LinkPreviewView.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package org.thoughtcrime.securesms.components;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.thoughtcrime.securesms.mms.GlideRequests;
-
-import org.thoughtcrime.securesms.mms.ImageSlide;
-import org.thoughtcrime.securesms.mms.SlidesClickedListener;
-
-import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
-
-import network.loki.messenger.R;
-import okhttp3.HttpUrl;
-
-public class LinkPreviewView extends FrameLayout {
-
- private static final int TYPE_CONVERSATION = 0;
- private static final int TYPE_COMPOSE = 1;
-
- private ViewGroup container;
- private OutlinedThumbnailView thumbnail;
- private TextView title;
- private TextView site;
- private View divider;
- private View closeButton;
- private View spinner;
-
- private int type;
- private int defaultRadius;
- private CornerMask cornerMask;
- private Outliner outliner;
- private CloseClickedListener closeClickedListener;
-
- public LinkPreviewView(Context context) {
- super(context);
- init(null);
- }
-
- public LinkPreviewView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- init(attrs);
- }
-
- private void init(@Nullable AttributeSet attrs) {
- inflate(getContext(), R.layout.link_preview, this);
-
- container = findViewById(R.id.linkpreview_container);
- thumbnail = findViewById(R.id.linkpreview_thumbnail);
- title = findViewById(R.id.linkpreview_title);
- site = findViewById(R.id.linkpreview_site);
- divider = findViewById(R.id.linkpreview_divider);
- spinner = findViewById(R.id.linkpreview_progress_wheel);
- closeButton = findViewById(R.id.linkpreview_close);
- defaultRadius = getResources().getDimensionPixelSize(R.dimen.thumbnail_default_radius);
- cornerMask = new CornerMask(this);
- outliner = new Outliner();
-
- outliner.setColor(getResources().getColor(R.color.transparent));
-
- if (attrs != null) {
- TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.LinkPreviewView, 0, 0);
- type = typedArray.getInt(R.styleable.LinkPreviewView_linkpreview_type, 0);
- typedArray.recycle();
- }
-
- if (type == TYPE_COMPOSE) {
- container.setBackgroundColor(Color.TRANSPARENT);
- container.setPadding(0, 0, 0, 0);
- divider.setVisibility(VISIBLE);
-
- closeButton.setOnClickListener(v -> {
- if (closeClickedListener != null) {
- closeClickedListener.onCloseClicked();
- }
- });
- }
-
- setWillNotDraw(false);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- if (type == TYPE_COMPOSE) return;
-
- cornerMask.mask(canvas);
- outliner.draw(canvas);
- }
-
- public void setLoading() {
- title.setVisibility(GONE);
- site.setVisibility(GONE);
- thumbnail.setVisibility(GONE);
- spinner.setVisibility(VISIBLE);
- closeButton.setVisibility(GONE);
- }
-
- public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull LinkPreview linkPreview, boolean showThumbnail, boolean showCloseButton) {
- setLinkPreview(glideRequests, linkPreview, showThumbnail);
- if (showCloseButton) {
- closeButton.setVisibility(VISIBLE);
- } else {
- closeButton.setVisibility(GONE);
- }
- }
-
- public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull LinkPreview linkPreview, boolean showThumbnail) {
- title.setVisibility(VISIBLE);
- site.setVisibility(VISIBLE);
- thumbnail.setVisibility(VISIBLE);
- spinner.setVisibility(GONE);
- closeButton.setVisibility(VISIBLE);
-
- title.setText(linkPreview.getTitle());
-
- HttpUrl url = HttpUrl.parse(linkPreview.getUrl());
- if (url != null) {
- site.setText(url.topPrivateDomain());
- }
-
- if (showThumbnail && linkPreview.getThumbnail().isPresent()) {
- thumbnail.setVisibility(VISIBLE);
- thumbnail.setImageResource(glideRequests, new ImageSlide(getContext(), linkPreview.getThumbnail().get()), type == TYPE_CONVERSATION, false);
- thumbnail.showDownloadText(false);
- } else {
- thumbnail.setVisibility(GONE);
- }
- }
-
- public void setCorners(int topLeft, int topRight) {
- cornerMask.setRadii(topLeft, topRight, 0, 0);
- outliner.setRadii(topLeft, topRight, 0, 0);
- thumbnail.setCorners(topLeft, defaultRadius, defaultRadius, defaultRadius);
- postInvalidate();
- }
-
- public void setCloseClickedListener(@Nullable CloseClickedListener closeClickedListener) {
- this.closeClickedListener = closeClickedListener;
- }
-
- public void setDownloadClickedListener(SlidesClickedListener listener) {
- thumbnail.setDownloadClickListener(listener);
- }
-
- public interface CloseClickedListener {
- void onCloseClicked();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/OutlinedThumbnailView.java b/app/src/main/java/org/thoughtcrime/securesms/components/OutlinedThumbnailView.java
deleted file mode 100644
index 71bf8a2804..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/components/OutlinedThumbnailView.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.thoughtcrime.securesms.components;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-
-import org.session.libsession.utilities.ThemeUtil;
-import org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailView;
-
-import network.loki.messenger.R;
-
-public class OutlinedThumbnailView extends ThumbnailView {
-
- private CornerMask cornerMask;
- private Outliner outliner;
-
- public OutlinedThumbnailView(Context context) {
- super(context);
- init();
- }
-
- public OutlinedThumbnailView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- private void init() {
- cornerMask = new CornerMask(this);
- outliner = new Outliner();
-
- outliner.setColor(ThemeUtil.getThemedColor(getContext(), R.attr.conversation_item_image_outline_color));
- setWillNotDraw(false);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
-
- cornerMask.mask(canvas);
- outliner.draw(canvas);
- }
-
- public void setCorners(int topLeft, int topRight, int bottomRight, int bottomLeft) {
- cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft);
- outliner.setRadii(topLeft, topRight, bottomRight, bottomLeft);
- postInvalidate();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt
index 0ded9f346e..a827a7d260 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt
@@ -34,6 +34,8 @@ class ProfilePictureView @JvmOverloads constructor(
private val profilePicturesCache = mutableMapOf()
private val unknownRecipientDrawable = ResourceContactPhoto(R.drawable.ic_profile_default)
.asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context), false)
+ private val unknownOpenGroupDrawable = ResourceContactPhoto(R.drawable.ic_notification)
+ .asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context), false)
// endregion
@@ -43,10 +45,8 @@ class ProfilePictureView @JvmOverloads constructor(
val contact = DatabaseComponent.get(context).sessionContactDatabase().getContactWithSessionID(publicKey)
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
}
- fun isOpenGroupWithProfilePicture(recipient: Recipient): Boolean {
- return recipient.isOpenGroupRecipient && recipient.groupAvatarId != null
- }
- if (recipient.isGroupRecipient && !isOpenGroupWithProfilePicture(recipient)) {
+
+ if (recipient.isClosedGroupRecipient) {
val members = DatabaseComponent.get(context).groupDatabase()
.getGroupMemberAddresses(recipient.address.toGroupString(), true)
.sorted()
@@ -107,7 +107,7 @@ class ProfilePictureView @JvmOverloads constructor(
if (profilePicturesCache.containsKey(publicKey) && profilePicturesCache[publicKey] == recipient.profileAvatar) return
val signalProfilePicture = recipient.contactPhoto
val avatar = (signalProfilePicture as? ProfileContactPhoto)?.avatarObject
- val placeholder = PlaceholderAvatarPhoto(context, publicKey, displayName ?: "${publicKey.take(4)}...${publicKey.takeLast(4)}")
+
if (signalProfilePicture != null && avatar != "0" && avatar != "") {
glide.clear(imageView)
glide.load(signalProfilePicture)
@@ -117,7 +117,12 @@ class ProfilePictureView @JvmOverloads constructor(
.diskCacheStrategy(DiskCacheStrategy.NONE)
.circleCrop()
.into(imageView)
+ } else if (recipient.isOpenGroupRecipient && recipient.groupAvatarId == null) {
+ glide.clear(imageView)
+ imageView.setImageDrawable(unknownOpenGroupDrawable)
} else {
+ val placeholder = PlaceholderAvatarPhoto(context, publicKey, displayName ?: "${publicKey.take(4)}...${publicKey.takeLast(4)}")
+
glide.clear(imageView)
glide.load(placeholder)
.placeholder(unknownRecipientDrawable)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt b/app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt
new file mode 100644
index 0000000000..6748478736
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/SafeViewPager.kt
@@ -0,0 +1,30 @@
+package org.thoughtcrime.securesms.components
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import androidx.viewpager.widget.ViewPager
+
+/**
+ * An extension of ViewPager to swallow erroneous multi-touch exceptions.
+ *
+ * @see https://stackoverflow.com/questions/6919292/pointerindex-out-of-range-android-multitouch
+ */
+class SafeViewPager @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null
+) : ViewPager(context, attrs) {
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onTouchEvent(event: MotionEvent?): Boolean = try {
+ super.onTouchEvent(event)
+ } catch (e: IllegalArgumentException) {
+ false
+ }
+
+ override fun onInterceptTouchEvent(event: MotionEvent?): Boolean = try {
+ super.onInterceptTouchEvent(event)
+ } catch (e: IllegalArgumentException) {
+ false
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/StickerView.java b/app/src/main/java/org/thoughtcrime/securesms/components/StickerView.java
index 6214c58531..98a623eef3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/StickerView.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/StickerView.java
@@ -52,19 +52,4 @@ public class StickerView extends FrameLayout {
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
image.setOnLongClickListener(l);
}
-
- public void setSticker(@NonNull GlideRequests glideRequests, @NonNull Slide stickerSlide) {
- boolean showControls = stickerSlide.asAttachment().getDataUri() == null;
-
- image.setImageResource(glideRequests, stickerSlide, showControls, false);
- missingShade.setVisibility(showControls ? View.VISIBLE : View.GONE);
- }
-
- public void setThumbnailClickListener(@NonNull SlideClickListener listener) {
- image.setThumbnailClickListener(listener);
- }
-
- public void setDownloadClickListener(@NonNull SlidesClickedListener listener) {
- image.setDownloadClickListener(listener);
- }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
index d512e0924c..4f0072cc24 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java
@@ -24,7 +24,7 @@ public class EmojiTextView extends AppCompatTextView {
private static final char ELLIPSIS = '…';
private CharSequence previousText;
- private BufferType previousBufferType;
+ private BufferType previousBufferType = BufferType.NORMAL;
private float originalFontSize;
private boolean useSystemEmoji;
private boolean sizeChangeInProgress;
@@ -49,6 +49,15 @@ public class EmojiTextView extends AppCompatTextView {
}
@Override public void setText(@Nullable CharSequence text, BufferType type) {
+ // No need to do anything special if the text is null or empty
+ if (text == null || text.length() == 0) {
+ previousText = text;
+ previousOverflowText = overflowText;
+ previousBufferType = type;
+ super.setText(text, type);
+ return;
+ }
+
EmojiParser.CandidateList candidates = EmojiProvider.getCandidates(text);
if (scaleEmojis && candidates != null && candidates.allEmojis) {
@@ -149,10 +158,15 @@ public class EmojiTextView extends AppCompatTextView {
}
private boolean unchanged(CharSequence text, CharSequence overflowText, BufferType bufferType) {
- return Util.equals(previousText, text) &&
- Util.equals(previousOverflowText, overflowText) &&
- Util.equals(previousBufferType, bufferType) &&
- useSystemEmoji == useSystemEmoji() &&
+ CharSequence finalPrevText = (previousText == null || previousText.length() == 0 ? "" : previousText);
+ CharSequence finalText = (text == null || text.length() == 0 ? "" : text);
+ CharSequence finalPrevOverflowText = (previousOverflowText == null || previousOverflowText.length() == 0 ? "" : previousOverflowText);
+ CharSequence finalOverflowText = (overflowText == null || overflowText.length() == 0 ? "" : overflowText);
+
+ return Util.equals(finalPrevText, finalText) &&
+ Util.equals(finalPrevOverflowText, finalOverflowText) &&
+ Util.equals(previousBufferType, bufferType) &&
+ useSystemEmoji == useSystemEmoji() &&
!sizeChangeInProgress;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/menu/ActionItem.kt b/app/src/main/java/org/thoughtcrime/securesms/components/menu/ActionItem.kt
index 358a9d326b..d0b101a9f1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/menu/ActionItem.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/menu/ActionItem.kt
@@ -5,8 +5,9 @@ import androidx.annotation.AttrRes
/**
* Represents an action to be rendered
*/
-data class ActionItem(
+data class ActionItem @JvmOverloads constructor(
@AttrRes val iconRes: Int,
val title: CharSequence,
- val action: Runnable
+ val action: Runnable,
+ val contentDescription: String? = null
)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt b/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt
index 65fb1ddbbc..c86b40dfa5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/menu/ContextMenuList.kt
@@ -77,6 +77,7 @@ class ContextMenuList(recyclerView: RecyclerView, onItemClick: () -> Unit) {
context.theme.resolveAttribute(model.item.iconRes, typedValue, true)
icon.setImageDrawable(ContextCompat.getDrawable(context, typedValue.resourceId))
}
+ itemView.contentDescription = model.item.contentDescription
title.text = model.item.title
itemView.setOnClickListener {
model.item.action.run()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index c961be7264..2c3e8203b3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -32,7 +32,6 @@ import android.widget.RelativeLayout
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
-import androidx.core.view.drawToBitmap
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
@@ -45,12 +44,15 @@ import com.annimon.stream.Stream
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityConversationV2Binding
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import nl.komponents.kovenant.ui.successUi
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.contacts.Contact
+import org.session.libsession.messaging.jobs.AttachmentDownloadJob
+import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.mentions.Mention
import org.session.libsession.messaging.mentions.MentionsManager
import org.session.libsession.messaging.messages.ExpirationConfiguration
@@ -155,6 +157,7 @@ import org.thoughtcrime.securesms.util.SaveAttachmentTask
import org.thoughtcrime.securesms.util.push
import org.thoughtcrime.securesms.util.show
import org.thoughtcrime.securesms.util.toPx
+import java.lang.ref.WeakReference
import java.util.Locale
import java.util.concurrent.ExecutionException
import java.util.concurrent.atomic.AtomicLong
@@ -248,11 +251,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val searchViewModel: SearchViewModel by viewModels()
var searchViewItem: MenuItem? = null
+ private var emojiPickerVisible = false
+
private val isScrolledToBottom: Boolean
- get() {
- val position = layoutManager?.findFirstCompletelyVisibleItemPosition() ?: 0
- return position == 0
- }
+ get() = binding?.conversationRecyclerView?.isScrolledToBottom ?: true
private val layoutManager: LinearLayoutManager?
get() { return binding?.conversationRecyclerView?.layoutManager as LinearLayoutManager? }
@@ -293,6 +295,12 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
onDeselect(message, position, it)
}
},
+ onAttachmentNeedsDownload = { attachmentId, mmsId ->
+ // Start download (on IO thread)
+ lifecycleScope.launch(Dispatchers.IO) {
+ JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
+ }
+ },
glide = glide,
lifecycleCoroutineScope = lifecycleScope
)
@@ -338,41 +346,66 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// messageIdToScroll
messageToScrollTimestamp.set(intent.getLongExtra(SCROLL_MESSAGE_ID, -1))
messageToScrollAuthor.set(intent.getParcelableExtra(SCROLL_MESSAGE_AUTHOR))
- val thread = threadDb.getRecipientForThreadId(viewModel.threadId)
- if (thread == null) {
+ val recipient = viewModel.recipient
+ val openGroup = recipient.let { viewModel.openGroup }
+ if (recipient == null || (recipient.isOpenGroupRecipient && openGroup == null)) {
Toast.makeText(this, "This thread has been deleted.", Toast.LENGTH_LONG).show()
return finish()
}
- setUpRecyclerView()
+
setUpToolBar()
setUpInputBar()
setUpLinkPreviewObserver()
restoreDraftIfNeeded()
setUpUiStateObserver()
binding!!.scrollToBottomButton.setOnClickListener {
- val layoutManager = binding?.conversationRecyclerView?.layoutManager ?: return@setOnClickListener
+ val layoutManager = (binding?.conversationRecyclerView?.layoutManager as? LinearLayoutManager) ?: return@setOnClickListener
+
if (layoutManager.isSmoothScrolling) {
binding?.conversationRecyclerView?.scrollToPosition(0)
} else {
- binding?.conversationRecyclerView?.smoothScrollToPosition(0)
+ // It looks like 'smoothScrollToPosition' will actually load all intermediate items in
+ // order to do the scroll, this can be very slow if there are a lot of messages so
+ // instead we check the current position and if there are more than 10 items to scroll
+ // we jump instantly to the 10th item and scroll from there (this should happen quick
+ // enough to give a similar scroll effect without having to load everything)
+ val position = layoutManager.findFirstVisibleItemPosition()
+ if (position > 10) {
+ binding?.conversationRecyclerView?.scrollToPosition(10)
+ }
+
+ binding?.conversationRecyclerView?.post {
+ binding?.conversationRecyclerView?.smoothScrollToPosition(0)
+ }
}
}
- unreadCount = mmsSmsDb.getUnreadCount(viewModel.threadId)
+
updateUnreadCountIndicator()
- setUpTypingObserver()
- setUpRecipientObserver()
- getLatestOpenGroupInfoIfNeeded()
+ updateSubtitle()
setUpBlockedBanner()
- setUpOutdatedClientBanner()
binding!!.searchBottomBar.setEventListener(this)
- setUpSearchResultObserver()
- scrollToFirstUnreadMessageIfNeeded()
+ updateSendAfterApprovalText()
showOrHideInputIfNeeded()
setUpMessageRequestsBar()
- viewModel.recipient?.let { recipient ->
- if (recipient.isOpenGroupRecipient && viewModel.openGroup == null) {
- Toast.makeText(this, "This thread has been deleted.", Toast.LENGTH_LONG).show()
- return finish()
+
+ val weakActivity = WeakReference(this)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ unreadCount = mmsSmsDb.getUnreadCount(viewModel.threadId)
+
+ // Note: We are accessing the `adapter` property because we want it to be loaded on
+ // the background thread to avoid blocking the UI thread and potentially hanging when
+ // transitioning to the activity
+ weakActivity.get()?.adapter ?: return@launch
+
+ withContext(Dispatchers.Main) {
+ setUpRecyclerView()
+ setUpTypingObserver()
+ setUpRecipientObserver()
+ getLatestOpenGroupInfoIfNeeded()
+ setUpSearchResultObserver()
+ scrollToFirstUnreadMessageIfNeeded()
+ setUpOutdatedClientBanner()
}
}
@@ -386,7 +419,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
super.onResume()
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(viewModel.threadId)
val recipient = viewModel.recipient ?: return
- threadDb.markAllAsRead(viewModel.threadId, recipient.isOpenGroupRecipient)
+
+ lifecycleScope.launch(Dispatchers.IO) {
+ threadDb.markAllAsRead(viewModel.threadId, recipient.isOpenGroupRecipient)
+ }
+
contentResolver.registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
true,
@@ -449,11 +486,16 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
handleRecyclerViewScrolled()
}
})
+
+ binding!!.conversationRecyclerView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
+ showScrollToBottomButtonIfApplicable()
+ }
}
// called from onCreate
private fun setUpToolBar() {
- setSupportActionBar(binding?.toolbar)
+ val binding = binding ?: return
+ setSupportActionBar(binding.toolbar)
val actionBar = supportActionBar ?: return
val recipient = viewModel.recipient ?: return
actionBar.title = ""
@@ -465,6 +507,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// called from onCreate
private fun setUpInputBar() {
+ binding!!.inputBar.isVisible = viewModel.openGroup == null || viewModel.openGroup?.canWrite == true
binding!!.inputBar.delegate = this
binding!!.inputBarRecordingView.delegate = this
// GIF button
@@ -567,7 +610,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val name = contact?.displayName(Contact.ContactContext.REGULAR) ?: sessionID
binding?.blockedBannerTextView?.text = resources.getString(R.string.activity_conversation_blocked_banner_text, name)
binding?.blockedBanner?.isVisible = recipient.isBlocked
- binding?.blockedBanner?.setOnClickListener { viewModel.unblock() }
+ binding?.blockedBanner?.setOnClickListener { viewModel.unblock(this@ConversationActivityV2) }
}
private fun setUpOutdatedClientBanner() {
@@ -647,6 +690,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// region Animation & Updating
override fun onModified(recipient: Recipient) {
+ viewModel.updateRecipient()
+
runOnUiThread {
val threadRecipient = viewModel.recipient ?: return@runOnUiThread
if (threadRecipient.isContactRecipient) {
@@ -654,7 +699,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
setUpMessageRequestsBar()
invalidateOptionsMenu()
+ updateSubtitle()
+ updateSendAfterApprovalText()
showOrHideInputIfNeeded()
+
maybeUpdateToolbar(threadRecipient)
}
}
@@ -663,6 +711,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
binding?.toolbarContent?.update(recipient, viewModel.openGroup, viewModel.expirationConfiguration)
}
+ private fun updateSendAfterApprovalText() {
+ binding?.textSendAfterApproval?.isVisible = viewModel.showSendAfterApprovalText
+ }
+
private fun showOrHideInputIfNeeded() {
val recipient = viewModel.recipient
if (recipient != null && recipient.isClosedGroupRecipient) {
@@ -782,7 +834,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val recipient = viewModel.recipient ?: return
if (!isShowingMentionCandidatesView) {
additionalContentContainer.removeAllViews()
- val view = MentionCandidatesView(this)
+ val view = MentionCandidatesView(this).apply {
+ contentDescription = context.getString(R.string.AccessibilityId_mentions_list)
+ }
view.glide = glide
view.onCandidateSelected = { handleMentionSelected(it) }
additionalContentContainer.addView(view)
@@ -899,15 +953,14 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val binding = binding ?: return
val wasTypingIndicatorVisibleBefore = binding.typingIndicatorViewContainer.isVisible
binding.typingIndicatorViewContainer.isVisible = wasTypingIndicatorVisibleBefore && isScrolledToBottom
- binding.typingIndicatorViewContainer.isVisible
- showOrHidScrollToBottomButton()
+ showScrollToBottomButtonIfApplicable()
val firstVisiblePosition = layoutManager?.findFirstVisibleItemPosition() ?: -1
unreadCount = min(unreadCount, firstVisiblePosition).coerceAtLeast(0)
updateUnreadCountIndicator()
}
- private fun showOrHidScrollToBottomButton(show: Boolean = true) {
- binding?.scrollToBottomButton?.isVisible = show && !isScrolledToBottom && adapter.itemCount > 0
+ private fun showScrollToBottomButtonIfApplicable() {
+ binding?.scrollToBottomButton?.isVisible = !emojiPickerVisible && !isScrolledToBottom && adapter.itemCount > 0
}
private fun updateUnreadCountIndicator() {
@@ -939,17 +992,19 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
override fun block(deleteThread: Boolean) {
val title = R.string.RecipientPreferenceActivity_block_this_contact_question
val message = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact
- AlertDialog.Builder(this)
+ val dialog = AlertDialog.Builder(this)
.setTitle(title)
.setMessage(message)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_block) { _, _ ->
- viewModel.block()
+ viewModel.block(this@ConversationActivityV2)
if (deleteThread) {
viewModel.deleteThread()
finish()
}
}.show()
+ val button = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
+ button.setContentDescription("Confirm block")
}
override fun copySessionID(sessionId: String) {
@@ -959,6 +1014,18 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
}
+ override fun copyOpenGroupUrl(thread: Recipient) {
+ if (!thread.isOpenGroupRecipient) { return }
+
+ val threadId = threadDb.getThreadIdIfExistsFor(thread) ?: return
+ val openGroup = lokiThreadDb.getOpenGroupChat(threadId) ?: return
+
+ val clip = ClipData.newPlainText("Community URL", openGroup.joinURL)
+ val manager = getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
+ manager.setPrimaryClip(clip)
+ Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
+ }
+
override fun showExpirationSettings(thread: Recipient) {
if (thread.isClosedGroupRecipient) {
val group = groupDb.getGroup(thread.address.toGroupString()).orNull()
@@ -977,7 +1044,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
.setMessage(message)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.ConversationActivity_unblock) { _, _ ->
- viewModel.unblock()
+ viewModel.unblock(this@ConversationActivityV2)
}.show()
}
@@ -1038,33 +1105,37 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
Log.e("Loki", "Failed to show emoji picker", e)
return
}
+
+ val binding = binding ?: return
+
+ emojiPickerVisible = true
ViewUtil.hideKeyboard(this, visibleMessageView)
- binding?.reactionsShade?.isVisible = true
- showOrHidScrollToBottomButton(false)
- binding?.conversationRecyclerView?.suppressLayout(true)
+ binding.reactionsShade.isVisible = true
+ binding.scrollToBottomButton.isVisible = false
+ binding.conversationRecyclerView.suppressLayout(true)
reactionDelegate.setOnActionSelectedListener(ReactionsToolbarListener(message))
reactionDelegate.setOnHideListener(object: ConversationReactionOverlay.OnHideListener {
override fun startHide() {
- binding?.reactionsShade?.let {
+ emojiPickerVisible = false
+ binding.reactionsShade.let {
ViewUtil.fadeOut(it, resources.getInteger(R.integer.reaction_scrubber_hide_duration), View.GONE)
}
- showOrHidScrollToBottomButton(true)
+ showScrollToBottomButtonIfApplicable()
}
override fun onHide() {
- binding?.conversationRecyclerView?.suppressLayout(false)
+ binding.conversationRecyclerView.suppressLayout(false)
WindowUtil.setLightStatusBarFromTheme(this@ConversationActivityV2);
WindowUtil.setLightNavigationBarFromTheme(this@ConversationActivityV2);
}
})
- val contentBounds = Rect()
- visibleMessageView.messageContentView.getGlobalVisibleRect(contentBounds)
+ val topLeft = intArrayOf(0, 0).also { visibleMessageView.messageContentView.getLocationInWindow(it) }
val selectedConversationModel = SelectedConversationModel(
messageContentBitmap,
- contentBounds.left.toFloat(),
- contentBounds.top.toFloat(),
+ topLeft[0].toFloat(),
+ topLeft[1].toFloat(),
visibleMessageView.messageContentView.width,
message.isOutgoing,
visibleMessageView.messageContentView
@@ -1090,7 +1161,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// Create the message
val recipient = viewModel.recipient ?: return
val reactionMessage = VisibleMessage()
- val emojiTimestamp = System.currentTimeMillis() + SnodeAPI.clockOffset
+ val emojiTimestamp = SnodeAPI.nowWithOffset
reactionMessage.sentTimestamp = emojiTimestamp
val author = textSecurePreferences.getLocalNumber()!!
// Put the message in the database
@@ -1123,7 +1194,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun sendEmojiRemoval(emoji: String, originalMessage: MessageRecord) {
val recipient = viewModel.recipient ?: return
val message = VisibleMessage()
- val emojiTimestamp = System.currentTimeMillis() + SnodeAPI.clockOffset
+ val emojiTimestamp = SnodeAPI.nowWithOffset
message.sentTimestamp = emojiTimestamp
val author = textSecurePreferences.getLocalNumber()!!
reactionDb.deleteReaction(emoji, MessageId(originalMessage.id, originalMessage.isMms), author, false)
@@ -1314,7 +1385,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
override fun sendMessage() {
val recipient = viewModel.recipient ?: return
if (recipient.isContactRecipient && recipient.isBlocked) {
- BlockedDialog(recipient).show(supportFragmentManager, "Blocked Dialog")
+ BlockedDialog(recipient, this).show(supportFragmentManager, "Blocked Dialog")
return
}
val binding = binding ?: return
@@ -1352,7 +1423,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
// Create the message
val message = VisibleMessage()
- message.sentTimestamp = System.currentTimeMillis() + SnodeAPI.clockOffset
+ message.sentTimestamp = SnodeAPI.nowWithOffset
message.text = text
val expiresInMillis = (viewModel.expirationConfiguration?.durationSeconds ?: 0) * 1000L
val expireStartedAt = if (viewModel.expirationConfiguration?.expirationType == ExpirationType.DELETE_AFTER_SEND) {
@@ -1379,9 +1450,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val recipient = viewModel.recipient ?: return
processMessageRequestApproval()
// Create the message
- val sentTimestampMs = System.currentTimeMillis() + SnodeAPI.clockOffset
val message = VisibleMessage()
- message.sentTimestamp = sentTimestampMs
+ message.sentTimestamp = SnodeAPI.nowWithOffset
message.text = body
val quote = quotedMessage?.let {
val quotedAttachments = (it as? MmsMessageRecord)?.slideDeck?.asAttachments() ?: listOf()
@@ -1425,16 +1495,16 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val hasSeenGIFMetaDataWarning: Boolean = textSecurePreferences.hasSeenGIFMetaDataWarning()
if (!hasSeenGIFMetaDataWarning) {
val builder = AlertDialog.Builder(this)
- builder.setTitle("Search GIFs?")
- builder.setMessage("You will not have full metadata protection when sending GIFs.")
- builder.setPositiveButton("OK") { dialog: DialogInterface, _: Int ->
+ builder.setTitle(R.string.giphy_permission_title)
+ builder.setMessage(R.string.giphy_permission_message)
+ builder.setPositiveButton(R.string.continue_2) { dialog: DialogInterface, _: Int ->
textSecurePreferences.setHasSeenGIFMetaDataWarning()
AttachmentManager.selectGif(this, PICK_GIF)
dialog.dismiss()
}
- builder.setNegativeButton(
- "Cancel"
- ) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
+ builder.setNegativeButton(R.string.cancel) { dialog: DialogInterface, _: Int ->
+ dialog.dismiss()
+ }
builder.create().show()
} else {
AttachmentManager.selectGif(this, PICK_GIF)
@@ -1540,7 +1610,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
showVoiceMessageUI()
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
audioRecorder.startRecording()
- stopAudioHandler.postDelayed(stopVoiceMessageRecordingTask, 60000) // Limit voice messages to 1 minute each
+ stopAudioHandler.postDelayed(stopVoiceMessageRecordingTask, 300000) // Limit voice messages to 5 minute each
} else {
Permissions.with(this)
.request(Manifest.permission.RECORD_AUDIO)
@@ -1714,6 +1784,13 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
endActionMode()
}
+ override fun resyncMessage(messages: Set) {
+ messages.iterator().forEach { messageRecord ->
+ ResendMessageUtilities.resend(this, messageRecord, viewModel.blindedPublicKey, isResync = true)
+ }
+ endActionMode()
+ }
+
override fun resendMessage(messages: Set) {
messages.iterator().forEach { messageRecord ->
ResendMessageUtilities.resend(this, messageRecord, viewModel.blindedPublicKey)
@@ -1782,7 +1859,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private fun sendMediaSavedNotification() {
val recipient = viewModel.recipient ?: return
if (recipient.isGroupRecipient) { return }
- val timestamp = System.currentTimeMillis()
+ val timestamp = SnodeAPI.nowWithOffset
val kind = DataExtractionNotification.Kind.MediaSaved(timestamp)
val message = DataExtractionNotification(kind)
MessageSender.send(message, recipient.address)
@@ -1874,6 +1951,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val selectedItems = setOf(message)
when (action) {
ConversationReactionOverlay.Action.REPLY -> reply(selectedItems)
+ ConversationReactionOverlay.Action.RESYNC -> resyncMessage(selectedItems)
ConversationReactionOverlay.Action.RESEND -> resendMessage(selectedItems)
ConversationReactionOverlay.Action.DOWNLOAD -> saveAttachment(selectedItems)
ConversationReactionOverlay.Action.COPY_MESSAGE -> copyMessages(selectedItems)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt
index 17a47a843f..85d3c8e6de 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt
@@ -39,10 +39,10 @@ class ConversationAdapter(
private val onItemSwipeToReply: (MessageRecord, Int) -> Unit,
private val onItemLongPress: (MessageRecord, Int, VisibleMessageView) -> Unit,
private val onDeselect: (MessageRecord, Int) -> Unit,
+ private val onAttachmentNeedsDownload: (Long, Long) -> Unit,
private val glide: GlideRequests,
lifecycleCoroutineScope: LifecycleCoroutineScope
-)
- : CursorRecyclerViewAdapter(context, cursor) {
+) : CursorRecyclerViewAdapter(context, cursor) {
private val messageDB by lazy { DatabaseComponent.get(context).mmsSmsDatabase() }
private val contactDB by lazy { DatabaseComponent.get(context).sessionContactDatabase() }
var selectedItems = mutableSetOf()
@@ -120,7 +120,18 @@ class ConversationAdapter(
}
val contact = contactCache[senderIdHash]
- visibleMessageView.bind(message, messageBefore, getMessageAfter(position, cursor), glide, searchQuery, contact, senderId, visibleMessageViewDelegate)
+ visibleMessageView.bind(
+ message,
+ messageBefore,
+ getMessageAfter(position, cursor),
+ glide,
+ searchQuery,
+ contact,
+ senderId,
+ visibleMessageViewDelegate,
+ onAttachmentNeedsDownload
+ )
+
if (!message.isDeleted) {
visibleMessageView.onPress = { event -> onItemPress(message, viewHolder.adapterPosition, visibleMessageView, event) }
visibleMessageView.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) }
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java
index 995dcda2f2..20462bef34 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.java
@@ -81,6 +81,8 @@ public final class ConversationReactionOverlay extends FrameLayout {
private View dropdownAnchor;
private LinearLayout conversationItem;
+ private View conversationBubble;
+ private TextView conversationTimestamp;
private View backgroundView;
private ConstraintLayout foregroundView;
private EmojiImageView[] emojiViews;
@@ -116,6 +118,8 @@ public final class ConversationReactionOverlay extends FrameLayout {
dropdownAnchor = findViewById(R.id.dropdown_anchor);
conversationItem = findViewById(R.id.conversation_item);
+ conversationBubble = conversationItem.findViewById(R.id.conversation_item_bubble);
+ conversationTimestamp = conversationItem.findViewById(R.id.conversation_item_timestamp);
backgroundView = findViewById(R.id.conversation_reaction_scrubber_background);
foregroundView = findViewById(R.id.conversation_reaction_scrubber_foreground);
@@ -165,10 +169,8 @@ public final class ConversationReactionOverlay extends FrameLayout {
Bitmap conversationItemSnapshot = selectedConversationModel.getBitmap();
- View conversationBubble = conversationItem.findViewById(R.id.conversation_item_bubble);
conversationBubble.setLayoutParams(new LinearLayout.LayoutParams(conversationItemSnapshot.getWidth(), conversationItemSnapshot.getHeight()));
conversationBubble.setBackground(new BitmapDrawable(getResources(), conversationItemSnapshot));
- TextView conversationTimestamp = conversationItem.findViewById(R.id.conversation_item_timestamp);
conversationTimestamp.setText(DateUtils.getDisplayFormattedTimeSpanString(getContext(), Locale.getDefault(), messageRecord.getTimestamp()));
updateConversationTimestamp(messageRecord);
@@ -190,12 +192,8 @@ public final class ConversationReactionOverlay extends FrameLayout {
}
private void updateConversationTimestamp(MessageRecord message) {
- View bubble = conversationItem.findViewById(R.id.conversation_item_bubble);
- View timestamp = conversationItem.findViewById(R.id.conversation_item_timestamp);
- conversationItem.removeAllViewsInLayout();
- conversationItem.addView(message.isOutgoing() ? timestamp : bubble);
- conversationItem.addView(message.isOutgoing() ? bubble : timestamp);
- conversationItem.requestLayout();
+ if (message.isOutgoing()) conversationBubble.bringToFront();
+ else conversationTimestamp.bringToFront();
}
private void showAfterLayout(@NonNull MessageRecord messageRecord,
@@ -203,10 +201,11 @@ public final class ConversationReactionOverlay extends FrameLayout {
boolean isMessageOnLeft) {
contextMenu = new ConversationContextMenu(dropdownAnchor, getMenuActionItems(messageRecord));
- float itemX = isMessageOnLeft ? scrubberHorizontalMargin :
+ float endX = isMessageOnLeft ? scrubberHorizontalMargin :
selectedConversationModel.getBubbleX() - conversationItem.getWidth() + selectedConversationModel.getBubbleWidth();
- conversationItem.setX(itemX);
- conversationItem.setY(selectedConversationModel.getBubbleY() - statusBarHeight);
+ float endY = selectedConversationModel.getBubbleY() - statusBarHeight;
+ conversationItem.setX(endX);
+ conversationItem.setY(endY);
Bitmap conversationItemSnapshot = selectedConversationModel.getBitmap();
boolean isWideLayout = contextMenu.getMaxWidth() + scrubberWidth < getWidth();
@@ -214,8 +213,6 @@ public final class ConversationReactionOverlay extends FrameLayout {
int overlayHeight = getHeight();
int bubbleWidth = selectedConversationModel.getBubbleWidth();
- float endX = itemX;
- float endY = conversationItem.getY();
float endApparentTop = endY;
float endScale = 1f;
@@ -265,9 +262,7 @@ public final class ConversationReactionOverlay extends FrameLayout {
}
} else {
endY = overlayHeight - contextMenu.getMaxHeight() - menuPadding - conversationItemSnapshot.getHeight();
-
- float contextMenuTop = endY + conversationItemSnapshot.getHeight();
- reactionBarBackgroundY = getReactionBarOffsetForTouch(selectedConversationModel.getBubbleY(), contextMenuTop, menuPadding, reactionBarOffset, reactionBarHeight, reactionBarTopPadding, endY);
+ reactionBarBackgroundY = endY - reactionBarHeight - menuPadding;
}
endApparentTop = endY;
@@ -354,11 +349,14 @@ public final class ConversationReactionOverlay extends FrameLayout {
int revealDuration = getContext().getResources().getInteger(R.integer.reaction_scrubber_reveal_duration);
+ conversationBubble.animate()
+ .scaleX(endScale)
+ .scaleY(endScale)
+ .setDuration(revealDuration);
+
conversationItem.animate()
.x(endX)
.y(endY)
- .scaleX(endScale)
- .scaleY(endScale)
.setDuration(revealDuration);
}
@@ -660,10 +658,15 @@ public final class ConversationReactionOverlay extends FrameLayout {
String userPublicKey = TextSecurePreferences.getLocalNumber(getContext());
// Select message
- items.add(new ActionItem(R.attr.menu_select_icon, getContext().getResources().getString(R.string.conversation_context__menu_select), () -> handleActionItemClicked(Action.SELECT)));
+ items.add(new ActionItem(R.attr.menu_select_icon, getContext().getResources().getString(R.string.conversation_context__menu_select), () -> handleActionItemClicked(Action.SELECT),
+ getContext().getResources().getString(R.string.AccessibilityId_select)));
// Reply
- if (!message.isPending() && !message.isFailed()) {
- items.add(new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_reply), () -> handleActionItemClicked(Action.REPLY)));
+ boolean canWrite = openGroup == null || openGroup.getCanWrite();
+ if (canWrite && !message.isPending() && !message.isFailed()) {
+ items.add(
+ new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_reply), () -> handleActionItemClicked(Action.REPLY),
+ getContext().getResources().getString(R.string.AccessibilityId_reply_message))
+ );
}
// Copy message text
if (!containsControlMessage && hasText) {
@@ -671,11 +674,17 @@ public final class ConversationReactionOverlay extends FrameLayout {
}
// Copy Session ID
if (recipient.isGroupRecipient() && !recipient.isOpenGroupRecipient() && !message.getRecipient().getAddress().toString().equals(userPublicKey)) {
- items.add(new ActionItem(R.attr.menu_copy_icon, getContext().getResources().getString(R.string.activity_conversation_menu_copy_session_id), () -> handleActionItemClicked(Action.COPY_SESSION_ID)));
+ items.add(new ActionItem(
+ R.attr.menu_copy_icon, getContext().getResources().getString(R.string.activity_conversation_menu_copy_session_id), () -> handleActionItemClicked(Action.COPY_SESSION_ID))
+ );
}
// Delete message
if (ConversationMenuItemHelper.userCanDeleteSelectedItems(getContext(), message, openGroup, userPublicKey, blindedPublicKey)) {
- items.add(new ActionItem(R.attr.menu_trash_icon, getContext().getResources().getString(R.string.delete), () -> handleActionItemClicked(Action.DELETE)));
+ items.add(new ActionItem(R.attr.menu_trash_icon, getContext().getResources().getString(R.string.delete),
+ () -> handleActionItemClicked(Action.DELETE),
+ getContext().getResources().getString(R.string.AccessibilityId_delete_message)
+ )
+ );
}
// Ban user
if (ConversationMenuItemHelper.userCanBanSelectedUsers(getContext(), message, openGroup, userPublicKey, blindedPublicKey)) {
@@ -693,9 +702,15 @@ public final class ConversationReactionOverlay extends FrameLayout {
if (message.isFailed()) {
items.add(new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_resend_message), () -> handleActionItemClicked(Action.RESEND)));
}
+ // Resync
+ if (message.isSyncFailed()) {
+ items.add(new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_resync_message), () -> handleActionItemClicked(Action.RESYNC)));
+ }
// Save media
if (message.isMms() && ((MediaMmsMessageRecord)message).containsMediaSlide()) {
- items.add(new ActionItem(R.attr.menu_save_icon, getContext().getResources().getString(R.string.conversation_context_image__save_attachment), () -> handleActionItemClicked(Action.DOWNLOAD)));
+ items.add(new ActionItem(R.attr.menu_save_icon, getContext().getResources().getString(R.string.conversation_context_image__save_attachment), () -> handleActionItemClicked(Action.DOWNLOAD),
+ getContext().getResources().getString(R.string.AccessibilityId_save_attachment))
+ );
}
backgroundView.setVisibility(View.VISIBLE);
@@ -876,6 +891,7 @@ public final class ConversationReactionOverlay extends FrameLayout {
public enum Action {
REPLY,
RESEND,
+ RESYNC,
DOWNLOAD,
COPY_MESSAGE,
COPY_SESSION_ID,
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt
index b863823dcf..a87d3b2067 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt
@@ -1,11 +1,15 @@
package org.thoughtcrime.securesms.conversation.v2
+import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import com.goterl.lazysodium.utils.KeyPair
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
@@ -21,6 +25,7 @@ import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.repository.ConversationRepository
+import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import java.util.UUID
class ConversationViewModel(
@@ -30,17 +35,26 @@ class ConversationViewModel(
private val storage: Storage
) : ViewModel() {
+ val showSendAfterApprovalText: Boolean
+ get() = recipient?.run { isContactRecipient && !isLocalNumber && !hasApprovedMe() } ?: false
+
private val _uiState = MutableStateFlow(ConversationUiState())
val uiState: StateFlow = _uiState
+ private var _recipient: RetrieveOnce = RetrieveOnce {
+ repository.maybeGetRecipientForThreadId(threadId)
+ }
val expirationConfiguration: ExpirationConfiguration?
get() = storage.getExpirationConfiguration(threadId)
val recipient: Recipient?
- get() = repository.maybeGetRecipientForThreadId(threadId)
+ get() = _recipient.value
+ private var _openGroup: RetrieveOnce = RetrieveOnce {
+ storage.getOpenGroup(threadId)
+ }
val openGroup: OpenGroup?
- get() = storage.getOpenGroup(threadId)
+ get() = _openGroup.value
val serverCapabilities: List
get() = openGroup?.let { storage.getServerCapabilities(it.server) } ?: listOf()
@@ -52,28 +66,46 @@ class ConversationViewModel(
}
fun saveDraft(text: String) {
- repository.saveDraft(threadId, text)
+ GlobalScope.launch(Dispatchers.IO) {
+ repository.saveDraft(threadId, text)
+ }
}
fun getDraft(): String? {
- return repository.getDraft(threadId)
+ val draft: String? = repository.getDraft(threadId)
+
+ viewModelScope.launch(Dispatchers.IO) {
+ repository.clearDrafts(threadId)
+ }
+
+ return draft
}
fun inviteContacts(contacts: List) {
repository.inviteContacts(threadId, contacts)
}
- fun block() {
+ fun block(context: Context) {
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for block action")
if (recipient.isContactRecipient) {
repository.setBlocked(recipient, true)
+
+ // TODO: Remove in UserConfig branch
+ GlobalScope.launch(Dispatchers.IO) {
+ ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
+ }
}
}
- fun unblock() {
+ fun unblock(context: Context) {
val recipient = recipient ?: return Log.w("Loki", "Recipient was null for unblock action")
if (recipient.isContactRecipient) {
repository.setBlocked(recipient, false)
+
+ // TODO: Remove in UserConfig branch
+ GlobalScope.launch(Dispatchers.IO) {
+ ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
+ }
}
}
@@ -164,6 +196,10 @@ class ConversationViewModel(
return repository.hasReceived(threadId)
}
+ fun updateRecipient() {
+ _recipient.updateTo(repository.maybeGetRecipientForThreadId(threadId))
+ }
+
@dagger.assisted.AssistedFactory
interface AssistedFactory {
fun create(threadId: Long, edKeyPair: KeyPair?): Factory
@@ -189,3 +225,19 @@ data class ConversationUiState(
val uiMessages: List = emptyList(),
val isMessageRequestAccepted: Boolean? = null
)
+
+data class RetrieveOnce(val retrieval: () -> T?) {
+ private var triedToRetrieve: Boolean = false
+ private var _value: T? = null
+
+ val value: T?
+ get() {
+ if (triedToRetrieve) { return _value }
+
+ triedToRetrieve = true
+ _value = retrieval()
+ return _value
+ }
+
+ fun updateTo(value: T?) { _value = value }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt
index 66f33cf299..b6212b8542 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/DeleteOptionsBottomSheet.kt
@@ -69,7 +69,6 @@ class DeleteOptionsBottomSheet : BottomSheetDialogFragment(), View.OnClickListen
override fun onStart() {
super.onStart()
val window = dialog?.window ?: return
- val isLightMode = UiModeUtilities.isDayUiMode(requireContext())
- window.setDimAmount(if (isLightMode) 0.1f else 0.75f)
+ window.setDimAmount(0.6f)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt
index 104c9851b0..0938b21dd9 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt
@@ -10,6 +10,7 @@ import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.messaging.utilities.SessionId
import org.session.libsession.messaging.utilities.SodiumUtilities
+import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.ExpirationUtil
import org.session.libsession.utilities.TextSecurePreferences
@@ -88,7 +89,7 @@ class MessageDetailActivity: PassphraseRequiredActionBarActivity() {
binding.expiresContainer.visibility = View.GONE
} else {
binding.expiresContainer.visibility = View.VISIBLE
- val elapsed = System.currentTimeMillis() - messageRecord!!.expireStarted
+ val elapsed = SnodeAPI.nowWithOffset - messageRecord!!.expireStarted
val remaining = messageRecord!!.expiresIn - elapsed
val duration = ExpirationUtil.getExpirationDisplayValue(this, Math.max((remaining / 1000).toInt(), 1))
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt
index 28c86b3311..54deea1c8d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ModalUrlBottomSheet.kt
@@ -60,8 +60,7 @@ class ModalUrlBottomSheet(private val url: String): BottomSheetDialogFragment(),
override fun onStart() {
super.onStart()
val window = dialog?.window ?: return
- val isLightMode = UiModeUtilities.isDayUiMode(requireContext())
- window.setDimAmount(if (isLightMode) 0.1f else 0.75f)
+ window.setDimAmount(0.6f)
}
override fun onClick(v: View?) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java
index 4bff4e76aa..6083bb267c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/WindowUtil.java
@@ -38,14 +38,10 @@ public final class WindowUtil {
}
public static void setNavigationBarColor(@NonNull Window window, @ColorInt int color) {
- if (Build.VERSION.SDK_INT < 21) return;
-
window.setNavigationBarColor(color);
}
public static void setLightStatusBarFromTheme(@NonNull Activity activity) {
- if (Build.VERSION.SDK_INT < 23) return;
-
final boolean isLightStatusBar = ThemeUtil.getThemedBoolean(activity, android.R.attr.windowLightStatusBar);
if (isLightStatusBar) setLightStatusBar(activity.getWindow());
@@ -53,20 +49,14 @@ public final class WindowUtil {
}
public static void clearLightStatusBar(@NonNull Window window) {
- if (Build.VERSION.SDK_INT < 23) return;
-
clearSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
public static void setLightStatusBar(@NonNull Window window) {
- if (Build.VERSION.SDK_INT < 23) return;
-
setSystemUiFlags(window, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
public static void setStatusBarColor(@NonNull Window window, @ColorInt int color) {
- if (Build.VERSION.SDK_INT < 21) return;
-
window.setStatusBarColor(color);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt
index 8f0ddd8bef..330534e232 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt
@@ -8,53 +8,39 @@ import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.ViewGroup
import android.widget.FrameLayout
+import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.view.children
import androidx.core.view.isVisible
import network.loki.messenger.R
import network.loki.messenger.databinding.AlbumThumbnailViewBinding
-import org.session.libsession.messaging.jobs.AttachmentDownloadJob
-import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.MediaPreviewActivity
import org.thoughtcrime.securesms.components.CornerMask
-import org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
+import org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailView
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.mms.Slide
import org.thoughtcrime.securesms.util.ActivityDispatcher
-class AlbumThumbnailView : FrameLayout {
-
- private lateinit var binding: AlbumThumbnailViewBinding
-
+class AlbumThumbnailView : RelativeLayout {
companion object {
const val MAX_ALBUM_DISPLAY_SIZE = 3
}
+ private val binding: AlbumThumbnailViewBinding by lazy { AlbumThumbnailViewBinding.bind(this) }
+
// region Lifecycle
- constructor(context: Context) : super(context) {
- initialize()
- }
-
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- initialize()
- }
-
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
- initialize()
- }
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private val cornerMask by lazy { CornerMask(this) }
private var slides: List = listOf()
private var slideSize: Int = 0
- private fun initialize() {
- binding = AlbumThumbnailViewBinding.inflate(LayoutInflater.from(context), this, true)
- }
-
override fun dispatchDraw(canvas: Canvas?) {
super.dispatchDraw(canvas)
cornerMask.mask(canvas)
@@ -63,26 +49,25 @@ class AlbumThumbnailView : FrameLayout {
// region Interaction
- fun calculateHitObject(event: MotionEvent, mms: MmsMessageRecord, threadRecipient: Recipient) {
+ fun calculateHitObject(event: MotionEvent, mms: MmsMessageRecord, threadRecipient: Recipient, onAttachmentNeedsDownload: (Long, Long) -> Unit) {
val rawXInt = event.rawX.toInt()
val rawYInt = event.rawY.toInt()
val eventRect = Rect(rawXInt, rawYInt, rawXInt, rawYInt)
val testRect = Rect()
// test each album child
- binding.albumCellContainer.findViewById(R.id.album_thumbnail_root)?.children?.forEachIndexed { index, child ->
+ binding.albumCellContainer.findViewById(R.id.album_thumbnail_root)?.children?.forEachIndexed forEach@{ index, child ->
child.getGlobalVisibleRect(testRect)
if (testRect.contains(eventRect)) {
// hit intersects with this particular child
- val slide = slides.getOrNull(index) ?: return
+ val slide = slides.getOrNull(index) ?: return@forEach
// only open to downloaded images
if (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED) {
- // restart download here
+ // Restart download here (on IO thread)
(slide.asAttachment() as? DatabaseAttachment)?.let { attachment ->
- val attachmentId = attachment.attachmentId.rowId
- JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mms.getId()))
+ onAttachmentNeedsDownload(attachment.attachmentId.rowId, mms.getId())
}
}
- if (slide.isInProgress) return
+ if (slide.isInProgress) return@forEach
ActivityDispatcher.get(context)?.dispatchIntent { context ->
MediaPreviewActivity.getPreviewIntent(context, slide, mms, threadRecipient)
@@ -133,7 +118,7 @@ class AlbumThumbnailView : FrameLayout {
else -> R.layout.album_thumbnail_3 // three stacked with additional text
}
- fun getThumbnailView(position: Int): KThumbnailView = when (position) {
+ fun getThumbnailView(position: Int): ThumbnailView = when (position) {
0 -> binding.albumCellContainer.findViewById(R.id.albumCellContainer).findViewById(R.id.album_cell_1)
1 -> binding.albumCellContainer.findViewById(R.id.albumCellContainer).findViewById(R.id.album_cell_2)
2 -> binding.albumCellContainer.findViewById(R.id.albumCellContainer).findViewById(R.id.album_cell_3)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt
index c1fce3f50b..66164f100f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/LinkPreviewDraftView.kt
@@ -23,7 +23,7 @@ class LinkPreviewDraftView : LinearLayout {
// Start out with the loader showing and the content view hidden
binding = ViewLinkPreviewDraftBinding.inflate(LayoutInflater.from(context), this, true)
binding.linkPreviewDraftContainer.isVisible = false
- binding.thumbnailImageView.clipToOutline = true
+ binding.thumbnailImageView.root.clipToOutline = true
binding.linkPreviewDraftCancelButton.setOnClickListener { cancel() }
}
@@ -31,10 +31,10 @@ class LinkPreviewDraftView : LinearLayout {
// Hide the loader and show the content view
binding.linkPreviewDraftContainer.isVisible = true
binding.linkPreviewDraftLoader.isVisible = false
- binding.thumbnailImageView.radius = toPx(4, resources)
+ binding.thumbnailImageView.root.radius = toPx(4, resources)
if (linkPreview.getThumbnail().isPresent) {
// This internally fetches the thumbnail
- binding.thumbnailImageView.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), false, false)
+ binding.thumbnailImageView.root.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), false, null)
}
binding.linkPreviewDraftTitleTextView.text = linkPreview.title
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorView.java
deleted file mode 100644
index 826cfe7b3a..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorView.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.thoughtcrime.securesms.conversation.v2.components;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import androidx.annotation.Nullable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import network.loki.messenger.R;
-
-public class TypingIndicatorView extends LinearLayout {
- private boolean isActive;
- private long startTime;
-
- private static final long CYCLE_DURATION = 1500;
- private static final long DOT_DURATION = 600;
- private static final float MIN_ALPHA = 0.4f;
- private static final float MIN_SCALE = 0.75f;
-
- private View dot1;
- private View dot2;
- private View dot3;
-
- public TypingIndicatorView(Context context) {
- super(context);
- initialize(null);
- }
-
- public TypingIndicatorView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- initialize(attrs);
- }
-
- private void initialize(@Nullable AttributeSet attrs) {
- inflate(getContext(), R.layout.view_typing_indicator, this);
-
- setWillNotDraw(false);
-
- dot1 = findViewById(R.id.typing_dot1);
- dot2 = findViewById(R.id.typing_dot2);
- dot3 = findViewById(R.id.typing_dot3);
-
- if (attrs != null) {
- TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.TypingIndicatorView, 0, 0);
- int tint = typedArray.getColor(R.styleable.TypingIndicatorView_typingIndicator_tint, Color.WHITE);
- typedArray.recycle();
-
- dot1.getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY);
- dot2.getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY);
- dot3.getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY);
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (!isActive) {
- super.onDraw(canvas);
- return;
- }
-
- long timeInCycle = (System.currentTimeMillis() - startTime) % CYCLE_DURATION;
-
- render(dot1, timeInCycle, 0);
- render(dot2, timeInCycle, 150);
- render(dot3, timeInCycle, 300);
-
- super.onDraw(canvas);
- postInvalidate();
- }
-
- private void render(View dot, long timeInCycle, long start) {
- long end = start + DOT_DURATION;
- long peak = start + (DOT_DURATION / 2);
-
- if (timeInCycle < start || timeInCycle > end) {
- renderDefault(dot);
- } else if (timeInCycle < peak) {
- renderFadeIn(dot, timeInCycle, start);
- } else {
- renderFadeOut(dot, timeInCycle, peak);
- }
- }
-
- private void renderDefault(View dot) {
- dot.setAlpha(MIN_ALPHA);
- dot.setScaleX(MIN_SCALE);
- dot.setScaleY(MIN_SCALE);
- }
-
- private void renderFadeIn(View dot, long timeInCycle, long fadeInStart) {
- float percent = (float) (timeInCycle - fadeInStart) / 300;
- dot.setAlpha(MIN_ALPHA + (1 - MIN_ALPHA) * percent);
- dot.setScaleX(MIN_SCALE + (1 - MIN_SCALE) * percent);
- dot.setScaleY(MIN_SCALE + (1 - MIN_SCALE) * percent);
- }
-
- private void renderFadeOut(View dot, long timeInCycle, long fadeOutStart) {
- float percent = (float) (timeInCycle - fadeOutStart) / 300;
- dot.setAlpha(1 - (1 - MIN_ALPHA) * percent);
- dot.setScaleX(1 - (1 - MIN_SCALE) * percent);
- dot.setScaleY(1 - (1 - MIN_SCALE) * percent);
- }
-
- public void startAnimation() {
- isActive = true;
- startTime = System.currentTimeMillis();
-
- postInvalidate();
- }
-
- public void stopAnimation() {
- isActive = false;
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorView.kt
new file mode 100644
index 0000000000..d1310bffba
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorView.kt
@@ -0,0 +1,105 @@
+package org.thoughtcrime.securesms.conversation.v2.components
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.PorterDuff
+import android.util.AttributeSet
+import android.view.View
+import android.widget.LinearLayout
+import network.loki.messenger.R
+import network.loki.messenger.databinding.ViewTypingIndicatorBinding
+
+class TypingIndicatorView : LinearLayout {
+ companion object {
+ private const val CYCLE_DURATION: Long = 1500
+ private const val DOT_DURATION: Long = 600
+ private const val MIN_ALPHA = 0.4f
+ private const val MIN_SCALE = 0.75f
+ }
+
+ private val binding: ViewTypingIndicatorBinding by lazy {
+ val binding = ViewTypingIndicatorBinding.bind(this)
+
+ if (tint != -1) {
+ binding.typingDot1.getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY)
+ binding.typingDot2.getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY)
+ binding.typingDot3.getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY)
+ }
+
+ return@lazy binding
+ }
+
+ private var isActive = false
+ private var startTime: Long = 0
+ private var tint: Int = -1
+
+ constructor(context: Context) : super(context) { initialize(null) }
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize(attrs) }
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize(attrs) }
+
+ private fun initialize(attrs: AttributeSet?) {
+ setWillNotDraw(false)
+
+ if (attrs != null) {
+ val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.TypingIndicatorView, 0, 0)
+ this.tint = typedArray.getColor(R.styleable.TypingIndicatorView_typingIndicator_tint, Color.WHITE)
+ typedArray.recycle()
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ if (!isActive) {
+ super.onDraw(canvas)
+ return
+ }
+ val timeInCycle = (System.currentTimeMillis() - startTime) % CYCLE_DURATION
+ render(binding.typingDot1, timeInCycle, 0)
+ render(binding.typingDot2, timeInCycle, 150)
+ render(binding.typingDot3, timeInCycle, 300)
+ super.onDraw(canvas)
+ postInvalidate()
+ }
+
+ private fun render(dot: View?, timeInCycle: Long, start: Long) {
+ val end = start + DOT_DURATION
+ val peak = start + DOT_DURATION / 2
+ if (timeInCycle < start || timeInCycle > end) {
+ renderDefault(dot)
+ } else if (timeInCycle < peak) {
+ renderFadeIn(dot, timeInCycle, start)
+ } else {
+ renderFadeOut(dot, timeInCycle, peak)
+ }
+ }
+
+ private fun renderDefault(dot: View?) {
+ dot!!.alpha = MIN_ALPHA
+ dot.scaleX = MIN_SCALE
+ dot.scaleY = MIN_SCALE
+ }
+
+ private fun renderFadeIn(dot: View?, timeInCycle: Long, fadeInStart: Long) {
+ val percent = (timeInCycle - fadeInStart).toFloat() / 300
+ dot!!.alpha = MIN_ALPHA + (1 - MIN_ALPHA) * percent
+ dot.scaleX = MIN_SCALE + (1 - MIN_SCALE) * percent
+ dot.scaleY = MIN_SCALE + (1 - MIN_SCALE) * percent
+ }
+
+ private fun renderFadeOut(dot: View?, timeInCycle: Long, fadeOutStart: Long) {
+ val percent = (timeInCycle - fadeOutStart).toFloat() / 300
+ dot!!.alpha = 1 - (1 - MIN_ALPHA) * percent
+ dot.scaleX = 1 - (1 - MIN_SCALE) * percent
+ dot.scaleY = 1 - (1 - MIN_SCALE) * percent
+ }
+
+ fun startAnimation() {
+ isActive = true
+ startTime = System.currentTimeMillis()
+ postInvalidate()
+ }
+
+ fun stopAnimation() {
+ isActive = false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorViewContainer.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorViewContainer.kt
index 768d49146e..3077d227e3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorViewContainer.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/TypingIndicatorViewContainer.kt
@@ -19,7 +19,7 @@ class TypingIndicatorViewContainer : LinearLayout {
}
fun setTypists(typists: List) {
- if (typists.isEmpty()) { binding.typingIndicator.stopAnimation(); return }
- binding.typingIndicator.startAnimation()
+ if (typists.isEmpty()) { binding.typingIndicator.root.stopAnimation(); return }
+ binding.typingIndicator.root.startAnimation()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/BlockedDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/BlockedDialog.kt
index 39ca7c6913..bcabca98f1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/BlockedDialog.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/BlockedDialog.kt
@@ -1,20 +1,25 @@
package org.thoughtcrime.securesms.conversation.v2.dialogs
+import android.content.Context
import android.graphics.Typeface
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
import network.loki.messenger.R
import network.loki.messenger.databinding.DialogBlockedBinding
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
+import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
/** Shown upon sending a message to a user that's blocked. */
-class BlockedDialog(private val recipient: Recipient) : BaseDialog() {
+class BlockedDialog(private val recipient: Recipient, private val context: Context) : BaseDialog() {
override fun setContentView(builder: AlertDialog.Builder) {
val binding = DialogBlockedBinding.inflate(LayoutInflater.from(requireContext()))
@@ -37,5 +42,10 @@ class BlockedDialog(private val recipient: Recipient) : BaseDialog() {
private fun unblock() {
DatabaseComponent.get(requireContext()).recipientDatabase().setBlocked(recipient, false)
dismiss()
+
+ // TODO: Remove in UserConfig branch
+ GlobalScope.launch(Dispatchers.IO) {
+ ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
index 7ac70b843a..73e2d571c0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
@@ -57,9 +57,9 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
val attachmentButtonsContainerHeight: Int
get() = binding.attachmentsButtonContainer.height
- private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24) }
- private val microphoneButton by lazy { InputBarButton(context, R.drawable.ic_microphone) }
- private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true) }
+ private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24).apply { contentDescription = context.getString(R.string.AccessibilityId_attachments_button)} }
+ private val microphoneButton by lazy { InputBarButton(context, R.drawable.ic_microphone).apply { contentDescription = context.getString(R.string.AccessibilityId_microphone_button)} }
+ private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true).apply { contentDescription = context.getString(R.string.AccessibilityId_send_message_button)} }
// region Lifecycle
constructor(context: Context) : super(context) { initialize() }
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt
index 401ccaa3c2..e62f7f8f85 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt
@@ -7,6 +7,7 @@ import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import dagger.hilt.android.AndroidEntryPoint
+import network.loki.messenger.R
import org.session.libsession.messaging.mentions.Mention
import org.thoughtcrime.securesms.database.LokiThreadDatabase
import org.thoughtcrime.securesms.mms.GlideRequests
@@ -41,7 +42,9 @@ class MentionCandidatesView(context: Context, attrs: AttributeSet?, defStyleAttr
override fun getItem(position: Int): Mention { return candidates[position] }
override fun getView(position: Int, cellToBeReused: View?, parent: ViewGroup): View {
- val cell = cellToBeReused as MentionCandidateView? ?: MentionCandidateView(context)
+ val cell = cellToBeReused as MentionCandidateView? ?: MentionCandidateView(context).apply {
+ contentDescription = context.getString(R.string.AccessibilityId_contact)
+ }
val mentionCandidate = getItem(position)
cell.glide = glide
cell.candidate = mentionCandidate
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt
index d475a64448..f86920f90f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationActionModeCallback.kt
@@ -70,6 +70,8 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
menu.findItem(R.id.menu_message_details).isVisible = (selectedItems.size == 1 && firstMessage.isOutgoing)
// Resend
menu.findItem(R.id.menu_context_resend).isVisible = (selectedItems.size == 1 && firstMessage.isFailed)
+ // Resync
+ menu.findItem(R.id.menu_context_resync).isVisible = (selectedItems.size == 1 && firstMessage.isSyncFailed)
// Save media
menu.findItem(R.id.menu_context_save_attachment).isVisible = (selectedItems.size == 1
&& firstMessage.isMms && (firstMessage as MediaMmsMessageRecord).containsMediaSlide())
@@ -90,6 +92,7 @@ class ConversationActionModeCallback(private val adapter: ConversationAdapter, p
R.id.menu_context_ban_and_delete_all -> delegate?.banAndDeleteAll(selectedItems)
R.id.menu_context_copy -> delegate?.copyMessages(selectedItems)
R.id.menu_context_copy_public_key -> delegate?.copySessionID(selectedItems)
+ R.id.menu_context_resync -> delegate?.resyncMessage(selectedItems)
R.id.menu_context_resend -> delegate?.resendMessage(selectedItems)
R.id.menu_message_details -> delegate?.showMessageDetail(selectedItems)
R.id.menu_context_save_attachment -> delegate?.saveAttachment(selectedItems)
@@ -113,6 +116,7 @@ interface ConversationActionModeCallbackDelegate {
fun banAndDeleteAll(messages: Set)
fun copyMessages(messages: Set)
fun copySessionID(messages: Set)
+ fun resyncMessage(messages: Set)
fun resendMessage(messages: Set)
fun showMessageDetail(messages: Set)
fun saveAttachment(messages: Set)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
index 709bf4df68..68228d592a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.menus
import android.annotation.SuppressLint
import android.content.Context
+import android.content.DialogInterface
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.AsyncTask
@@ -57,6 +58,10 @@ object ConversationMenuHelper {
if (!isOpenGroup && (thread.hasApprovedMe() || thread.isClosedGroupRecipient || thread.isLocalNumber)) {
inflater.inflate(R.menu.menu_conversation_expiration, menu)
}
+ // One-on-one chat menu allows copying the session id
+ if (thread.isContactRecipient) {
+ inflater.inflate(R.menu.menu_conversation_copy_session_id, menu)
+ }
// One-on-one chat menu (options that should only be present for one-on-one chats)
if (thread.isContactRecipient) {
if (thread.isBlocked) {
@@ -132,6 +137,7 @@ object ConversationMenuHelper {
R.id.menu_block -> { block(context, thread, deleteThread = false) }
R.id.menu_block_delete -> { blockAndDelete(context, thread) }
R.id.menu_copy_session_id -> { copySessionID(context, thread) }
+ R.id.menu_copy_open_group_url -> { copyOpenGroupUrl(context, thread) }
R.id.menu_edit_group -> { editClosedGroup(context, thread) }
R.id.menu_leave_group -> { leaveClosedGroup(context, thread) }
R.id.menu_invite_to_open_group -> { inviteContacts(context, thread) }
@@ -158,7 +164,7 @@ object ConversationMenuHelper {
private fun call(context: Context, thread: Recipient) {
if (!TextSecurePreferences.isCallNotificationsEnabled(context)) {
- AlertDialog.Builder(context)
+ val dialog = AlertDialog.Builder(context)
.setTitle(R.string.ConversationActivity_call_title)
.setMessage(R.string.ConversationActivity_call_prompt)
.setPositiveButton(R.string.activity_settings_title) { _, _ ->
@@ -167,7 +173,10 @@ object ConversationMenuHelper {
}
.setNeutralButton(R.string.cancel) { d, _ ->
d.dismiss()
- }.show()
+ }.create()
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE)?.contentDescription = context.getString(R.string.AccessibilityId_settings)
+ dialog.getButton(DialogInterface.BUTTON_NEGATIVE)?.contentDescription = context.getString(R.string.AccessibilityId_cancel_button)
+ dialog.show()
return
}
@@ -248,6 +257,12 @@ object ConversationMenuHelper {
listener.copySessionID(thread.address.toString())
}
+ private fun copyOpenGroupUrl(context: Context, thread: Recipient) {
+ if (!thread.isOpenGroupRecipient) { return }
+ val listener = context as? ConversationMenuListener ?: return
+ listener.copyOpenGroupUrl(thread)
+ }
+
private fun editClosedGroup(context: Context, thread: Recipient) {
if (!thread.isClosedGroupRecipient) { return }
val intent = Intent(context, EditClosedGroupActivity::class.java)
@@ -322,6 +337,7 @@ object ConversationMenuHelper {
fun block(deleteThread: Boolean = false)
fun unblock()
fun copySessionID(sessionId: String)
+ fun copyOpenGroupUrl(thread: Recipient)
fun showExpirationSettings(thread: Recipient)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt
index a4e4a52d5b..3e370104ea 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt
@@ -31,6 +31,7 @@ class ControlMessageView : LinearLayout {
binding.dateBreakTextView.showDateBreak(message, previous)
binding.iconImageView.visibility = View.GONE
var messageBody: CharSequence = message.getDisplayBody(context)
+ binding.root.contentDescription= null
when {
message.isExpirationTimerUpdate -> {
binding.iconImageView.setImageDrawable(
@@ -46,6 +47,7 @@ class ControlMessageView : LinearLayout {
}
message.isMessageRequestResponse -> {
messageBody = context.getString(R.string.message_requests_accepted)
+ binding.root.contentDescription=context.getString(R.string.AccessibilityId_message_request_config_message)
}
message.isCallLog -> {
val drawable = when {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.java
deleted file mode 100644
index 6d16f1f421..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.java
+++ /dev/null
@@ -1,346 +0,0 @@
-package org.thoughtcrime.securesms.conversation.v2.messages;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.AttributeSet;
-import android.view.HapticFeedbackConstants;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.constraintlayout.widget.Group;
-import androidx.core.content.ContextCompat;
-
-import com.google.android.flexbox.FlexboxLayout;
-import com.google.android.flexbox.JustifyContent;
-
-import org.session.libsession.utilities.TextSecurePreferences;
-import org.session.libsession.utilities.ThemeUtil;
-import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
-import org.thoughtcrime.securesms.components.emoji.EmojiUtil;
-import org.thoughtcrime.securesms.conversation.v2.ViewUtil;
-import org.thoughtcrime.securesms.database.model.MessageId;
-import org.thoughtcrime.securesms.database.model.ReactionRecord;
-import org.thoughtcrime.securesms.util.NumberUtil;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import network.loki.messenger.R;
-
-public class EmojiReactionsView extends LinearLayout implements View.OnTouchListener {
-
- // Normally 6dp, but we have 1dp left+right margin on the pills themselves
- private final int OUTER_MARGIN = ViewUtil.dpToPx(2);
- private static final int DEFAULT_THRESHOLD = 5;
-
- private List records;
- private long messageId;
- private ViewGroup container;
- private Group showLess;
- private VisibleMessageViewDelegate delegate;
- private Handler gestureHandler = new Handler(Looper.getMainLooper());
- private Runnable pressCallback;
- private Runnable longPressCallback;
- private long onDownTimestamp = 0;
- private static long longPressDurationThreshold = 250;
- private static long maxDoubleTapInterval = 200;
- private boolean extended = false;
-
- public EmojiReactionsView(Context context) {
- super(context);
- init(null);
- }
-
- public EmojiReactionsView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- init(attrs);
- }
-
- private void init(@Nullable AttributeSet attrs) {
- inflate(getContext(), R.layout.view_emoji_reactions, this);
-
- this.container = findViewById(R.id.layout_emoji_container);
- this.showLess = findViewById(R.id.group_show_less);
-
- records = new ArrayList<>();
-
- if (attrs != null) {
- TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.EmojiReactionsView, 0, 0);
- typedArray.recycle();
- }
- }
-
- public void clear() {
- this.records.clear();
- container.removeAllViews();
- }
-
- public void setReactions(long messageId, @NonNull List records, boolean outgoing, VisibleMessageViewDelegate delegate) {
- this.delegate = delegate;
- if (records.equals(this.records)) {
- return;
- }
-
- FlexboxLayout containerLayout = (FlexboxLayout) this.container;
- containerLayout.setJustifyContent(outgoing ? JustifyContent.FLEX_END : JustifyContent.FLEX_START);
- this.records.clear();
- this.records.addAll(records);
- if (this.messageId != messageId) {
- extended = false;
- }
- this.messageId = messageId;
-
- displayReactions(extended ? Integer.MAX_VALUE : DEFAULT_THRESHOLD);
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (v.getTag() == null) return false;
-
- Reaction reaction = (Reaction) v.getTag();
- int action = event.getAction();
- if (action == MotionEvent.ACTION_DOWN) onDown(new MessageId(reaction.messageId, reaction.isMms));
- else if (action == MotionEvent.ACTION_CANCEL) removeLongPressCallback();
- else if (action == MotionEvent.ACTION_UP) onUp(reaction);
- return true;
- }
-
- private void displayReactions(int threshold) {
- String userPublicKey = TextSecurePreferences.getLocalNumber(getContext());
- List reactions = buildSortedReactionsList(records, userPublicKey, threshold);
-
- container.removeAllViews();
- LinearLayout overflowContainer = new LinearLayout(getContext());
- overflowContainer.setOrientation(LinearLayout.HORIZONTAL);
- int innerPadding = ViewUtil.dpToPx(4);
- overflowContainer.setPaddingRelative(innerPadding,innerPadding,innerPadding,innerPadding);
-
- int pixelSize = ViewUtil.dpToPx(1);
-
- for (Reaction reaction : reactions) {
- if (container.getChildCount() + 1 >= DEFAULT_THRESHOLD && threshold != Integer.MAX_VALUE && reactions.size() > threshold) {
- if (overflowContainer.getParent() == null) {
- container.addView(overflowContainer);
- MarginLayoutParams overflowParams = (MarginLayoutParams) overflowContainer.getLayoutParams();
- overflowParams.height = ViewUtil.dpToPx(26);
- overflowParams.setMargins(pixelSize, pixelSize, pixelSize, pixelSize);
- overflowContainer.setLayoutParams(overflowParams);
- overflowContainer.setBackground(ContextCompat.getDrawable(getContext(), R.drawable.reaction_pill_background));
- }
- View pill = buildPill(getContext(), this, reaction, true);
- pill.setOnClickListener(v -> {
- extended = true;
- displayReactions(Integer.MAX_VALUE);
- });
- pill.findViewById(R.id.reactions_pill_count).setVisibility(View.GONE);
- pill.findViewById(R.id.reactions_pill_spacer).setVisibility(View.GONE);
- overflowContainer.addView(pill);
- } else {
- View pill = buildPill(getContext(), this, reaction, false);
- pill.setTag(reaction);
- pill.setOnTouchListener(this);
- MarginLayoutParams params = (MarginLayoutParams) pill.getLayoutParams();
- params.setMargins(pixelSize, pixelSize, pixelSize, pixelSize);
- pill.setLayoutParams(params);
- container.addView(pill);
- }
- }
-
- int overflowChildren = overflowContainer.getChildCount();
- int negativeMargin = ViewUtil.dpToPx(-8);
- for (int i = 0; i < overflowChildren; i++) {
- View child = overflowContainer.getChildAt(i);
- MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
- if ((i == 0 && overflowChildren > 1) || i + 1 < overflowChildren) {
- // if first and there is more than one child, or we are not the last child then set negative right margin
- childParams.setMargins(0,0, negativeMargin, 0);
- child.setLayoutParams(childParams);
- }
- }
-
- if (threshold == Integer.MAX_VALUE) {
- showLess.setVisibility(VISIBLE);
- for (int id : showLess.getReferencedIds()) {
- findViewById(id).setOnClickListener(view -> {
- extended = false;
- displayReactions(DEFAULT_THRESHOLD);
- });
- }
- } else {
- showLess.setVisibility(GONE);
- }
- }
-
- private void onReactionClicked(Reaction reaction) {
- if (reaction.messageId != 0) {
- MessageId messageId = new MessageId(reaction.messageId, reaction.isMms);
- delegate.onReactionClicked(reaction.emoji, messageId, reaction.userWasSender);
- }
- }
-
- private static @NonNull List buildSortedReactionsList(@NonNull List records, String userPublicKey, int threshold) {
- Map counters = new LinkedHashMap<>();
-
- for (ReactionRecord record : records) {
- String baseEmoji = EmojiUtil.getCanonicalRepresentation(record.getEmoji());
- Reaction info = counters.get(baseEmoji);
-
- if (info == null) {
- info = new Reaction(record.getMessageId(), record.isMms(), record.getEmoji(), record.getCount(), record.getSortId(), record.getDateReceived(), userPublicKey.equals(record.getAuthor()));
- } else {
- info.update(record.getEmoji(), record.getCount(), record.getDateReceived(), userPublicKey.equals(record.getAuthor()));
- }
-
- counters.put(baseEmoji, info);
- }
-
- List reactions = new ArrayList<>(counters.values());
-
- Collections.sort(reactions, Collections.reverseOrder());
-
- if (reactions.size() >= threshold + 2 && threshold != Integer.MAX_VALUE) {
- List shortened = new ArrayList<>(threshold + 2);
- shortened.addAll(reactions.subList(0, threshold + 2));
- return shortened;
- } else {
- return reactions;
- }
- }
-
- private static View buildPill(@NonNull Context context, @NonNull ViewGroup parent, @NonNull Reaction reaction, boolean isCompact) {
- View root = LayoutInflater.from(context).inflate(R.layout.reactions_pill, parent, false);
- EmojiImageView emojiView = root.findViewById(R.id.reactions_pill_emoji);
- TextView countView = root.findViewById(R.id.reactions_pill_count);
- View spacer = root.findViewById(R.id.reactions_pill_spacer);
-
- if (isCompact) {
- root.setPaddingRelative(1,1,1,1);
- ViewGroup.LayoutParams layoutParams = root.getLayoutParams();
- layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
- root.setLayoutParams(layoutParams);
- }
-
- if (reaction.emoji != null) {
- emojiView.setImageEmoji(reaction.emoji);
-
- if (reaction.count >= 1) {
- countView.setText(NumberUtil.getFormattedNumber(reaction.count));
- } else {
- countView.setVisibility(GONE);
- spacer.setVisibility(GONE);
- }
- } else {
- emojiView.setVisibility(GONE);
- spacer.setVisibility(GONE);
- countView.setText(context.getString(R.string.ReactionsConversationView_plus, reaction.count));
- }
-
- if (reaction.userWasSender && !isCompact) {
- root.setBackground(ContextCompat.getDrawable(context, R.drawable.reaction_pill_background_selected));
- countView.setTextColor(ThemeUtil.getThemedColor(context, R.attr.reactionsPillSelectedTextColor));
- } else {
- if (!isCompact) {
- root.setBackground(ContextCompat.getDrawable(context, R.drawable.reaction_pill_background));
- }
- }
-
- return root;
- }
-
- private void onDown(MessageId messageId) {
- removeLongPressCallback();
- Runnable newLongPressCallback = () -> {
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- if (delegate != null) {
- delegate.onReactionLongClicked(messageId);
- }
- };
- this.longPressCallback = newLongPressCallback;
- gestureHandler.postDelayed(newLongPressCallback, longPressDurationThreshold);
- onDownTimestamp = new Date().getTime();
- }
-
- private void removeLongPressCallback() {
- if (longPressCallback != null) {
- gestureHandler.removeCallbacks(longPressCallback);
- }
- }
-
- private void onUp(Reaction reaction) {
- if ((new Date().getTime() - onDownTimestamp) < longPressDurationThreshold) {
- removeLongPressCallback();
- if (pressCallback != null) {
- gestureHandler.removeCallbacks(pressCallback);
- this.pressCallback = null;
- } else {
- Runnable newPressCallback = () -> {
- onReactionClicked(reaction);
- pressCallback = null;
- };
- this.pressCallback = newPressCallback;
- gestureHandler.postDelayed(newPressCallback, maxDoubleTapInterval);
- }
- }
- }
-
- private static class Reaction implements Comparable {
- private final long messageId;
- private final boolean isMms;
- private String emoji;
- private long count;
- private long sortIndex;
- private long lastSeen;
- private boolean userWasSender;
-
- Reaction(long messageId, boolean isMms, @Nullable String emoji, long count, long sortIndex, long lastSeen, boolean userWasSender) {
- this.messageId = messageId;
- this.isMms = isMms;
- this.emoji = emoji;
- this.count = count;
- this.sortIndex = sortIndex;
- this.lastSeen = lastSeen;
- this.userWasSender = userWasSender;
- }
-
- void update(@NonNull String emoji, long count, long lastSeen, boolean userWasSender) {
- if (!this.userWasSender) {
- if (userWasSender || lastSeen > this.lastSeen) {
- this.emoji = emoji;
- }
- }
-
- this.count = this.count + count;
- this.lastSeen = Math.max(this.lastSeen, lastSeen);
- this.userWasSender = this.userWasSender || userWasSender;
- }
-
- @NonNull Reaction merge(@NonNull Reaction other) {
- this.count = this.count + other.count;
- this.lastSeen = Math.max(this.lastSeen, other.lastSeen);
- this.userWasSender = this.userWasSender || other.userWasSender;
- return this;
- }
-
- @Override
- public int compareTo(Reaction rhs) {
- Reaction lhs = this;
- if (lhs.count == rhs.count ) {
- return Long.compare(lhs.sortIndex, rhs.sortIndex);
- } else {
- return Long.compare(lhs.count, rhs.count);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt
new file mode 100644
index 0000000000..49e4b1044f
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/EmojiReactionsView.kt
@@ -0,0 +1,291 @@
+package org.thoughtcrime.securesms.conversation.v2.messages
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.util.AttributeSet
+import android.view.*
+import android.view.View.OnTouchListener
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat
+import com.google.android.flexbox.JustifyContent
+import network.loki.messenger.R
+import network.loki.messenger.databinding.ViewEmojiReactionsBinding
+import org.session.libsession.utilities.TextSecurePreferences.Companion.getLocalNumber
+import org.session.libsession.utilities.ThemeUtil
+import org.thoughtcrime.securesms.components.emoji.EmojiImageView
+import org.thoughtcrime.securesms.components.emoji.EmojiUtil
+import org.thoughtcrime.securesms.conversation.v2.ViewUtil
+import org.thoughtcrime.securesms.database.model.MessageId
+import org.thoughtcrime.securesms.database.model.ReactionRecord
+import org.thoughtcrime.securesms.util.NumberUtil.getFormattedNumber
+import java.util.*
+
+class EmojiReactionsView : ConstraintLayout, OnTouchListener {
+ companion object {
+ private const val DEFAULT_THRESHOLD = 5
+ private const val longPressDurationThreshold: Long = 250
+ private const val maxDoubleTapInterval: Long = 200
+ }
+
+ private val binding: ViewEmojiReactionsBinding by lazy { ViewEmojiReactionsBinding.bind(this) }
+
+ // Normally 6dp, but we have 1dp left+right margin on the pills themselves
+ private val OUTER_MARGIN = ViewUtil.dpToPx(2)
+ private var records: MutableList? = null
+ private var messageId: Long = 0
+ private var delegate: VisibleMessageViewDelegate? = null
+ private val gestureHandler = Handler(Looper.getMainLooper())
+ private var pressCallback: Runnable? = null
+ private var longPressCallback: Runnable? = null
+ private var onDownTimestamp: Long = 0
+ private var extended = false
+
+ constructor(context: Context) : super(context) { init(null) }
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { init(attrs) }
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { init(attrs) }
+
+ private fun init(attrs: AttributeSet?) {
+ records = ArrayList()
+
+ if (attrs != null) {
+ val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.EmojiReactionsView, 0, 0)
+ typedArray.recycle()
+ }
+ }
+
+ fun clear() {
+ records!!.clear()
+ binding.layoutEmojiContainer.removeAllViews()
+ }
+
+ fun setReactions(messageId: Long, records: List, outgoing: Boolean, delegate: VisibleMessageViewDelegate?) {
+ this.delegate = delegate
+ if (records == this.records) {
+ return
+ }
+
+ binding.layoutEmojiContainer.justifyContent = if (outgoing) JustifyContent.FLEX_END else JustifyContent.FLEX_START
+ this.records!!.clear()
+ this.records!!.addAll(records)
+ if (this.messageId != messageId) {
+ extended = false
+ }
+ this.messageId = messageId
+ displayReactions(if (extended) Int.MAX_VALUE else DEFAULT_THRESHOLD)
+ }
+
+ override fun onTouch(v: View, event: MotionEvent): Boolean {
+ if (v.tag == null) return false
+ val reaction = v.tag as Reaction
+ val action = event.action
+ if (action == MotionEvent.ACTION_DOWN) onDown(MessageId(reaction.messageId, reaction.isMms)) else if (action == MotionEvent.ACTION_CANCEL) removeLongPressCallback() else if (action == MotionEvent.ACTION_UP) onUp(reaction)
+ return true
+ }
+
+ private fun displayReactions(threshold: Int) {
+ val userPublicKey = getLocalNumber(context)
+ val reactions = buildSortedReactionsList(records!!, userPublicKey, threshold)
+ binding.layoutEmojiContainer.removeAllViews()
+ val overflowContainer = LinearLayout(context)
+ overflowContainer.orientation = LinearLayout.HORIZONTAL
+ val innerPadding = ViewUtil.dpToPx(4)
+ overflowContainer.setPaddingRelative(innerPadding, innerPadding, innerPadding, innerPadding)
+ val pixelSize = ViewUtil.dpToPx(1)
+ for (reaction in reactions) {
+ if (binding.layoutEmojiContainer.childCount + 1 >= DEFAULT_THRESHOLD && threshold != Int.MAX_VALUE && reactions.size > threshold) {
+ if (overflowContainer.parent == null) {
+ binding.layoutEmojiContainer.addView(overflowContainer)
+ val overflowParams = overflowContainer.layoutParams as MarginLayoutParams
+ overflowParams.height = ViewUtil.dpToPx(26)
+ overflowParams.setMargins(pixelSize, pixelSize, pixelSize, pixelSize)
+ overflowContainer.layoutParams = overflowParams
+ overflowContainer.background = ContextCompat.getDrawable(context, R.drawable.reaction_pill_background)
+ }
+ val pill = buildPill(context, this, reaction, true)
+ pill.setOnClickListener { v: View? ->
+ extended = true
+ displayReactions(Int.MAX_VALUE)
+ }
+ pill.findViewById(R.id.reactions_pill_count).visibility = GONE
+ pill.findViewById(R.id.reactions_pill_spacer).visibility = GONE
+ overflowContainer.addView(pill)
+ } else {
+ val pill = buildPill(context, this, reaction, false)
+ pill.tag = reaction
+ pill.setOnTouchListener(this)
+ val params = pill.layoutParams as MarginLayoutParams
+ params.setMargins(pixelSize, pixelSize, pixelSize, pixelSize)
+ pill.layoutParams = params
+ binding.layoutEmojiContainer.addView(pill)
+ }
+ }
+ val overflowChildren = overflowContainer.childCount
+ val negativeMargin = ViewUtil.dpToPx(-8)
+ for (i in 0 until overflowChildren) {
+ val child = overflowContainer.getChildAt(i)
+ val childParams = child.layoutParams as MarginLayoutParams
+ if (i == 0 && overflowChildren > 1 || i + 1 < overflowChildren) {
+ // if first and there is more than one child, or we are not the last child then set negative right margin
+ childParams.setMargins(0, 0, negativeMargin, 0)
+ child.layoutParams = childParams
+ }
+ }
+ if (threshold == Int.MAX_VALUE) {
+ binding.groupShowLess.visibility = VISIBLE
+ for (id in binding.groupShowLess.referencedIds) {
+ findViewById(id).setOnClickListener { view: View? ->
+ extended = false
+ displayReactions(DEFAULT_THRESHOLD)
+ }
+ }
+ } else {
+ binding.groupShowLess.visibility = GONE
+ }
+ }
+
+ private fun buildSortedReactionsList(records: List, userPublicKey: String?, threshold: Int): List {
+ val counters: MutableMap = LinkedHashMap()
+
+ records.forEach {
+ val baseEmoji = EmojiUtil.getCanonicalRepresentation(it.emoji)
+ val info = counters[baseEmoji]
+
+ if (info == null) {
+ counters[baseEmoji] = Reaction(messageId, it.isMms, it.emoji, it.count, it.sortId, it.dateReceived, userPublicKey == it.author)
+ }
+ else {
+ info.update(it.emoji, it.count, it.dateReceived, userPublicKey == it.author)
+ }
+ }
+
+ val reactions: List = ArrayList(counters.values)
+ Collections.sort(reactions, Collections.reverseOrder())
+
+ return if (reactions.size >= threshold + 2 && threshold != Int.MAX_VALUE) {
+ val shortened: MutableList = ArrayList(threshold + 2)
+ shortened.addAll(reactions.subList(0, threshold + 2))
+ shortened
+ } else {
+ reactions
+ }
+ }
+
+ private fun buildPill(context: Context, parent: ViewGroup, reaction: Reaction, isCompact: Boolean): View {
+ val root = LayoutInflater.from(context).inflate(R.layout.reactions_pill, parent, false)
+ val emojiView = root.findViewById(R.id.reactions_pill_emoji)
+ val countView = root.findViewById(R.id.reactions_pill_count)
+ val spacer = root.findViewById(R.id.reactions_pill_spacer)
+ if (isCompact) {
+ root.setPaddingRelative(1, 1, 1, 1)
+ val layoutParams = root.layoutParams
+ layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ root.layoutParams = layoutParams
+ }
+ if (reaction.emoji != null) {
+ emojiView.setImageEmoji(reaction.emoji)
+ if (reaction.count >= 1) {
+ countView.text = getFormattedNumber(reaction.count)
+ } else {
+ countView.visibility = GONE
+ spacer.visibility = GONE
+ }
+ } else {
+ emojiView.visibility = GONE
+ spacer.visibility = GONE
+ countView.text = context.getString(R.string.ReactionsConversationView_plus, reaction.count)
+ }
+ if (reaction.userWasSender && !isCompact) {
+ root.background = ContextCompat.getDrawable(context, R.drawable.reaction_pill_background_selected)
+ countView.setTextColor(ThemeUtil.getThemedColor(context, R.attr.reactionsPillSelectedTextColor))
+ } else {
+ if (!isCompact) {
+ root.background = ContextCompat.getDrawable(context, R.drawable.reaction_pill_background)
+ }
+ }
+ return root
+ }
+
+ private fun onReactionClicked(reaction: Reaction) {
+ if (reaction.messageId != 0L) {
+ val messageId = MessageId(reaction.messageId, reaction.isMms)
+ delegate!!.onReactionClicked(reaction.emoji!!, messageId, reaction.userWasSender)
+ }
+ }
+
+ private fun onDown(messageId: MessageId) {
+ removeLongPressCallback()
+ val newLongPressCallback = Runnable {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
+ if (delegate != null) {
+ delegate!!.onReactionLongClicked(messageId)
+ }
+ }
+ longPressCallback = newLongPressCallback
+ gestureHandler.postDelayed(newLongPressCallback, longPressDurationThreshold)
+ onDownTimestamp = Date().time
+ }
+
+ private fun removeLongPressCallback() {
+ if (longPressCallback != null) {
+ gestureHandler.removeCallbacks(longPressCallback!!)
+ }
+ }
+
+ private fun onUp(reaction: Reaction) {
+ if (Date().time - onDownTimestamp < longPressDurationThreshold) {
+ removeLongPressCallback()
+ if (pressCallback != null) {
+ gestureHandler.removeCallbacks(pressCallback!!)
+ pressCallback = null
+ } else {
+ val newPressCallback = Runnable {
+ onReactionClicked(reaction)
+ pressCallback = null
+ }
+ pressCallback = newPressCallback
+ gestureHandler.postDelayed(newPressCallback, maxDoubleTapInterval)
+ }
+ }
+ }
+
+ internal class Reaction(
+ internal val messageId: Long,
+ internal val isMms: Boolean,
+ internal var emoji: String?,
+ internal var count: Long,
+ internal val sortIndex: Long,
+ internal var lastSeen: Long,
+ internal var userWasSender: Boolean
+ ) : Comparable {
+ fun update(emoji: String, count: Long, lastSeen: Long, userWasSender: Boolean) {
+ if (!this.userWasSender) {
+ if (userWasSender || lastSeen > this.lastSeen) {
+ this.emoji = emoji
+ }
+ }
+ this.count = this.count + count
+ this.lastSeen = Math.max(this.lastSeen, lastSeen)
+ this.userWasSender = this.userWasSender || userWasSender
+ }
+
+ fun merge(other: Reaction): Reaction {
+ count = count + other.count
+ lastSeen = Math.max(lastSeen, other.lastSeen)
+ userWasSender = userWasSender || other.userWasSender
+ return this
+ }
+
+ override fun compareTo(other: Reaction?): Int {
+ if (other == null) { return -1 }
+
+ if (this.count == other.count) {
+ return this.sortIndex.compareTo(other.sortIndex)
+ }
+
+ return this.count.compareTo(other.count)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt
index cb6bb536ff..9677223894 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt
@@ -4,11 +4,9 @@ import android.content.Context
import android.graphics.Canvas
import android.graphics.Rect
import android.util.AttributeSet
-import android.view.LayoutInflater
import android.view.MotionEvent
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isVisible
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewLinkPreviewBinding
@@ -19,21 +17,16 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.MessageBubbleUtiliti
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.mms.ImageSlide
-import org.thoughtcrime.securesms.util.UiModeUtilities
class LinkPreviewView : LinearLayout {
- private lateinit var binding: ViewLinkPreviewBinding
+ private val binding: ViewLinkPreviewBinding by lazy { ViewLinkPreviewBinding.bind(this) }
private val cornerMask by lazy { CornerMask(this) }
private var url: String? = null
// region Lifecycle
- constructor(context: Context) : super(context) { initialize() }
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
-
- private fun initialize() {
- binding = ViewLinkPreviewBinding.inflate(LayoutInflater.from(context), this, true)
- }
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
// endregion
// region Updating
@@ -48,8 +41,8 @@ class LinkPreviewView : LinearLayout {
// Thumbnail
if (linkPreview.getThumbnail().isPresent) {
// This internally fetches the thumbnail
- binding.thumbnailImageView.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), isPreview = false, message)
- binding.thumbnailImageView.loadIndicator.isVisible = false
+ binding.thumbnailImageView.root.setImageResource(glide, ImageSlide(context, linkPreview.getThumbnail().get()), isPreview = false, message)
+ binding.thumbnailImageView.root.loadIndicator.isVisible = false
}
// Title
binding.titleTextView.text = linkPreview.title
@@ -64,8 +57,12 @@ class LinkPreviewView : LinearLayout {
val cornerRadii = MessageBubbleUtilities.calculateRadii(context, isStartOfMessageCluster, isEndOfMessageCluster, message.isOutgoing)
cornerMask.setTopLeftRadius(cornerRadii[0])
cornerMask.setTopRightRadius(cornerRadii[1])
- cornerMask.setBottomRightRadius(cornerRadii[2])
- cornerMask.setBottomLeftRadius(cornerRadii[3])
+
+ // Only round the bottom corners if there is no body text
+ if (message.body.isEmpty()) {
+ cornerMask.setBottomRightRadius(cornerRadii[2])
+ cornerMask.setBottomLeftRadius(cornerRadii[3])
+ }
}
override fun dispatchDraw(canvas: Canvas) {
@@ -80,7 +77,7 @@ class LinkPreviewView : LinearLayout {
val rawYInt = event.rawY.toInt()
val hitRect = Rect(rawXInt, rawYInt, rawXInt, rawYInt)
val previewRect = Rect()
- binding.mainLinkPreviewParent.getGlobalVisibleRect(previewRect)
+ binding.mainLinkPreviewContainer.getGlobalVisibleRect(previewRect)
if (previewRect.contains(hitRect)) {
openURL()
return
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt
index 91ab4c106d..4e91400430 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt
@@ -93,7 +93,7 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
val backgroundColor = context.getAccentColor()
binding.quoteViewAttachmentPreviewContainer.backgroundTintList = ColorStateList.valueOf(backgroundColor)
binding.quoteViewAttachmentPreviewImageView.isVisible = false
- binding.quoteViewAttachmentThumbnailImageView.isVisible = false
+ binding.quoteViewAttachmentThumbnailImageView.root.isVisible = false
when {
attachments.audioSlide != null -> {
binding.quoteViewAttachmentPreviewImageView.setImageResource(R.drawable.ic_microphone)
@@ -108,9 +108,9 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
attachments.thumbnailSlide != null -> {
val slide = attachments.thumbnailSlide!!
// This internally fetches the thumbnail
- binding.quoteViewAttachmentThumbnailImageView.radius = toPx(4, resources)
- binding.quoteViewAttachmentThumbnailImageView.setImageResource(glide, slide, false, false)
- binding.quoteViewAttachmentThumbnailImageView.isVisible = true
+ binding.quoteViewAttachmentThumbnailImageView.root.radius = toPx(4, resources)
+ binding.quoteViewAttachmentThumbnailImageView.root.setImageResource(glide, slide, false, null)
+ binding.quoteViewAttachmentThumbnailImageView.root.isVisible = true
binding.quoteViewBodyTextView.text = if (MediaUtil.isVideo(slide.asAttachment())) resources.getString(R.string.Slide_video) else resources.getString(R.string.Slide_image)
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
index c6fc57c289..75a3c58752 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
@@ -10,10 +10,8 @@ import android.text.style.ForegroundColorSpan
import android.text.style.URLSpan
import android.text.util.Linkify
import android.util.AttributeSet
-import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
-import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
@@ -22,13 +20,12 @@ import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.text.getSpans
import androidx.core.text.toSpannable
+import androidx.core.view.children
import androidx.core.view.isVisible
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewVisibleMessageContentBinding
import okhttp3.HttpUrl
import org.session.libsession.messaging.MessagingModuleConfiguration
-import org.session.libsession.messaging.jobs.AttachmentDownloadJob
-import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.getColorFromAttr
@@ -47,26 +44,30 @@ import org.thoughtcrime.securesms.util.getAccentColor
import java.util.*
import kotlin.math.roundToInt
-class VisibleMessageContentView : LinearLayout {
- private lateinit var binding: ViewVisibleMessageContentBinding
+class VisibleMessageContentView : ConstraintLayout {
+ private val binding: ViewVisibleMessageContentBinding by lazy { ViewVisibleMessageContentBinding.bind(this) }
var onContentClick: MutableList<((event: MotionEvent) -> Unit)> = mutableListOf()
var onContentDoubleTap: (() -> Unit)? = null
var delegate: VisibleMessageViewDelegate? = null
var indexInAdapter: Int = -1
// region Lifecycle
- constructor(context: Context) : super(context) { initialize() }
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
-
- private fun initialize() {
- binding = ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(context), this, true)
- }
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
// endregion
// region Updating
- fun bind(message: MessageRecord, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean,
- glide: GlideRequests, thread: Recipient, searchQuery: String?, contactIsTrusted: Boolean) {
+ fun bind(
+ message: MessageRecord,
+ isStartOfMessageCluster: Boolean,
+ isEndOfMessageCluster: Boolean,
+ glide: GlideRequests,
+ thread: Recipient,
+ searchQuery: String?,
+ contactIsTrusted: Boolean,
+ onAttachmentNeedsDownload: (Long, Long) -> Unit
+ ) {
// Background
val background = getBackground(message.isOutgoing)
val color = if (message.isOutgoing) context.getAccentColor()
@@ -80,7 +81,7 @@ class VisibleMessageContentView : LinearLayout {
// reset visibilities / containers
onContentClick.clear()
- binding.albumThumbnailView.clearViews()
+ binding.albumThumbnailView.root.clearViews()
onContentDoubleTap = null
if (message.isDeleted) {
@@ -88,28 +89,26 @@ class VisibleMessageContentView : LinearLayout {
binding.deletedMessageView.root.bind(message, getTextColor(context, message))
binding.bodyTextView.isVisible = false
binding.quoteView.root.isVisible = false
- binding.linkPreviewView.isVisible = false
+ binding.linkPreviewView.root.isVisible = false
binding.untrustedView.root.isVisible = false
binding.voiceMessageView.root.isVisible = false
binding.documentView.root.isVisible = false
- binding.albumThumbnailView.isVisible = false
+ binding.albumThumbnailView.root.isVisible = false
binding.openGroupInvitationView.root.isVisible = false
return
} else {
binding.deletedMessageView.root.isVisible = false
}
- // clear the
+
+ // Note: Need to clear the body to prevent the message bubble getting incorrectly
+ // sized based on text content from a recycled view
binding.bodyTextView.text = null
-
-
binding.quoteView.root.isVisible = message is MmsMessageRecord && message.quote != null
-
- binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
-
+ binding.linkPreviewView.root.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
binding.untrustedView.root.isVisible = !contactIsTrusted && message is MmsMessageRecord && message.quote == null && message.linkPreviews.isEmpty()
binding.voiceMessageView.root.isVisible = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.audioSlide != null
binding.documentView.root.isVisible = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.documentSlide != null
- binding.albumThumbnailView.isVisible = mediaThumbnailMessage
+ binding.albumThumbnailView.root.isVisible = mediaThumbnailMessage
binding.openGroupInvitationView.root.isVisible = message.isOpenGroupInvitation
var hideBody = false
@@ -141,8 +140,7 @@ class VisibleMessageContentView : LinearLayout {
val attachmentId = dbAttachment.attachmentId.rowId
if (attach.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_PENDING
&& MessagingModuleConfiguration.shared.storage.getAttachmentUploadJob(attachmentId) == null) {
- // start download
- JobQueue.shared.add(AttachmentDownloadJob(attachmentId, dbAttachment.mmsId))
+ onAttachmentNeedsDownload(attachmentId, dbAttachment.mmsId)
}
}
message.linkPreviews.forEach { preview ->
@@ -150,16 +148,18 @@ class VisibleMessageContentView : LinearLayout {
val attachmentId = previewThumbnail.attachmentId.rowId
if (previewThumbnail.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_PENDING
&& MessagingModuleConfiguration.shared.storage.getAttachmentUploadJob(attachmentId) == null) {
- JobQueue.shared.add(AttachmentDownloadJob(attachmentId, previewThumbnail.mmsId))
+ onAttachmentNeedsDownload(attachmentId, previewThumbnail.mmsId)
}
}
}
when {
message is MmsMessageRecord && message.linkPreviews.isNotEmpty() -> {
- binding.linkPreviewView.bind(message, glide, isStartOfMessageCluster, isEndOfMessageCluster)
- onContentClick.add { event -> binding.linkPreviewView.calculateHit(event) }
- // Body text view is inside the link preview for layout convenience
+ binding.linkPreviewView.root.bind(message, glide, isStartOfMessageCluster, isEndOfMessageCluster)
+ onContentClick.add { event -> binding.linkPreviewView.root.calculateHit(event) }
+
+ // When in a link preview ensure the bodyTextView can expand to the full width
+ binding.bodyTextView.maxWidth = binding.linkPreviewView.root.layoutParams.width
}
message is MmsMessageRecord && message.slideDeck.audioSlide != null -> {
hideBody = true
@@ -195,21 +195,21 @@ class VisibleMessageContentView : LinearLayout {
if (contactIsTrusted || message.isOutgoing) {
// isStart and isEnd of cluster needed for calculating the mask for full bubble image groups
// bind after add view because views are inflated and calculated during bind
- binding.albumThumbnailView.bind(
+ binding.albumThumbnailView.root.bind(
glideRequests = glide,
message = message,
isStart = isStartOfMessageCluster,
isEnd = isEndOfMessageCluster
)
- val layoutParams = binding.albumThumbnailView.layoutParams as ConstraintLayout.LayoutParams
+ val layoutParams = binding.albumThumbnailView.root.layoutParams as ConstraintLayout.LayoutParams
layoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f
- binding.albumThumbnailView.layoutParams = layoutParams
+ binding.albumThumbnailView.root.layoutParams = layoutParams
onContentClick.add { event ->
- binding.albumThumbnailView.calculateHitObject(event, message, thread)
+ binding.albumThumbnailView.root.calculateHitObject(event, message, thread, onAttachmentNeedsDownload)
}
} else {
hideBody = true
- binding.albumThumbnailView.clearViews()
+ binding.albumThumbnailView.root.clearViews()
binding.untrustedView.root.bind(UntrustedAttachmentView.AttachmentType.MEDIA, VisibleMessageContentView.getTextColor(context,message))
onContentClick.add { binding.untrustedView.root.showTrustDialog(message.individualRecipient) }
}
@@ -222,6 +222,7 @@ class VisibleMessageContentView : LinearLayout {
}
binding.bodyTextView.isVisible = message.body.isNotEmpty() && !hideBody
+ binding.contentParent.apply { isVisible = children.any { it.isVisible } }
if (message.body.isNotEmpty() && !hideBody) {
val color = getTextColor(context, message)
@@ -241,7 +242,7 @@ class VisibleMessageContentView : LinearLayout {
}
private fun ViewVisibleMessageContentBinding.barrierViewsGone(): Boolean =
- listOf(albumThumbnailView, linkPreviewView, voiceMessageView.root, quoteView.root).none { it.isVisible }
+ listOf(albumThumbnailView.root, linkPreviewView.root, voiceMessageView.root, quoteView.root).none { it.isVisible }
private fun getBackground(isOutgoing: Boolean): Drawable {
val backgroundID = if (isOutgoing) R.drawable.message_bubble_background_sent_alone else R.drawable.message_bubble_background_received_alone
@@ -256,8 +257,8 @@ class VisibleMessageContentView : LinearLayout {
binding.openGroupInvitationView.root,
binding.documentView.root,
binding.quoteView.root,
- binding.linkPreviewView,
- binding.albumThumbnailView,
+ binding.linkPreviewView.root,
+ binding.albumThumbnailView.root,
binding.bodyTextView
).forEach { view: View -> view.isVisible = false }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
index 0b4c1455fc..319140731a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
@@ -13,6 +13,9 @@ import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.view.View
import android.widget.LinearLayout
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
@@ -26,6 +29,7 @@ import network.loki.messenger.databinding.ViewVisibleMessageBinding
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.contacts.Contact.ContactContext
import org.session.libsession.messaging.open_groups.OpenGroupApi
+import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.getColorFromAttr
@@ -85,7 +89,7 @@ class VisibleMessageView : LinearLayout {
var onPress: ((event: MotionEvent) -> Unit)? = null
var onSwipeToReply: (() -> Unit)? = null
var onLongPress: (() -> Unit)? = null
- val messageContentView: VisibleMessageContentView by lazy { binding.messageContentView }
+ val messageContentView: VisibleMessageContentView by lazy { binding.messageContentView.root }
companion object {
const val swipeToReplyThreshold = 64.0f // dp
@@ -108,7 +112,7 @@ class VisibleMessageView : LinearLayout {
isHapticFeedbackEnabled = true
setWillNotDraw(false)
binding.messageInnerContainer.disableClipping()
- binding.messageContentView.disableClipping()
+ binding.messageContentView.root.disableClipping()
}
// endregion
@@ -122,6 +126,7 @@ class VisibleMessageView : LinearLayout {
contact: Contact?,
senderSessionID: String,
delegate: VisibleMessageViewDelegate?,
+ onAttachmentNeedsDownload: (Long, Long) -> Unit
) {
val threadID = message.threadId
val thread = threadDb.getRecipientForThreadId(threadID) ?: return
@@ -157,7 +162,8 @@ class VisibleMessageView : LinearLayout {
binding.profilePictureView.root.update(message.individualRecipient)
binding.profilePictureView.root.setOnClickListener {
if (thread.isOpenGroupRecipient) {
- if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED) {
+ val openGroup = lokiThreadDb.getOpenGroupChat(threadID)
+ if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED && openGroup?.canWrite == true) {
val intent = Intent(context, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.FROM_GROUP_THREAD_ID, threadID)
intent.putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(senderSessionID))
@@ -190,50 +196,75 @@ class VisibleMessageView : LinearLayout {
binding.dateBreakTextView.text = if (showDateBreak) DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp) else null
binding.dateBreakTextView.isVisible = showDateBreak
// Message status indicator
- val (iconID, iconColor) = getMessageStatusImage(message)
- if (iconID != null) {
- val drawable = ContextCompat.getDrawable(context, iconID)?.mutate()
- if (iconColor != null) {
- drawable?.setTint(iconColor)
- }
- binding.messageStatusImageView.setImageDrawable(drawable)
- }
if (message.isOutgoing) {
+ val (iconID, iconColor, textId, contentDescription) = getMessageStatusImage(message)
+ if (textId != null) {
+ binding.messageStatusTextView.setText(textId)
+
+ if (iconColor != null) {
+ binding.messageStatusTextView.setTextColor(iconColor)
+ }
+ }
+ if (iconID != null) {
+ val drawable = ContextCompat.getDrawable(context, iconID)?.mutate()
+ if (iconColor != null) {
+ drawable?.setTint(iconColor)
+ }
+ binding.messageStatusImageView.setImageDrawable(drawable)
+ }
+ binding.messageStatusImageView.contentDescription = contentDescription
+
val lastMessageID = mmsSmsDb.getLastMessageID(message.threadId)
- binding.messageStatusImageView.isVisible =
- !message.isSent || message.id == lastMessageID
+ binding.messageStatusTextView.isVisible = (
+ textId != null && (
+ !message.isSent ||
+ message.id == lastMessageID
+ )
+ )
+ binding.messageStatusImageView.isVisible = (
+ iconID != null && (
+ !message.isSent ||
+ message.id == lastMessageID
+ )
+ )
} else {
+ binding.messageStatusTextView.isVisible = false
binding.messageStatusImageView.isVisible = false
}
// Expiration timer
updateExpirationTimer(message)
// Emoji Reactions
- val emojiLayoutParams = binding.emojiReactionsView.layoutParams as ConstraintLayout.LayoutParams
+ val emojiLayoutParams = binding.emojiReactionsView.root.layoutParams as ConstraintLayout.LayoutParams
emojiLayoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f
- binding.emojiReactionsView.layoutParams = emojiLayoutParams
- val capabilities = lokiThreadDb.getOpenGroupChat(threadID)?.server?.let { lokiApiDb.getServerCapabilities(it) }
- if (message.reactions.isNotEmpty() &&
- (capabilities.isNullOrEmpty() || capabilities.contains(OpenGroupApi.Capability.REACTIONS.name.lowercase()))
- ) {
- binding.emojiReactionsView.setReactions(message.id, message.reactions, message.isOutgoing, delegate)
- binding.emojiReactionsView.isVisible = true
- } else {
- binding.emojiReactionsView.isVisible = false
+ binding.emojiReactionsView.root.layoutParams = emojiLayoutParams
+
+ if (message.reactions.isNotEmpty()) {
+ val capabilities = lokiThreadDb.getOpenGroupChat(threadID)?.server?.let { lokiApiDb.getServerCapabilities(it) }
+ if (capabilities.isNullOrEmpty() || capabilities.contains(OpenGroupApi.Capability.REACTIONS.name.lowercase())) {
+ binding.emojiReactionsView.root.setReactions(message.id, message.reactions, message.isOutgoing, delegate)
+ binding.emojiReactionsView.root.isVisible = true
+ } else {
+ binding.emojiReactionsView.root.isVisible = false
+ }
+ }
+ else {
+ binding.emojiReactionsView.root.isVisible = false
}
// Populate content view
- binding.messageContentView.indexInAdapter = indexInAdapter
- binding.messageContentView.bind(
+ binding.messageContentView.root.indexInAdapter = indexInAdapter
+ binding.messageContentView.root.bind(
message,
isStartOfMessageCluster,
isEndOfMessageCluster,
glide,
thread,
searchQuery,
- message.isOutgoing || isGroupThread || (contact?.isTrusted ?: false)
+ message.isOutgoing || isGroupThread || (contact?.isTrusted ?: false),
+ onAttachmentNeedsDownload
)
- binding.messageContentView.delegate = delegate
- onDoubleTap = { binding.messageContentView.onContentDoubleTap?.invoke() }
+ binding.messageContentView.root.delegate = delegate
+ onDoubleTap = { binding.messageContentView.root.onContentDoubleTap?.invoke() }
}
private fun isStartOfMessageCluster(current: MessageRecord, previous: MessageRecord?, isGroupThread: Boolean): Boolean {
@@ -256,25 +287,60 @@ class VisibleMessageView : LinearLayout {
}
}
- private fun getMessageStatusImage(message: MessageRecord): Pair {
- return when {
- !message.isOutgoing -> null to null
- message.isFailed -> R.drawable.ic_error to resources.getColor(R.color.destructive, context.theme)
- message.isPending -> R.drawable.ic_circle_dot_dot_dot to null
- message.isRead -> R.drawable.ic_filled_circle_check to null
- else -> R.drawable.ic_circle_check to null
- }
+ data class MessageStatusInfo(@DrawableRes val iconId: Int?,
+ @ColorInt val iconTint: Int?,
+ @StringRes val messageText: Int?,
+ val contentDescription: String?)
+
+ private fun getMessageStatusImage(message: MessageRecord): MessageStatusInfo = when {
+ message.isFailed ->
+ MessageStatusInfo(
+ R.drawable.ic_delivery_status_failed,
+ resources.getColor(R.color.destructive, context.theme),
+ R.string.delivery_status_failed,
+ null
+ )
+ message.isSyncFailed ->
+ MessageStatusInfo(
+ R.drawable.ic_delivery_status_failed,
+ context.getColor(R.color.accent_orange),
+ R.string.delivery_status_sync_failed,
+ null
+ )
+ message.isPending ->
+ MessageStatusInfo(
+ R.drawable.ic_delivery_status_sending,
+ context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_sending,
+ context.getString(R.string.AccessibilityId_message_sent_status_pending)
+ )
+ message.isResyncing ->
+ MessageStatusInfo(
+ R.drawable.ic_delivery_status_sending,
+ context.getColor(R.color.accent_orange), R.string.delivery_status_syncing,
+ context.getString(R.string.AccessibilityId_message_sent_status_syncing)
+ )
+ message.isRead ->
+ MessageStatusInfo(
+ R.drawable.ic_delivery_status_read,
+ context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_read,
+ null
+ )
+ else ->
+ MessageStatusInfo(
+ R.drawable.ic_delivery_status_sent,
+ context.getColorFromAttr(R.attr.message_status_color),
+ R.string.delivery_status_sent,
+ context.getString(R.string.AccessibilityId_message_sent_status_tick)
+ )
}
private fun updateExpirationTimer(message: MessageRecord) {
val container = binding.messageInnerContainer
- val content = binding.messageContentView
+ val content = binding.messageContentView.root
val expiration = binding.expirationTimerView
- val spacing = binding.messageContentSpacing
container.removeAllViewsInLayout()
container.addView(if (message.isOutgoing) expiration else content)
container.addView(if (message.isOutgoing) content else expiration)
- container.addView(spacing, if (message.isOutgoing) 0 else 2)
val containerParams = container.layoutParams as ConstraintLayout.LayoutParams
containerParams.horizontalBias = if (message.isOutgoing) 1f else 0f
container.layoutParams = containerParams
@@ -285,7 +351,7 @@ class VisibleMessageView : LinearLayout {
if (message.expireStarted > 0) {
binding.expirationTimerView.setExpirationTime(message.expireStarted, message.expiresIn)
binding.expirationTimerView.startAnimation()
- if (message.expireStarted + message.expiresIn <= System.currentTimeMillis()) {
+ if (message.expireStarted + message.expiresIn <= SnodeAPI.nowWithOffset) {
ApplicationContext.getInstance(context).expiringMessageManager.checkSchedule()
}
} else if (!message.isMediaPending) {
@@ -319,7 +385,7 @@ class VisibleMessageView : LinearLayout {
override fun onDraw(canvas: Canvas) {
val spacing = context.resources.getDimensionPixelSize(R.dimen.small_spacing)
val iconSize = toPx(24, context.resources)
- val left = binding.messageInnerContainer.left + binding.messageContentView.right + spacing
+ val left = binding.messageInnerContainer.left + binding.messageContentView.root.right + spacing
val top = height - (binding.messageInnerContainer.height / 2) - binding.profilePictureView.root.marginBottom - (iconSize / 2)
val right = left + iconSize
val bottom = top + iconSize
@@ -341,7 +407,7 @@ class VisibleMessageView : LinearLayout {
fun recycle() {
binding.profilePictureView.root.recycle()
- binding.messageContentView.recycle()
+ binding.messageContentView.root.recycle()
}
// endregion
@@ -437,7 +503,7 @@ class VisibleMessageView : LinearLayout {
}
fun onContentClick(event: MotionEvent) {
- binding.messageContentView.onContentClick.iterator().forEach { clickHandler -> clickHandler.invoke(event) }
+ binding.messageContentView.root.onContentClick.iterator().forEach { clickHandler -> clickHandler.invoke(event) }
}
private fun onPress(event: MotionEvent) {
@@ -457,7 +523,7 @@ class VisibleMessageView : LinearLayout {
}
fun playVoiceMessage() {
- binding.messageContentView.playVoiceMessage()
+ binding.messageContentView.root.playVoiceMessage()
}
// endregion
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt
index e1456a7f94..c3a9689a00 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/BaseDialog.kt
@@ -14,9 +14,7 @@ open class BaseDialog : DialogFragment() {
val builder = AlertDialog.Builder(requireContext())
setContentView(builder)
val result = builder.create()
- result.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
- val isLightMode = UiModeUtilities.isDayUiMode(requireContext())
- result.window?.setDimAmount(if (isLightMode) 0.1f else 0.75f)
+ result.window?.setDimAmount(0.6f)
return result
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt
index 80f4cc0bf8..e01a75b30c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ResendMessageUtilities.kt
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.utilities
import android.content.Context
import org.session.libsession.messaging.MessagingModuleConfiguration
+import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.visible.LinkPreview
import org.session.libsession.messaging.messages.visible.OpenGroupInvitation
import org.session.libsession.messaging.messages.visible.Quote
@@ -15,7 +16,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord
object ResendMessageUtilities {
- fun resend(context: Context, messageRecord: MessageRecord, userBlindedKey: String?) {
+ fun resend(context: Context, messageRecord: MessageRecord, userBlindedKey: String?, isResync: Boolean = false) {
val recipient: Recipient = messageRecord.recipient
val message = VisibleMessage()
message.id = messageRecord.getId()
@@ -55,8 +56,13 @@ object ResendMessageUtilities {
val sentTimestamp = message.sentTimestamp
val sender = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
if (sentTimestamp != null && sender != null) {
- MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender)
+ if (isResync) {
+ MessagingModuleConfiguration.shared.storage.markAsResyncing(sentTimestamp, sender)
+ MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = true)
+ } else {
+ MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender)
+ MessageSender.send(message, recipient.address)
+ }
}
- MessageSender.send(message, recipient.address)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt
index 800ace54c3..7a47b92756 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/TextUtilities.kt
@@ -38,13 +38,12 @@ object TextUtilities {
fun TextView.getIntersectedModalSpans(hitRect: Rect): List {
val textLayout = layout ?: return emptyList()
val lineRect = Rect()
- val bodyTextRect = Rect()
- getGlobalVisibleRect(bodyTextRect)
+ val offset = intArrayOf(0, 0).also { getLocationOnScreen(it) }
val textSpannable = text.toSpannable()
return (0 until textLayout.lineCount).flatMap { line ->
textLayout.getLineBounds(line, lineRect)
- lineRect.offset(bodyTextRect.left + totalPaddingLeft, bodyTextRect.top + totalPaddingTop)
- if ((Rect(lineRect)).contains(hitRect)) {
+ lineRect.offset(offset[0] + totalPaddingLeft, offset[1] + totalPaddingTop)
+ if (lineRect.contains(hitRect)) {
// calculate the url span intersected with (if any)
val off = textLayout.getOffsetForHorizontal(line, hitRect.left.toFloat()) // left and right will be the same
textSpannable.getSpans(off, off).toList()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.java
deleted file mode 100644
index 912253ecd8..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.java
+++ /dev/null
@@ -1,425 +0,0 @@
-package org.thoughtcrime.securesms.conversation.v2.utilities;
-
-import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.net.Uri;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.UiThread;
-
-import com.bumptech.glide.RequestBuilder;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
-import com.bumptech.glide.load.resource.bitmap.CenterCrop;
-import com.bumptech.glide.load.resource.bitmap.FitCenter;
-import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
-import com.bumptech.glide.request.RequestOptions;
-
-import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.ViewUtil;
-import org.session.libsignal.utilities.ListenableFuture;
-import org.session.libsignal.utilities.Log;
-import org.session.libsignal.utilities.SettableFuture;
-import org.session.libsignal.utilities.guava.Optional;
-import org.thoughtcrime.securesms.components.GlideBitmapListeningTarget;
-import org.thoughtcrime.securesms.components.GlideDrawableListeningTarget;
-import org.thoughtcrime.securesms.components.TransferControlView;
-import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
-import org.thoughtcrime.securesms.mms.GlideRequest;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.thoughtcrime.securesms.mms.Slide;
-import org.thoughtcrime.securesms.mms.SlideClickListener;
-import org.thoughtcrime.securesms.mms.SlidesClickedListener;
-
-import java.util.Collections;
-import java.util.Locale;
-
-import network.loki.messenger.R;
-
-public class ThumbnailView extends FrameLayout {
-
- private static final String TAG = ThumbnailView.class.getSimpleName();
- private static final int WIDTH = 0;
- private static final int HEIGHT = 1;
- private static final int MIN_WIDTH = 0;
- private static final int MAX_WIDTH = 1;
- private static final int MIN_HEIGHT = 2;
- private static final int MAX_HEIGHT = 3;
-
- private ImageView image;
- private View playOverlay;
- private View loadIndicator;
- private OnClickListener parentClickListener;
-
- private final int[] dimens = new int[2];
- private final int[] bounds = new int[4];
- private final int[] measureDimens = new int[2];
-
- private Optional transferControls = Optional.absent();
- private SlideClickListener thumbnailClickListener = null;
- private SlidesClickedListener downloadClickListener = null;
- private Slide slide = null;
-
- public int radius;
-
- public ThumbnailView(Context context) {
- this(context, null);
- }
-
- public ThumbnailView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ThumbnailView(final Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- inflate(context, R.layout.thumbnail_view, this);
-
- this.image = findViewById(R.id.thumbnail_image);
- this.playOverlay = findViewById(R.id.play_overlay);
- this.loadIndicator = findViewById(R.id.thumbnail_load_indicator);
- super.setOnClickListener(new ThumbnailClickDispatcher());
-
- if (attrs != null) {
- TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ThumbnailView, 0, 0);
- bounds[MIN_WIDTH] = typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_minWidth, 0);
- bounds[MAX_WIDTH] = typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_maxWidth, 0);
- bounds[MIN_HEIGHT] = typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_minHeight, 0);
- bounds[MAX_HEIGHT] = typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_maxHeight, 0);
- radius = typedArray.getDimensionPixelSize(R.styleable.ThumbnailView_thumbnail_radius, 0);
- typedArray.recycle();
- } else {
- radius = 0;
- }
- }
-
- @Override
- protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
- fillTargetDimensions(measureDimens, dimens, bounds);
- if (measureDimens[WIDTH] == 0 && measureDimens[HEIGHT] == 0) {
- super.onMeasure(originalWidthMeasureSpec, originalHeightMeasureSpec);
- return;
- }
-
- int finalWidth = measureDimens[WIDTH] + getPaddingLeft() + getPaddingRight();
- int finalHeight = measureDimens[HEIGHT] + getPaddingTop() + getPaddingBottom();
-
- super.onMeasure(MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
- }
-
- @SuppressWarnings("SuspiciousNameCombination")
- private void fillTargetDimensions(int[] targetDimens, int[] dimens, int[] bounds) {
- int dimensFilledCount = getNonZeroCount(dimens);
- int boundsFilledCount = getNonZeroCount(bounds);
-
- if (dimensFilledCount == 0 || boundsFilledCount == 0) {
- targetDimens[WIDTH] = 0;
- targetDimens[HEIGHT] = 0;
- return;
- }
-
- double naturalWidth = dimens[WIDTH];
- double naturalHeight = dimens[HEIGHT];
-
- int minWidth = bounds[MIN_WIDTH];
- int maxWidth = bounds[MAX_WIDTH];
- int minHeight = bounds[MIN_HEIGHT];
- int maxHeight = bounds[MAX_HEIGHT];
-
- if (dimensFilledCount > 0 && dimensFilledCount < dimens.length) {
- throw new IllegalStateException(String.format(Locale.ENGLISH, "Width or height has been specified, but not both. Dimens: %f x %f",
- naturalWidth, naturalHeight));
- }
- if (boundsFilledCount > 0 && boundsFilledCount < bounds.length) {
- throw new IllegalStateException(String.format(Locale.ENGLISH, "One or more min/max dimensions have been specified, but not all. Bounds: [%d, %d, %d, %d]",
- minWidth, maxWidth, minHeight, maxHeight));
- }
-
- double measuredWidth = naturalWidth;
- double measuredHeight = naturalHeight;
-
- boolean widthInBounds = measuredWidth >= minWidth && measuredWidth <= maxWidth;
- boolean heightInBounds = measuredHeight >= minHeight && measuredHeight <= maxHeight;
-
- if (!widthInBounds || !heightInBounds) {
- double minWidthRatio = naturalWidth / minWidth;
- double maxWidthRatio = naturalWidth / maxWidth;
- double minHeightRatio = naturalHeight / minHeight;
- double maxHeightRatio = naturalHeight / maxHeight;
-
- if (maxWidthRatio > 1 || maxHeightRatio > 1) {
- if (maxWidthRatio >= maxHeightRatio) {
- measuredWidth /= maxWidthRatio;
- measuredHeight /= maxWidthRatio;
- } else {
- measuredWidth /= maxHeightRatio;
- measuredHeight /= maxHeightRatio;
- }
-
- measuredWidth = Math.max(measuredWidth, minWidth);
- measuredHeight = Math.max(measuredHeight, minHeight);
-
- } else if (minWidthRatio < 1 || minHeightRatio < 1) {
- if (minWidthRatio <= minHeightRatio) {
- measuredWidth /= minWidthRatio;
- measuredHeight /= minWidthRatio;
- } else {
- measuredWidth /= minHeightRatio;
- measuredHeight /= minHeightRatio;
- }
-
- measuredWidth = Math.min(measuredWidth, maxWidth);
- measuredHeight = Math.min(measuredHeight, maxHeight);
- }
- }
-
- targetDimens[WIDTH] = (int) measuredWidth;
- targetDimens[HEIGHT] = (int) measuredHeight;
- }
-
- private int getNonZeroCount(int[] vals) {
- int count = 0;
- for (int val : vals) {
- if (val > 0) {
- count++;
- }
- }
- return count;
- }
-
- @Override
- public void setOnClickListener(OnClickListener l) {
- parentClickListener = l;
- }
-
- @Override
- public void setFocusable(boolean focusable) {
- super.setFocusable(focusable);
- if (transferControls.isPresent()) transferControls.get().setFocusable(focusable);
- }
-
- @Override
- public void setClickable(boolean clickable) {
- super.setClickable(clickable);
- if (transferControls.isPresent()) transferControls.get().setClickable(clickable);
- }
-
- private TransferControlView getTransferControls() {
- if (!transferControls.isPresent()) {
- transferControls = Optional.of(ViewUtil.inflateStub(this, R.id.transfer_controls_stub));
- }
- return transferControls.get();
- }
-
- public void setBounds(int minWidth, int maxWidth, int minHeight, int maxHeight) {
- bounds[MIN_WIDTH] = minWidth;
- bounds[MAX_WIDTH] = maxWidth;
- bounds[MIN_HEIGHT] = minHeight;
- bounds[MAX_HEIGHT] = maxHeight;
-
- forceLayout();
- }
-
- @UiThread
- public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
- boolean showControls, boolean isPreview)
- {
- return setImageResource(glideRequests, slide, showControls, isPreview, 0, 0);
- }
-
- @UiThread
- public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
- boolean showControls, boolean isPreview,
- int naturalWidth, int naturalHeight)
- {
- if (showControls) {
- getTransferControls().setSlide(slide);
- getTransferControls().setDownloadClickListener(new DownloadClickDispatcher());
- } else if (transferControls.isPresent()) {
- getTransferControls().setVisibility(View.GONE);
- }
-
- if (slide.getThumbnailUri() != null && slide.hasPlayOverlay() &&
- (slide.getTransferState() == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE || isPreview))
- {
- this.playOverlay.setVisibility(View.VISIBLE);
- } else {
- this.playOverlay.setVisibility(View.GONE);
- }
-
- if (Util.equals(slide, this.slide)) {
- Log.i(TAG, "Not re-loading slide " + slide.asAttachment().getDataUri());
- return new SettableFuture<>(false);
- }
-
- if (this.slide != null && this.slide.getFastPreflightId() != null &&
- this.slide.getFastPreflightId().equals(slide.getFastPreflightId()))
- {
- Log.i(TAG, "Not re-loading slide for fast preflight: " + slide.getFastPreflightId());
- this.slide = slide;
- return new SettableFuture<>(false);
- }
-
- Log.i(TAG, "loading part with id " + slide.asAttachment().getDataUri()
- + ", progress " + slide.getTransferState() + ", fast preflight id: " +
- slide.asAttachment().getFastPreflightId());
-
- this.slide = slide;
-
- dimens[WIDTH] = naturalWidth;
- dimens[HEIGHT] = naturalHeight;
- invalidate();
-
- SettableFuture result = new SettableFuture<>();
-
- if (slide.getThumbnailUri() != null) {
- buildThumbnailGlideRequest(glideRequests, slide).into(new GlideDrawableListeningTarget(image, result));
- } else if (slide.hasPlaceholder()) {
- buildPlaceholderGlideRequest(glideRequests, slide).into(new GlideBitmapListeningTarget(image, result));
- } else {
- glideRequests.load(R.drawable.ic_image_white_24dp).centerInside().into(image);
- result.set(false);
- }
-
- return result;
- }
-
- public ListenableFuture setImageResource(@NonNull GlideRequests glideRequests, @NonNull Uri uri) {
- SettableFuture future = new SettableFuture<>();
-
- if (transferControls.isPresent()) getTransferControls().setVisibility(View.GONE);
-
- GlideRequest request = glideRequests.load(new DecryptableUri(uri))
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .transition(withCrossFade());
-
- if (radius > 0) {
- request = request.transforms(new CenterCrop(), new RoundedCorners(radius));
- } else {
- request = request.transforms(new CenterCrop());
- }
-
- request.into(new GlideDrawableListeningTarget(image, future));
-
- return future;
- }
-
- public void setThumbnailClickListener(SlideClickListener listener) {
- this.thumbnailClickListener = listener;
- }
-
- public void setDownloadClickListener(SlidesClickedListener listener) {
- this.downloadClickListener = listener;
- }
-
- public void clear(GlideRequests glideRequests) {
- glideRequests.clear(image);
-
- if (transferControls.isPresent()) {
- getTransferControls().clear();
- }
-
- slide = null;
- }
-
- public void showDownloadText(boolean showDownloadText) {
- getTransferControls().setShowDownloadText(showDownloadText);
- }
-
- public void showProgressSpinner() {
- getTransferControls().showProgressSpinner();
- }
-
- public void setLoadIndicatorVisibile(boolean visible) {
- this.loadIndicator.setVisibility(visible ? VISIBLE : GONE);
- }
-
- protected void setRadius(int radius) {
- this.radius = radius;
- }
-
- private GlideRequest buildThumbnailGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) {
- GlideRequest request = applySizing(glideRequests.load(new DecryptableUri(slide.getThumbnailUri()))
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .transition(withCrossFade()), new CenterCrop());
-
- if (slide.isInProgress()) return request;
- else return request.apply(RequestOptions.errorOf(R.drawable.ic_missing_thumbnail_picture));
- }
-
- private RequestBuilder buildPlaceholderGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) {
- return applySizing(glideRequests.asBitmap()
- .load(slide.getPlaceholderRes(getContext().getTheme()))
- .diskCacheStrategy(DiskCacheStrategy.NONE), new FitCenter());
- }
-
- private GlideRequest applySizing(@NonNull GlideRequest request, @NonNull BitmapTransformation fitting) {
- int[] size = new int[2];
- fillTargetDimensions(size, dimens, bounds);
- if (size[WIDTH] == 0 && size[HEIGHT] == 0) {
- size[WIDTH] = getDefaultWidth();
- size[HEIGHT] = getDefaultHeight();
- }
-
- request = request.override(size[WIDTH], size[HEIGHT]);
-
- if (radius > 0) {
- return request.transforms(fitting, new RoundedCorners(radius));
- } else {
- return request.transforms(fitting);
- }
- }
-
- private int getDefaultWidth() {
- ViewGroup.LayoutParams params = getLayoutParams();
- if (params != null) {
- return Math.max(params.width, 0);
- }
- return 0;
- }
-
- private int getDefaultHeight() {
- ViewGroup.LayoutParams params = getLayoutParams();
- if (params != null) {
- return Math.max(params.height, 0);
- }
- return 0;
- }
-
- private class ThumbnailClickDispatcher implements View.OnClickListener {
-
- @Override
- public void onClick(View view) {
- if (thumbnailClickListener != null &&
- slide != null &&
- slide.asAttachment().getDataUri() != null &&
- slide.getTransferState() == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE)
- {
- thumbnailClickListener.onClick(view, slide);
- } else if (parentClickListener != null) {
- parentClickListener.onClick(view);
- }
- }
- }
-
- private class DownloadClickDispatcher implements View.OnClickListener {
-
- @Override
- public void onClick(View view) {
- if (downloadClickListener != null && slide != null) {
- downloadClickListener.onClick(view, Collections.singletonList(slide));
- } else {
- Log.w(TAG, "Received a download button click, but unable to execute it. slide: " + String.valueOf(slide) + " downloadClickListener: " + String.valueOf(downloadClickListener));
- }
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt
similarity index 82%
rename from app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt
rename to app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt
index 1ae2902188..4a9986d6ec 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailView.kt
@@ -2,14 +2,11 @@ package org.thoughtcrime.securesms.conversation.v2.utilities
import android.content.Context
import android.graphics.Bitmap
-import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.util.AttributeSet
-import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
-import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.CenterCrop
@@ -29,31 +26,33 @@ import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri
import org.thoughtcrime.securesms.mms.GlideRequest
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.mms.Slide
+import kotlin.Boolean
+import kotlin.Int
+import kotlin.getValue
+import kotlin.lazy
+import kotlin.let
-open class KThumbnailView: FrameLayout {
- private lateinit var binding: ThumbnailViewBinding
+open class ThumbnailView: FrameLayout {
companion object {
private const val WIDTH = 0
private const val HEIGHT = 1
}
+ private val binding: ThumbnailViewBinding by lazy { ThumbnailViewBinding.bind(this) }
+
// region Lifecycle
constructor(context: Context) : super(context) { initialize(null) }
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize(attrs) }
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize(attrs) }
- private val image by lazy { binding.thumbnailImage }
- private val playOverlay by lazy { binding.playOverlay }
val loadIndicator: View by lazy { binding.thumbnailLoadIndicator }
- val downloadIndicator: View by lazy { binding.thumbnailDownloadIcon }
private val dimensDelegate = ThumbnailDimensDelegate()
private var slide: Slide? = null
- private var radius: Int = 0
+ var radius: Int = 0
private fun initialize(attrs: AttributeSet?) {
- binding = ThumbnailViewBinding.inflate(LayoutInflater.from(context), this)
if (attrs != null) {
val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.ThumbnailView, 0, 0)
@@ -66,8 +65,6 @@ open class KThumbnailView: FrameLayout {
typedArray.recycle()
}
- val background = ContextCompat.getColor(context, R.color.transparent_black_6)
- binding.root.background = ColorDrawable(background)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
@@ -80,8 +77,8 @@ open class KThumbnailView: FrameLayout {
val finalHeight: Int = adjustedDimens[HEIGHT] + paddingTop + paddingBottom
super.onMeasure(
- MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY)
+ MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY)
)
}
@@ -90,17 +87,17 @@ open class KThumbnailView: FrameLayout {
// endregion
// region Interaction
- fun setImageResource(glide: GlideRequests, slide: Slide, isPreview: Boolean, mms: MmsMessageRecord): ListenableFuture {
+ fun setImageResource(glide: GlideRequests, slide: Slide, isPreview: Boolean, mms: MmsMessageRecord?): ListenableFuture {
return setImageResource(glide, slide, isPreview, 0, 0, mms)
}
fun setImageResource(glide: GlideRequests, slide: Slide,
isPreview: Boolean, naturalWidth: Int,
- naturalHeight: Int, mms: MmsMessageRecord): ListenableFuture {
+ naturalHeight: Int, mms: MmsMessageRecord?): ListenableFuture {
val currentSlide = this.slide
- playOverlay.isVisible = (slide.thumbnailUri != null && slide.hasPlayOverlay() &&
+ binding.playOverlay.isVisible = (slide.thumbnailUri != null && slide.hasPlayOverlay() &&
(slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE || isPreview))
if (equals(currentSlide, slide)) {
@@ -116,8 +113,8 @@ open class KThumbnailView: FrameLayout {
this.slide = slide
- loadIndicator.isVisible = slide.isInProgress
- downloadIndicator.isVisible = slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED
+ binding.thumbnailLoadIndicator.isVisible = slide.isInProgress
+ binding.thumbnailDownloadIcon.isVisible = slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED
dimensDelegate.setDimens(naturalWidth, naturalHeight)
invalidate()
@@ -126,13 +123,13 @@ open class KThumbnailView: FrameLayout {
when {
slide.thumbnailUri != null -> {
- buildThumbnailGlideRequest(glide, slide).into(GlideDrawableListeningTarget(image, result))
+ buildThumbnailGlideRequest(glide, slide).into(GlideDrawableListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, result))
}
slide.hasPlaceholder() -> {
- buildPlaceholderGlideRequest(glide, slide).into(GlideBitmapListeningTarget(image, result))
+ buildPlaceholderGlideRequest(glide, slide).into(GlideBitmapListeningTarget(binding.thumbnailImage, null, result))
}
else -> {
- glide.clear(image)
+ glide.clear(binding.thumbnailImage)
result.set(false)
}
}
@@ -176,7 +173,7 @@ open class KThumbnailView: FrameLayout {
}
open fun clear(glideRequests: GlideRequests) {
- glideRequests.clear(image)
+ glideRequests.clear(binding.thumbnailImage)
slide = null
}
@@ -193,11 +190,8 @@ open class KThumbnailView: FrameLayout {
request.transforms(CenterCrop())
}
- request.into(GlideDrawableListeningTarget(image, future))
+ request.into(GlideDrawableListeningTarget(binding.thumbnailImage, binding.thumbnailLoadIndicator, future))
return future
}
-
- // endregion
-
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java
index 43e9865598..7f0edddeb0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/KeyStoreHelper.java
@@ -1,13 +1,13 @@
package org.thoughtcrime.securesms.crypto;
-import android.os.Build;
+import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK;
+
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;
import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -45,44 +45,50 @@ public final class KeyStoreHelper {
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String KEY_ALIAS = "SignalSecret";
- @RequiresApi(Build.VERSION_CODES.M)
public static SealedData seal(@NonNull byte[] input) {
SecretKey secretKey = getOrCreateKeyStoreEntry();
try {
- Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
- cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ // Cipher operations are not thread-safe so we synchronize over them through doFinal to
+ // prevent crashes with quickly repeated encrypt/decrypt operations
+ // https://github.com/mozilla-mobile/android-components/issues/5342
+ synchronized (CIPHER_LOCK) {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
- byte[] iv = cipher.getIV();
- byte[] data = cipher.doFinal(input);
+ byte[] iv = cipher.getIV();
+ byte[] data = cipher.doFinal(input);
- return new SealedData(iv, data);
+ return new SealedData(iv, data);
+ }
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e);
}
}
- @RequiresApi(Build.VERSION_CODES.M)
public static byte[] unseal(@NonNull SealedData sealedData) {
SecretKey secretKey = getKeyStoreEntry();
try {
- Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
- cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv));
+ // Cipher operations are not thread-safe so we synchronize over them through doFinal to
+ // prevent crashes with quickly repeated encrypt/decrypt operations
+ // https://github.com/mozilla-mobile/android-components/issues/5342
+ synchronized (CIPHER_LOCK) {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv));
- return cipher.doFinal(sealedData.data);
+ return cipher.doFinal(sealedData.data);
+ }
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e);
}
}
- @RequiresApi(Build.VERSION_CODES.M)
private static SecretKey getOrCreateKeyStoreEntry() {
if (hasKeyStoreEntry()) return getKeyStoreEntry();
else return createKeyStoreEntry();
}
- @RequiresApi(Build.VERSION_CODES.M)
private static SecretKey createKeyStoreEntry() {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
@@ -99,7 +105,6 @@ public final class KeyStoreHelper {
}
}
- @RequiresApi(Build.VERSION_CODES.M)
private static SecretKey getKeyStoreEntry() {
KeyStore keyStore = getKeyStore();
@@ -137,7 +142,6 @@ public final class KeyStoreHelper {
}
}
- @RequiresApi(Build.VERSION_CODES.M)
private static boolean hasKeyStoreEntry() {
try {
KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE);
@@ -202,7 +206,5 @@ public final class KeyStoreHelper {
return Base64.decode(p.getValueAsString(), Base64.NO_WRAP | Base64.NO_PADDING);
}
}
-
}
-
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java
index 8c9916b87c..45172e2f6f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java
@@ -33,8 +33,9 @@ import androidx.annotation.VisibleForTesting;
import com.bumptech.glide.Glide;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
+import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
@@ -318,6 +319,28 @@ public class AttachmentDatabase extends Database {
notifyAttachmentListeners();
}
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ void deleteAttachmentsForMessages(long[] mmsIds) {
+ SQLiteDatabase database = databaseHelper.getWritableDatabase();
+ Cursor cursor = null;
+ String mmsIdString = StringUtils.join(mmsIds, ',');
+
+ try {
+ cursor = database.query(TABLE_NAME, new String[] {DATA, THUMBNAIL, CONTENT_TYPE}, MMS_ID + " IN (?)",
+ new String[] {mmsIdString}, null, null, null);
+
+ while (cursor != null && cursor.moveToNext()) {
+ deleteAttachmentOnDisk(cursor.getString(0), cursor.getString(1), cursor.getString(2));
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+
+ database.delete(TABLE_NAME, MMS_ID + " IN (?)", new String[] {mmsIdString});
+ notifyAttachmentListeners();
+ }
+
public void deleteAttachment(@NonNull AttachmentId id) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
index ce950214f0..b6b224589e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
@@ -23,7 +23,7 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.session.libsession.utilities.WindowDebouncer;
import org.thoughtcrime.securesms.ApplicationContext;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java
index 74396e2a93..76fa8c5c0b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java
@@ -19,7 +19,7 @@ package org.thoughtcrime.securesms.database;
import android.content.Context;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseUtilities.kt
index e6c9b9614e..f4d6530bbf 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseUtilities.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseUtilities.kt
@@ -1,9 +1,9 @@
package org.thoughtcrime.securesms.database
import android.content.ContentValues
+import android.database.Cursor
import androidx.core.database.getStringOrNull
-import net.sqlcipher.Cursor
-import net.sqlcipher.database.SQLiteDatabase
+import net.zetetic.database.sqlcipher.SQLiteDatabase
import org.session.libsignal.utilities.Base64
fun SQLiteDatabase.get(table: String, query: String?, arguments: Array?, get: (Cursor) -> T): T? {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DraftDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/DraftDatabase.java
index 2dd8b2bf24..822e40129e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/DraftDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/DraftDatabase.java
@@ -6,7 +6,7 @@ import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.Nullable;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java
index feaccc3983..79adead57e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java
@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.database;
-
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
@@ -12,7 +11,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.jetbrains.annotations.NotNull;
import org.session.libsession.utilities.Address;
@@ -319,6 +318,38 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
notifyConversationListListeners();
}
+ @Override
+ public void removeProfilePicture(String groupID) {
+ databaseHelper.getWritableDatabase()
+ .execSQL("UPDATE " + TABLE_NAME +
+ " SET " + AVATAR + " = NULL, " +
+ AVATAR_ID + " = NULL, " +
+ AVATAR_KEY + " = NULL, " +
+ AVATAR_CONTENT_TYPE + " = NULL, " +
+ AVATAR_RELAY + " = NULL, " +
+ AVATAR_DIGEST + " = NULL, " +
+ AVATAR_URL + " = NULL" +
+ " WHERE " +
+ GROUP_ID + " = ?",
+ new String[] {groupID});
+
+ Recipient.applyCached(Address.fromSerialized(groupID), recipient -> recipient.setGroupAvatarId(null));
+ notifyConversationListListeners();
+ }
+
+ public boolean hasDownloadedProfilePicture(String groupId) {
+ try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[]{AVATAR}, GROUP_ID + " = ?",
+ new String[] {groupId},
+ null, null, null))
+ {
+ if (cursor != null && cursor.moveToNext()) {
+ return !cursor.isNull(0);
+ }
+
+ return false;
+ }
+ }
+
public void updateMembers(String groupId, List members) {
Collections.sort(members);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupReceiptDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupReceiptDatabase.java
index 81f8b62aa5..a6fed5be83 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupReceiptDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupReceiptDatabase.java
@@ -1,14 +1,14 @@
package org.thoughtcrime.securesms.database;
-
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import androidx.annotation.NonNull;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
+import org.apache.commons.lang3.StringUtils;
import org.session.libsession.utilities.Address;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
@@ -110,6 +110,11 @@ public class GroupReceiptDatabase extends Database {
db.delete(TABLE_NAME, MMS_ID + " = ?", new String[] {String.valueOf(mmsId)});
}
+ void deleteRowsForMessages(long[] mmsIds) {
+ SQLiteDatabase db = databaseHelper.getWritableDatabase();
+ db.delete(TABLE_NAME, MMS_ID + " IN (?)", new String[] {StringUtils.join(mmsIds, ',')});
+ }
+
void deleteAllRows() {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.delete(TABLE_NAME, null, null);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java
deleted file mode 100644
index f878e3061a..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/database/JobDatabase.java
+++ /dev/null
@@ -1,249 +0,0 @@
-package org.thoughtcrime.securesms.database;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import androidx.annotation.NonNull;
-
-import net.sqlcipher.database.SQLiteDatabase;
-
-import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
-import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
-
-import java.util.LinkedList;
-import java.util.List;
-
-public class JobDatabase extends Database {
-
- public static final String[] CREATE_TABLE = new String[] { Jobs.CREATE_TABLE,
- Constraints.CREATE_TABLE,
- Dependencies.CREATE_TABLE };
-
- public static final class Jobs {
- public static final String TABLE_NAME = "job_spec";
- private static final String ID = "_id";
- private static final String JOB_SPEC_ID = "job_spec_id";
- private static final String FACTORY_KEY = "factory_key";
- private static final String QUEUE_KEY = "queue_key";
- private static final String CREATE_TIME = "create_time";
- private static final String NEXT_RUN_ATTEMPT_TIME = "next_run_attempt_time";
- private static final String RUN_ATTEMPT = "run_attempt";
- private static final String MAX_ATTEMPTS = "max_attempts";
- private static final String MAX_BACKOFF = "max_backoff";
- private static final String MAX_INSTANCES = "max_instances";
- private static final String LIFESPAN = "lifespan";
- private static final String SERIALIZED_DATA = "serialized_data";
- private static final String IS_RUNNING = "is_running";
-
- private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
- JOB_SPEC_ID + " TEXT UNIQUE, " +
- FACTORY_KEY + " TEXT, " +
- QUEUE_KEY + " TEXT, " +
- CREATE_TIME + " INTEGER, " +
- NEXT_RUN_ATTEMPT_TIME + " INTEGER, " +
- RUN_ATTEMPT + " INTEGER, " +
- MAX_ATTEMPTS + " INTEGER, " +
- MAX_BACKOFF + " INTEGER, " +
- MAX_INSTANCES + " INTEGER, " +
- LIFESPAN + " INTEGER, " +
- SERIALIZED_DATA + " TEXT, " +
- IS_RUNNING + " INTEGER)";
- }
-
- public static final class Constraints {
- public static final String TABLE_NAME = "constraint_spec";
- private static final String ID = "_id";
- private static final String JOB_SPEC_ID = "job_spec_id";
- private static final String FACTORY_KEY = "factory_key";
-
- private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
- JOB_SPEC_ID + " TEXT, " +
- FACTORY_KEY + " TEXT, " +
- "UNIQUE(" + JOB_SPEC_ID + ", " + FACTORY_KEY + "))";
- }
-
- public static final class Dependencies {
- public static final String TABLE_NAME = "dependency_spec";
- private static final String ID = "_id";
- private static final String JOB_SPEC_ID = "job_spec_id";
- private static final String DEPENDS_ON_JOB_SPEC_ID = "depends_on_job_spec_id";
-
- private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
- JOB_SPEC_ID + " TEXT, " +
- DEPENDS_ON_JOB_SPEC_ID + " TEXT, " +
- "UNIQUE(" + JOB_SPEC_ID + ", " + DEPENDS_ON_JOB_SPEC_ID + "))";
- }
-
-
- public JobDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
- super(context, databaseHelper);
- }
-
- public synchronized void insertJobs(@NonNull List fullSpecs) {
- SQLiteDatabase db = databaseHelper.getWritableDatabase();
-
- db.beginTransaction();
-
- try {
- for (FullSpec fullSpec : fullSpecs) {
- insertJobSpec(db, fullSpec.getJobSpec());
- insertConstraintSpecs(db, fullSpec.getConstraintSpecs());
- insertDependencySpecs(db, fullSpec.getDependencySpecs());
- }
-
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- public synchronized @NonNull List getAllJobSpecs() {
- List jobs = new LinkedList<>();
-
- try (Cursor cursor = databaseHelper.getReadableDatabase().query(Jobs.TABLE_NAME, null, null, null, null, null, Jobs.CREATE_TIME + ", " + Jobs.ID + " ASC")) {
- while (cursor != null && cursor.moveToNext()) {
- jobs.add(jobSpecFromCursor(cursor));
- }
- }
-
- return jobs;
- }
-
- public synchronized void updateJobRunningState(@NonNull String id, boolean isRunning) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Jobs.IS_RUNNING, isRunning ? 1 : 0);
-
- String query = Jobs.JOB_SPEC_ID + " = ?";
- String[] args = new String[]{ id };
-
- databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, query, args);
- }
-
- public synchronized void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Jobs.IS_RUNNING, isRunning ? 1 : 0);
- contentValues.put(Jobs.RUN_ATTEMPT, runAttempt);
- contentValues.put(Jobs.NEXT_RUN_ATTEMPT_TIME, nextRunAttemptTime);
-
- String query = Jobs.JOB_SPEC_ID + " = ?";
- String[] args = new String[]{ id };
-
- databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, query, args);
- }
-
- public synchronized void updateAllJobsToBePending() {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Jobs.IS_RUNNING, 0);
-
- databaseHelper.getWritableDatabase().update(Jobs.TABLE_NAME, contentValues, null, null);
- }
-
- public synchronized void deleteJobs(@NonNull List jobIds) {
- SQLiteDatabase db = databaseHelper.getWritableDatabase();
-
- db.beginTransaction();
-
- try {
- for (String jobId : jobIds) {
- String[] arg = new String[]{jobId};
-
- db.delete(Jobs.TABLE_NAME, Jobs.JOB_SPEC_ID + " = ?", arg);
- db.delete(Constraints.TABLE_NAME, Constraints.JOB_SPEC_ID + " = ?", arg);
- db.delete(Dependencies.TABLE_NAME, Dependencies.JOB_SPEC_ID + " = ?", arg);
- db.delete(Dependencies.TABLE_NAME, Dependencies.DEPENDS_ON_JOB_SPEC_ID + " = ?", arg);
- }
-
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- public synchronized @NonNull List getAllConstraintSpecs() {
- List constraints = new LinkedList<>();
-
- try (Cursor cursor = databaseHelper.getReadableDatabase().query(Constraints.TABLE_NAME, null, null, null, null, null, null)) {
- while (cursor != null && cursor.moveToNext()) {
- constraints.add(constraintSpecFromCursor(cursor));
- }
- }
-
- return constraints;
- }
-
- public synchronized @NonNull List getAllDependencySpecs() {
- List dependencies = new LinkedList<>();
-
- try (Cursor cursor = databaseHelper.getReadableDatabase().query(Dependencies.TABLE_NAME, null, null, null, null, null, null)) {
- while (cursor != null && cursor.moveToNext()) {
- dependencies.add(dependencySpecFromCursor(cursor));
- }
- }
-
- return dependencies;
- }
-
- private void insertJobSpec(@NonNull SQLiteDatabase db, @NonNull JobSpec job) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Jobs.JOB_SPEC_ID, job.getId());
- contentValues.put(Jobs.FACTORY_KEY, job.getFactoryKey());
- contentValues.put(Jobs.QUEUE_KEY, job.getQueueKey());
- contentValues.put(Jobs.CREATE_TIME, job.getCreateTime());
- contentValues.put(Jobs.NEXT_RUN_ATTEMPT_TIME, job.getNextRunAttemptTime());
- contentValues.put(Jobs.RUN_ATTEMPT, job.getRunAttempt());
- contentValues.put(Jobs.MAX_ATTEMPTS, job.getMaxAttempts());
- contentValues.put(Jobs.MAX_BACKOFF, job.getMaxBackoff());
- contentValues.put(Jobs.MAX_INSTANCES, job.getMaxInstances());
- contentValues.put(Jobs.LIFESPAN, job.getLifespan());
- contentValues.put(Jobs.SERIALIZED_DATA, job.getSerializedData());
- contentValues.put(Jobs.IS_RUNNING, job.isRunning() ? 1 : 0);
-
- db.insertWithOnConflict(Jobs.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
- }
-
- private void insertConstraintSpecs(@NonNull SQLiteDatabase db, @NonNull List constraints) {
- for (ConstraintSpec constraintSpec : constraints) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Constraints.JOB_SPEC_ID, constraintSpec.getJobSpecId());
- contentValues.put(Constraints.FACTORY_KEY, constraintSpec.getFactoryKey());
- db.insertWithOnConflict(Constraints.TABLE_NAME, null ,contentValues, SQLiteDatabase.CONFLICT_IGNORE);
- }
- }
-
- private void insertDependencySpecs(@NonNull SQLiteDatabase db, @NonNull List dependencies) {
- for (DependencySpec dependencySpec : dependencies) {
- ContentValues contentValues = new ContentValues();
- contentValues.put(Dependencies.JOB_SPEC_ID, dependencySpec.getJobId());
- contentValues.put(Dependencies.DEPENDS_ON_JOB_SPEC_ID, dependencySpec.getDependsOnJobId());
- db.insertWithOnConflict(Dependencies.TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
- }
- }
-
- private @NonNull JobSpec jobSpecFromCursor(@NonNull Cursor cursor) {
- return new JobSpec(cursor.getString(cursor.getColumnIndexOrThrow(Jobs.JOB_SPEC_ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Jobs.FACTORY_KEY)),
- cursor.getString(cursor.getColumnIndexOrThrow(Jobs.QUEUE_KEY)),
- cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.CREATE_TIME)),
- cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.NEXT_RUN_ATTEMPT_TIME)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.RUN_ATTEMPT)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.MAX_ATTEMPTS)),
- cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.MAX_BACKOFF)),
- cursor.getLong(cursor.getColumnIndexOrThrow(Jobs.LIFESPAN)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.MAX_INSTANCES)),
- cursor.getString(cursor.getColumnIndexOrThrow(Jobs.SERIALIZED_DATA)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Jobs.IS_RUNNING)) == 1);
- }
-
- private @NonNull ConstraintSpec constraintSpecFromCursor(@NonNull Cursor cursor) {
- return new ConstraintSpec(cursor.getString(cursor.getColumnIndexOrThrow(Constraints.JOB_SPEC_ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Constraints.FACTORY_KEY)));
- }
-
- private @NonNull DependencySpec dependencySpecFromCursor(@NonNull Cursor cursor) {
- return new DependencySpec(cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.JOB_SPEC_ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Dependencies.DEPENDS_ON_JOB_SPEC_ID)));
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt
index 6aeadc2b7b..b0f6a676c7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/LokiAPIDatabase.kt
@@ -300,6 +300,11 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
val lastHash = database.insertOrUpdate(lastMessageHashValueTable2, row, query, arrayOf( snode.toString(), publicKey, namespace.toString() ))
}
+ override fun clearAllLastMessageHashes() {
+ val database = databaseHelper.writableDatabase
+ database.delete(lastMessageHashValueTable2, null, null)
+ }
+
override fun getReceivedMessageHashValues(publicKey: String, namespace: Int): Set? {
val database = databaseHelper.readableDatabase
val query = "${Companion.publicKey} = ? AND ${Companion.receivedMessageHashNamespace} = ?"
@@ -321,6 +326,11 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
database.insertOrUpdate(receivedMessageHashValuesTable, row, query, arrayOf( publicKey, namespace.toString() ))
}
+ override fun clearReceivedMessageHashValues() {
+ val database = databaseHelper.writableDatabase
+ database.delete(receivedMessageHashValuesTable, null, null)
+ }
+
override fun getAuthToken(server: String): String? {
val database = databaseHelper.readableDatabase
return database.get(openGroupAuthTokenTable, "${Companion.server} = ?", wrap(server)) { cursor ->
@@ -339,7 +349,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
}
override fun getLastMessageServerID(room: String, server: String): Long? {
- val database = databaseHelper.writableDatabase
+ val database = databaseHelper.readableDatabase
val index = "$server.$room"
return database.get(lastMessageServerIDTable, "$lastMessageServerIDTableIndex = ?", wrap(index)) { cursor ->
cursor.getInt(lastMessageServerID)
@@ -510,7 +520,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
}
fun getServerCapabilities(serverName: String): List {
- val database = databaseHelper.writableDatabase
+ val database = databaseHelper.readableDatabase
return database.get(serverCapabilitiesTable, "$server = ?", wrap(serverName)) { cursor ->
cursor.getString(capabilities)
}?.split(",") ?: emptyList()
@@ -523,7 +533,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
}
fun getLastInboxMessageId(serverName: String): Long? {
- val database = databaseHelper.writableDatabase
+ val database = databaseHelper.readableDatabase
return database.get(lastInboxMessageServerIdTable, "$server = ?", wrap(serverName)) { cursor ->
cursor.getInt(lastInboxMessageServerId)
}?.toLong()
@@ -540,7 +550,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
}
fun getLastOutboxMessageId(serverName: String): Long? {
- val database = databaseHelper.writableDatabase
+ val database = databaseHelper.readableDatabase
return database.get(lastOutboxMessageServerIdTable, "$server = ?", wrap(serverName)) { cursor ->
cursor.getInt(lastOutboxMessageServerId)
}?.toLong()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt
index a3f6395b15..45184c2d23 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/LokiMessageDatabase.kt
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.database
import android.content.ContentValues
import android.content.Context
-import net.sqlcipher.database.SQLiteDatabase.CONFLICT_REPLACE
+import net.zetetic.database.sqlcipher.SQLiteDatabase.CONFLICT_REPLACE
import org.session.libsignal.database.LokiMessageDatabaseProtocol
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
@@ -77,6 +77,25 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
database.endTransaction()
}
+ fun deleteMessages(messageIDs: List) {
+ val database = databaseHelper.writableDatabase
+ database.beginTransaction()
+
+ database.delete(
+ messageIDTable,
+ "${Companion.messageID} IN (${messageIDs.map { "?" }.joinToString(",")})",
+ messageIDs.map { "$it" }.toTypedArray()
+ )
+ database.delete(
+ messageThreadMappingTable,
+ "${Companion.messageID} IN (${messageIDs.map { "?" }.joinToString(",")})",
+ messageIDs.map { "$it" }.toTypedArray()
+ )
+
+ database.setTransactionSuccessful()
+ database.endTransaction()
+ }
+
/**
* @return pair of sms or mms table-specific ID and whether it is in SMS table
*/
@@ -96,6 +115,37 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
}
}
+ fun getMessageIDs(serverIDs: List, threadID: Long): Pair, List> {
+ val database = databaseHelper.readableDatabase
+
+ // Retrieve the message ids
+ val messageIdCursor = database
+ .rawQuery(
+ """
+ SELECT ${messageThreadMappingTable}.${messageID}, ${messageIDTable}.${messageType}
+ FROM ${messageThreadMappingTable}
+ JOIN ${messageIDTable} ON ${messageIDTable}.message_id = ${messageThreadMappingTable}.${messageID}
+ WHERE (
+ ${messageThreadMappingTable}.${Companion.threadID} = $threadID AND
+ ${messageThreadMappingTable}.${Companion.serverID} IN (${serverIDs.joinToString(",")})
+ )
+ """
+ )
+
+ val smsMessageIds: MutableList = mutableListOf()
+ val mmsMessageIds: MutableList = mutableListOf()
+ while (messageIdCursor.moveToNext()) {
+ if (messageIdCursor.getInt(1) == SMS_TYPE) {
+ smsMessageIds.add(messageIdCursor.getLong(0))
+ }
+ else {
+ mmsMessageIds.add(messageIdCursor.getLong(0))
+ }
+ }
+
+ return Pair(smsMessageIds, mmsMessageIds)
+ }
+
override fun setServerID(messageID: Long, serverID: Long, isSms: Boolean) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(3)
@@ -183,6 +233,15 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
database.delete(messageHashTable, "${Companion.messageID} = ?", arrayOf(messageID.toString()))
}
+ fun deleteMessageServerHashes(messageIDs: List) {
+ val database = databaseHelper.writableDatabase
+ database.delete(
+ messageHashTable,
+ "${Companion.messageID} IN (${messageIDs.map { "?" }.joinToString(",")})",
+ messageIDs.map { "$it" }.toTypedArray()
+ )
+ }
+
fun migrateThreadId(legacyThreadId: Long, newThreadId: Long) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(1)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
index f16d663a10..1b273de929 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
@@ -7,7 +7,7 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment;
import org.session.libsession.utilities.Address;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java
index ffde5ca029..edc6bc1a6f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessagingDatabase.java
@@ -5,7 +5,7 @@ import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.Document;
@@ -37,11 +37,19 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
public abstract void markExpireStarted(long messageId, long startTime);
public abstract void markAsSent(long messageId, boolean secure);
+
+ public abstract void markAsSyncing(long id);
+
+ public abstract void markAsResyncing(long id);
+
+ public abstract void markAsSyncFailed(long id);
+
public abstract void markUnidentified(long messageId, boolean unidentified);
- public abstract void markAsDeleted(long messageId, boolean read);
+ public abstract void markAsDeleted(long messageId, boolean read, boolean hasMention);
public abstract boolean deleteMessage(long messageId);
+ public abstract boolean deleteMessages(long[] messageId, long threadId);
public abstract void updateThreadId(long fromId, long toId);
@@ -198,7 +206,6 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
contentValues.put(THREAD_ID, newThreadId);
db.update(getTableName(), contentValues, where, args);
}
-
public static class SyncMessageId {
private final Address address;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt
index da9ec1ec30..b13a5e1ce2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt
@@ -36,6 +36,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
+import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.UNKNOWN
import org.session.libsession.utilities.Address.Companion.fromExternal
@@ -60,11 +61,13 @@ import org.thoughtcrime.securesms.database.SmsDatabase.InsertListener
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
import org.thoughtcrime.securesms.database.model.MessageRecord
+import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord
import org.thoughtcrime.securesms.database.model.Quote
import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get
import org.thoughtcrime.securesms.mms.MmsException
import org.thoughtcrime.securesms.mms.SlideDeck
+import org.thoughtcrime.securesms.util.asSequence
import java.io.Closeable
import java.io.IOException
import java.security.SecureRandom
@@ -91,54 +94,22 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
return 0
}
- fun addFailures(messageId: Long, failure: List) {
- try {
- addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList::class.java)
- } catch (e: IOException) {
- Log.w(TAG, e)
+ fun isOutgoingMessage(timestamp: Long): Boolean =
+ databaseHelper.writableDatabase.query(
+ TABLE_NAME,
+ arrayOf(ID, THREAD_ID, MESSAGE_BOX, ADDRESS),
+ DATE_SENT + " = ?",
+ arrayOf(timestamp.toString()),
+ null,
+ null,
+ null,
+ null
+ ).use { cursor ->
+ cursor.asSequence()
+ .map { cursor.getColumnIndexOrThrow(MESSAGE_BOX) }
+ .map(cursor::getLong)
+ .any { MmsSmsColumns.Types.isOutgoingMessageType(it) }
}
- }
-
- fun removeFailure(messageId: Long, failure: NetworkFailure?) {
- try {
- removeFromDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList::class.java)
- } catch (e: IOException) {
- Log.w(TAG, e)
- }
- }
-
- fun isOutgoingMessage(timestamp: Long): Boolean {
- val database = databaseHelper.writableDatabase
- var cursor: Cursor? = null
- var isOutgoing = false
- try {
- cursor = database.query(
- TABLE_NAME,
- arrayOf(ID, THREAD_ID, MESSAGE_BOX, ADDRESS),
- DATE_SENT + " = ?",
- arrayOf(timestamp.toString()),
- null,
- null,
- null,
- null
- )
- while (cursor.moveToNext()) {
- if (MmsSmsColumns.Types.isOutgoingMessageType(
- cursor.getLong(
- cursor.getColumnIndexOrThrow(
- MESSAGE_BOX
- )
- )
- )
- ) {
- isOutgoing = true
- }
- }
- } finally {
- cursor?.close()
- }
- return isOutgoing
- }
fun incrementReceiptCount(
messageId: SyncMessageId,
@@ -254,15 +225,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
}
}
- private fun getThreadIdFor(notification: NotificationInd): Long {
- val fromString =
- if (notification.from != null && notification.from.textString != null) toIsoString(
- notification.from.textString
- ) else ""
- val recipient = Recipient.from(context, fromExternal(context, fromString), false)
- return get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
- }
-
private fun rawQuery(where: String, arguments: Array?): Cursor {
val database = databaseHelper.readableDatabase
return database.rawQuery(
@@ -273,10 +235,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
)
}
- fun getMessages(idsAsString: String): Cursor {
- return rawQuery(idsAsString, null)
- }
-
fun getMessage(messageId: Long): Cursor {
val cursor = rawQuery(RAW_ID_WHERE, arrayOf(messageId.toString()))
setNotifyConverationListeners(cursor, getThreadIdForMessage(messageId))
@@ -312,48 +270,40 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
}
}
- fun markAsPendingInsecureSmsFallback(messageId: Long) {
- val threadId = getThreadIdForMessage(messageId)
+ private fun markAs(
+ messageId: Long,
+ baseType: Long,
+ threadId: Long = getThreadIdForMessage(messageId)
+ ) {
updateMailboxBitmask(
messageId,
MmsSmsColumns.Types.BASE_TYPE_MASK,
- MmsSmsColumns.Types.BASE_PENDING_INSECURE_SMS_FALLBACK,
+ baseType,
Optional.of(threadId)
)
notifyConversationListeners(threadId)
}
+ override fun markAsSyncing(messageId: Long) {
+ markAs(messageId, MmsSmsColumns.Types.BASE_SYNCING_TYPE)
+ }
+ override fun markAsResyncing(messageId: Long) {
+ markAs(messageId, MmsSmsColumns.Types.BASE_RESYNCING_TYPE)
+ }
+ override fun markAsSyncFailed(messageId: Long) {
+ markAs(messageId, MmsSmsColumns.Types.BASE_SYNC_FAILED_TYPE)
+ }
+
fun markAsSending(messageId: Long) {
- val threadId = getThreadIdForMessage(messageId)
- updateMailboxBitmask(
- messageId,
- MmsSmsColumns.Types.BASE_TYPE_MASK,
- MmsSmsColumns.Types.BASE_SENDING_TYPE,
- Optional.of(threadId)
- )
- notifyConversationListeners(threadId)
+ markAs(messageId, MmsSmsColumns.Types.BASE_SENDING_TYPE)
}
fun markAsSentFailed(messageId: Long) {
- val threadId = getThreadIdForMessage(messageId)
- updateMailboxBitmask(
- messageId,
- MmsSmsColumns.Types.BASE_TYPE_MASK,
- MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE,
- Optional.of(threadId)
- )
- notifyConversationListeners(threadId)
+ markAs(messageId, MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE)
}
override fun markAsSent(messageId: Long, secure: Boolean) {
- val threadId = getThreadIdForMessage(messageId)
- updateMailboxBitmask(
- messageId,
- MmsSmsColumns.Types.BASE_TYPE_MASK,
- MmsSmsColumns.Types.BASE_SENT_TYPE or if (secure) MmsSmsColumns.Types.PUSH_MESSAGE_BIT or MmsSmsColumns.Types.SECURE_MESSAGE_BIT else 0,
- Optional.of(threadId)
- )
- notifyConversationListeners(threadId)
+ markAs(messageId, MmsSmsColumns.Types.BASE_SENT_TYPE or if (secure) MmsSmsColumns.Types.PUSH_MESSAGE_BIT or MmsSmsColumns.Types.SECURE_MESSAGE_BIT else 0)
}
override fun markUnidentified(messageId: Long, unidentified: Boolean) {
@@ -363,29 +313,25 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
db.update(TABLE_NAME, contentValues, ID_WHERE, arrayOf(messageId.toString()))
}
- override fun markAsDeleted(messageId: Long, read: Boolean) {
+ override fun markAsDeleted(messageId: Long, read: Boolean, hasMention: Boolean) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues()
contentValues.put(READ, 1)
contentValues.put(BODY, "")
+ contentValues.put(HAS_MENTION, 0)
database.update(TABLE_NAME, contentValues, ID_WHERE, arrayOf(messageId.toString()))
val attachmentDatabase = get(context).attachmentDatabase()
queue(Runnable { attachmentDatabase.deleteAttachmentsForMessage(messageId) })
val threadId = getThreadIdForMessage(messageId)
if (!read) {
- get(context).threadDatabase().decrementUnread(threadId, 1)
+ val mentionChange = if (hasMention) { 1 } else { 0 }
+ get(context).threadDatabase().decrementUnread(threadId, 1, mentionChange)
}
- updateMailboxBitmask(
- messageId,
- MmsSmsColumns.Types.BASE_TYPE_MASK,
- MmsSmsColumns.Types.BASE_DELETED_TYPE,
- Optional.of(threadId)
- )
- notifyConversationListeners(threadId)
+ markAs(messageId, MmsSmsColumns.Types.BASE_DELETED_TYPE, threadId)
}
override fun markExpireStarted(messageId: Long) {
- markExpireStarted(messageId, System.currentTimeMillis())
+ markExpireStarted(messageId, SnodeAPI.nowWithOffset)
}
override fun markExpireStarted(messageId: Long, startedTimestamp: Long) {
@@ -411,10 +357,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
)
}
- fun setAllMessagesRead(): List {
- return setMessagesRead(READ + " = 0", null)
- }
-
private fun setMessagesRead(where: String, arguments: Array?): List {
val database = databaseHelper.writableDatabase
val result: MutableList = LinkedList()
@@ -423,7 +365,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
try {
cursor = database.query(
TABLE_NAME,
- arrayOf(ID, ADDRESS, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED),
+ arrayOf(ID, ADDRESS, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED),
where,
arguments,
null,
@@ -669,6 +611,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
contentValues.put(EXPIRES_IN, retrieved.expiresIn)
contentValues.put(EXPIRE_STARTED, retrieved.expireStartedAt)
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified)
+ contentValues.put(HAS_MENTION, retrieved.hasMention())
contentValues.put(MESSAGE_REQUEST_RESPONSE, retrieved.isMessageRequestResponse)
if (!contentValues.containsKey(DATE_SENT)) {
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED))
@@ -700,7 +643,8 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
)
if (!MmsSmsColumns.Types.isExpirationTimerUpdate(mailbox)) {
if (runIncrement) {
- get(context).threadDatabase().incrementUnread(threadId, 1)
+ val mentionAmount = if (retrieved.hasMention()) { 1 } else { 0 }
+ get(context).threadDatabase().incrementUnread(threadId, 1, mentionAmount)
}
if (runThreadUpdate) {
get(context).threadDatabase().update(threadId, true)
@@ -805,7 +749,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
// In open groups messages should be sorted by their server timestamp
var receivedTimestamp = serverTimestamp
if (serverTimestamp == 0L) {
- receivedTimestamp = System.currentTimeMillis()
+ receivedTimestamp = SnodeAPI.nowWithOffset
}
contentValues.put(DATE_RECEIVED, receivedTimestamp)
contentValues.put(SUBSCRIPTION_ID, message.subscriptionId)
@@ -1007,6 +951,23 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
return threadDeleted
}
+ override fun deleteMessages(messageIds: LongArray, threadId: Long): Boolean {
+ val attachmentDatabase = get(context).attachmentDatabase()
+ val groupReceiptDatabase = get(context).groupReceiptDatabase()
+
+ queue(Runnable { attachmentDatabase.deleteAttachmentsForMessages(messageIds) })
+ groupReceiptDatabase.deleteRowsForMessages(messageIds)
+
+ val database = databaseHelper.writableDatabase
+ database!!.delete(TABLE_NAME, ID_IN, arrayOf(messageIds.joinToString(",")))
+
+ val threadDeleted = get(context).threadDatabase().update(threadId, false)
+ notifyConversationListeners(threadId)
+ notifyStickerListeners()
+ notifyStickerPackListeners()
+ return threadDeleted
+ }
+
override fun updateThreadId(fromId: Long, toId: Long) {
val contentValues = ContentValues(1)
contentValues.put(THREAD_ID, toId)
@@ -1274,7 +1235,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
val slideDeck = SlideDeck(context, message!!.attachments)
return MediaMmsMessageRecord(
id, message.recipient, message.recipient,
- 1, System.currentTimeMillis(), System.currentTimeMillis(),
+ 1, SnodeAPI.nowWithOffset, SnodeAPI.nowWithOffset,
0, threadId, message.body,
slideDeck, slideDeck.slides.size,
if (message.isSecure) MmsSmsColumns.Types.getOutgoingEncryptedMessageType() else MmsSmsColumns.Types.getOutgoingSmsMessageType(),
@@ -1282,7 +1243,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
LinkedList(),
message.subscriptionId,
message.expiresIn,
- System.currentTimeMillis(), 0,
+ SnodeAPI.nowWithOffset, 0,
if (message.outgoingQuote != null) Quote(
message.outgoingQuote!!.id,
message.outgoingQuote!!.author,
@@ -1290,7 +1251,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
message.outgoingQuote!!.missing,
SlideDeck(context, message.outgoingQuote!!.attachments!!)
) else null,
- message.sharedContacts, message.linkPreviews, listOf(), false
+ message.sharedContacts, message.linkPreviews, listOf(), false, false
)
}
@@ -1334,6 +1295,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
)
var readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(READ_RECEIPT_COUNT))
val subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))
+ val hasMention = (cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1)
if (!isReadReceiptsEnabled(context)) {
readReceiptCount = 0
}
@@ -1351,7 +1313,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
dateSent, dateReceived, deliveryReceiptCount, threadId,
contentLocationBytes, messageSize, expiry, status,
transactionIdBytes, mailbox, slideDeck,
- readReceiptCount
+ readReceiptCount, hasMention
)
}
@@ -1385,6 +1347,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
val expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN))
val expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED))
val unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED)) == 1
+ val hasMention = cursor.getInt(cursor.getColumnIndexOrThrow(HAS_MENTION)) == 1
if (!isReadReceiptsEnabled(context)) {
readReceiptCount = 0
}
@@ -1394,25 +1357,16 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
val attachments = get(context).attachmentDatabase().getAttachment(
cursor
)
- val contacts: List = getSharedContacts(
- cursor, attachments
- )
- val contactAttachments =
- contacts.map { obj: Contact? -> obj!!.avatarAttachment }
- .filter { a: Attachment? -> a != null }
- .toSet()
- val previews: List = getLinkPreviews(
- cursor, attachments
- )
- val previewAttachments =
- previews.filter { lp: LinkPreview? -> lp!!.getThumbnail().isPresent }
- .map { lp: LinkPreview? -> lp!!.getThumbnail().get() }
- .toSet()
+ val contacts: List = getSharedContacts(cursor, attachments)
+ val contactAttachments: Set =
+ contacts.mapNotNull { it?.avatarAttachment }.toSet()
+ val previews: List = getLinkPreviews(cursor, attachments)
+ val previewAttachments: Set =
+ previews.mapNotNull { it?.getThumbnail()?.orNull() }.toSet()
val slideDeck = getSlideDeck(
- Stream.of(attachments)
- .filterNot { o: DatabaseAttachment? -> contactAttachments.contains(o) }
- .filterNot { o: DatabaseAttachment? -> previewAttachments.contains(o) }
- .toList()
+ attachments
+ .filterNot { o: DatabaseAttachment? -> o in contactAttachments }
+ .filterNot { o: DatabaseAttachment? -> o in previewAttachments }
)
val quote = getQuote(cursor)
val reactions = get(context).reactionDatabase().getReactions(cursor)
@@ -1421,7 +1375,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
addressDeviceId, dateSent, dateReceived, deliveryReceiptCount,
threadId, body, slideDeck!!, partCount, box, mismatches,
networkFailures, subscriptionId, expiresIn, expireStarted,
- readReceiptCount, quote, contacts, previews, reactions, unidentified
+ readReceiptCount, quote, contacts, previews, reactions, unidentified, hasMention
)
}
@@ -1470,11 +1424,13 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
val retrievedQuote = get(context).mmsSmsDatabase().getMessageFor(quoteId, quoteAuthor)
val quoteText = retrievedQuote?.body
val quoteMissing = retrievedQuote == null
- val attachments = get(context).attachmentDatabase().getAttachment(cursor)
- val quoteAttachments: List? =
- Stream.of(attachments).filter { obj: DatabaseAttachment? -> obj!!.isQuote }
+ val quoteDeck = (
+ (retrievedQuote as? MmsMessageRecord)?.slideDeck ?:
+ Stream.of(get(context).attachmentDatabase().getAttachment(cursor))
+ .filter { obj: DatabaseAttachment? -> obj!!.isQuote }
.toList()
- val quoteDeck = SlideDeck(context, quoteAttachments!!)
+ .let { SlideDeck(context, it) }
+ )
return Quote(
quoteId,
fromExternal(context, quoteAuthor),
@@ -1574,6 +1530,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
SHARED_CONTACTS,
LINK_PREVIEWS,
UNIDENTIFIED,
+ HAS_MENTION,
"json_group_array(json_object(" +
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
@@ -1614,5 +1571,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
const val CREATE_MESSAGE_REQUEST_RESPONSE_COMMAND = "ALTER TABLE $TABLE_NAME ADD COLUMN $MESSAGE_REQUEST_RESPONSE INTEGER DEFAULT 0;"
const val CREATE_REACTIONS_UNREAD_COMMAND = "ALTER TABLE $TABLE_NAME ADD COLUMN $REACTIONS_UNREAD INTEGER DEFAULT 0;"
const val CREATE_REACTIONS_LAST_SEEN_COMMAND = "ALTER TABLE $TABLE_NAME ADD COLUMN $REACTIONS_LAST_SEEN INTEGER DEFAULT 0;"
+ const val CREATE_HAS_MENTION_COMMAND = "ALTER TABLE $TABLE_NAME ADD COLUMN $HAS_MENTION INTEGER DEFAULT 0;"
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java
index c4fe3d2437..1e1cc50896 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java
@@ -24,6 +24,8 @@ public interface MmsSmsColumns {
public static final String REACTIONS_UNREAD = "reactions_unread";
public static final String REACTIONS_LAST_SEEN = "reactions_last_seen";
+ public static final String HAS_MENTION = "has_mention";
+
public static class Types {
protected static final long TOTAL_MASK = 0xFFFFFFFF;
@@ -45,8 +47,13 @@ public interface MmsSmsColumns {
protected static final long BASE_PENDING_INSECURE_SMS_FALLBACK = 26;
public static final long BASE_DRAFT_TYPE = 27;
protected static final long BASE_DELETED_TYPE = 28;
+ protected static final long BASE_SYNCING_TYPE = 29;
+ protected static final long BASE_RESYNCING_TYPE = 30;
+ protected static final long BASE_SYNC_FAILED_TYPE = 31;
protected static final long[] OUTGOING_MESSAGE_TYPES = {BASE_OUTBOX_TYPE, BASE_SENT_TYPE,
+ BASE_SYNCING_TYPE, BASE_RESYNCING_TYPE,
+ BASE_SYNC_FAILED_TYPE,
BASE_SENDING_TYPE, BASE_SENT_FAILED_TYPE,
BASE_PENDING_SECURE_SMS_FALLBACK,
BASE_PENDING_INSECURE_SMS_FALLBACK,
@@ -107,6 +114,18 @@ public interface MmsSmsColumns {
return (type & BASE_TYPE_MASK) == BASE_DRAFT_TYPE;
}
+ public static boolean isResyncingType(long type) {
+ return (type & BASE_TYPE_MASK) == BASE_RESYNCING_TYPE;
+ }
+
+ public static boolean isSyncingType(long type) {
+ return (type & BASE_TYPE_MASK) == BASE_SYNCING_TYPE;
+ }
+
+ public static boolean isSyncFailedMessageType(long type) {
+ return (type & BASE_TYPE_MASK) == BASE_SYNC_FAILED_TYPE;
+ }
+
public static boolean isFailedMessageType(long type) {
return (type & BASE_TYPE_MASK) == BASE_SENT_FAILED_TYPE;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
index b3afeac477..c7f9d61324 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
@@ -22,8 +22,8 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import net.sqlcipher.database.SQLiteDatabase;
-import net.sqlcipher.database.SQLiteQueryBuilder;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteQueryBuilder;
import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.Util;
@@ -75,7 +75,9 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.QUOTE_ATTACHMENT,
MmsDatabase.SHARED_CONTACTS,
MmsDatabase.LINK_PREVIEWS,
- ReactionDatabase.REACTION_JSON_ALIAS};
+ ReactionDatabase.REACTION_JSON_ALIAS,
+ MmsSmsColumns.HAS_MENTION
+ };
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
@@ -186,7 +188,7 @@ public class MmsSmsDatabase extends Database {
}
public Cursor getConversationSnippet(long threadId) {
- String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
+ String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
return queryTables(PROJECTION, selection, order, null);
@@ -203,7 +205,7 @@ public class MmsSmsDatabase extends Database {
}
public Cursor getUnread() {
- String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
+ String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " ASC";
String selection = "(" + MmsSmsColumns.READ + " = 0 OR " + MmsSmsColumns.REACTIONS_UNREAD + " = 1) AND " + MmsSmsColumns.NOTIFIED + " = 0";
return queryTables(PROJECTION, selection, order, null);
@@ -238,7 +240,7 @@ public class MmsSmsDatabase extends Database {
}
public int getQuotedMessagePosition(long threadId, long quoteId, @NonNull Address address) {
- String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
+ String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.ADDRESS }, selection, order, null)) {
@@ -337,7 +339,9 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.QUOTE_MISSING,
MmsDatabase.QUOTE_ATTACHMENT,
MmsDatabase.SHARED_CONTACTS,
- MmsDatabase.LINK_PREVIEWS};
+ MmsDatabase.LINK_PREVIEWS,
+ MmsSmsColumns.HAS_MENTION
+ };
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
@@ -364,7 +368,9 @@ public class MmsSmsDatabase extends Database {
MmsDatabase.QUOTE_MISSING,
MmsDatabase.QUOTE_ATTACHMENT,
MmsDatabase.SHARED_CONTACTS,
- MmsDatabase.LINK_PREVIEWS};
+ MmsDatabase.LINK_PREVIEWS,
+ MmsSmsColumns.HAS_MENTION
+ };
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
@@ -408,6 +414,7 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(MmsDatabase.STATUS);
mmsColumnsPresent.add(MmsDatabase.UNIDENTIFIED);
mmsColumnsPresent.add(MmsDatabase.NETWORK_FAILURE);
+ mmsColumnsPresent.add(MmsSmsColumns.HAS_MENTION);
mmsColumnsPresent.add(AttachmentDatabase.ROW_ID);
mmsColumnsPresent.add(AttachmentDatabase.UNIQUE_ID);
@@ -470,6 +477,7 @@ public class MmsSmsDatabase extends Database {
smsColumnsPresent.add(SmsDatabase.DATE_RECEIVED);
smsColumnsPresent.add(SmsDatabase.STATUS);
smsColumnsPresent.add(SmsDatabase.UNIDENTIFIED);
+ smsColumnsPresent.add(MmsSmsColumns.HAS_MENTION);
smsColumnsPresent.add(ReactionDatabase.ROW_ID);
smsColumnsPresent.add(ReactionDatabase.MESSAGE_ID);
smsColumnsPresent.add(ReactionDatabase.IS_MMS);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/PushDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/PushDatabase.java
index d1ba25aa7e..b832d04dfc 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/PushDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/PushDatabase.java
@@ -6,7 +6,7 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import org.session.libsignal.utilities.Log;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.session.libsignal.utilities.Base64;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ReactionDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ReactionDatabase.kt
index 74e452db07..87c0b6c182 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/ReactionDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/ReactionDatabase.kt
@@ -48,6 +48,14 @@ class ReactionDatabase(context: Context, helper: SQLCipherOpenHelper) : Database
)
""".trimIndent()
+ @JvmField
+ val CREATE_INDEXS = arrayOf(
+ "CREATE INDEX IF NOT EXISTS reaction_message_id_index ON " + ReactionDatabase.TABLE_NAME + " (" + ReactionDatabase.MESSAGE_ID + ");",
+ "CREATE INDEX IF NOT EXISTS reaction_is_mms_index ON " + ReactionDatabase.TABLE_NAME + " (" + ReactionDatabase.IS_MMS + ");",
+ "CREATE INDEX IF NOT EXISTS reaction_message_id_is_mms_index ON " + ReactionDatabase.TABLE_NAME + " (" + ReactionDatabase.MESSAGE_ID + ", " + ReactionDatabase.IS_MMS + ");",
+ "CREATE INDEX IF NOT EXISTS reaction_sort_id_index ON " + ReactionDatabase.TABLE_NAME + " (" + ReactionDatabase.SORT_ID + ");",
+ )
+
@JvmField
val CREATE_REACTION_TRIGGERS = arrayOf(
"""
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
index 525391c63f..fe076916c2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java
@@ -11,7 +11,7 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.MaterialColor;
@@ -284,7 +284,7 @@ public class RecipientDatabase extends Database {
notifyRecipientListeners();
}
- public void setBlocked(@NonNull List recipients, boolean blocked) {
+ public void setBlocked(@NonNull Iterable recipients, boolean blocked) {
SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java
index 6bce73e227..eac6a5fbc3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchDatabase.java
@@ -1,13 +1,13 @@
package org.thoughtcrime.securesms.database;
import android.content.Context;
+import android.database.Cursor;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
-import net.sqlcipher.Cursor;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.session.libsession.utilities.Util;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SessionContactDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SessionContactDatabase.kt
index ef9f0cc383..40eee97428 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SessionContactDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SessionContactDatabase.kt
@@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.database
import android.content.ContentValues
import android.content.Context
import androidx.core.database.getStringOrNull
-import net.sqlcipher.Cursor
+import android.database.Cursor
import org.session.libsession.messaging.contacts.Contact
import org.session.libsignal.utilities.Base64
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
@@ -75,21 +75,6 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
}
fun contactFromCursor(cursor: Cursor): Contact {
- val sessionID = cursor.getString(sessionID)
- val contact = Contact(sessionID)
- contact.name = cursor.getStringOrNull(name)
- contact.nickname = cursor.getStringOrNull(nickname)
- contact.profilePictureURL = cursor.getStringOrNull(profilePictureURL)
- contact.profilePictureFileName = cursor.getStringOrNull(profilePictureFileName)
- cursor.getStringOrNull(profilePictureEncryptionKey)?.let {
- contact.profilePictureEncryptionKey = Base64.decode(it)
- }
- contact.threadID = cursor.getLong(threadID)
- contact.isTrusted = cursor.getInt(isTrusted) != 0
- return contact
- }
-
- fun contactFromCursor(cursor: android.database.Cursor): Contact {
val sessionID = cursor.getString(cursor.getColumnIndexOrThrow(sessionID))
val contact = Contact(sessionID)
contact.name = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(name))
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt
index 595168fdf7..b081fb007e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SessionJobDatabase.kt
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.database
import android.content.ContentValues
import android.content.Context
-import net.sqlcipher.Cursor
+import android.database.Cursor
import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.BackgroundGroupAddJob
import org.session.libsession.messaging.jobs.GroupAvatarDownloadJob
@@ -46,7 +46,7 @@ class SessionJobDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
databaseHelper.writableDatabase.delete(sessionJobTable, "${Companion.jobID} = ?", arrayOf( jobID ))
}
- fun getAllPendingJobs(type: String): Map {
+ fun getAllJobs(type: String): Map {
val database = databaseHelper.readableDatabase
return database.getAll(sessionJobTable, "$jobType = ?", arrayOf( type )) { cursor ->
val jobID = cursor.getString(jobID)
@@ -83,11 +83,11 @@ class SessionJobDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
}
}
- fun getGroupAvatarDownloadJob(server: String, room: String): GroupAvatarDownloadJob? {
+ fun getGroupAvatarDownloadJob(server: String, room: String, imageId: String?): GroupAvatarDownloadJob? {
val database = databaseHelper.readableDatabase
return database.getAll(sessionJobTable, "$jobType = ?", arrayOf(GroupAvatarDownloadJob.KEY)) {
jobFromCursor(it) as GroupAvatarDownloadJob?
- }.filterNotNull().find { it.server == server && it.room == room }
+ }.filterNotNull().find { it.server == server && it.room == room && (imageId == null || it.imageId == imageId) }
}
fun cancelPendingMessageSendJobs(threadID: Long) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
index bd05c0a7a7..dc458d0f35 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
@@ -28,13 +28,15 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
-import net.sqlcipher.database.SQLiteDatabase;
-import net.sqlcipher.database.SQLiteStatement;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteStatement;
+import org.apache.commons.lang3.StringUtils;
import org.session.libsession.messaging.calls.CallMessageType;
import org.session.libsession.messaging.messages.signal.IncomingGroupMessage;
import org.session.libsession.messaging.messages.signal.IncomingTextMessage;
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
+import org.session.libsession.snode.SnodeAPI;
import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.IdentityKeyMismatch;
import org.session.libsession.utilities.IdentityKeyMismatchList;
@@ -53,6 +55,7 @@ import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
import java.io.Closeable;
import java.io.IOException;
import java.security.SecureRandom;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -104,7 +107,7 @@ public class SmsDatabase extends MessagingDatabase {
PROTOCOL, READ, STATUS, TYPE,
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, DELIVERY_RECEIPT_COUNT,
MISMATCHED_IDENTITIES, SUBSCRIPTION_ID, EXPIRES_IN, EXPIRE_STARTED,
- NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED,
+ NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED, HAS_MENTION,
"json_group_array(json_object(" +
"'" + ReactionDatabase.ROW_ID + "', " + ReactionDatabase.TABLE_NAME + "." + ReactionDatabase.ROW_ID + ", " +
"'" + ReactionDatabase.MESSAGE_ID + "', " + ReactionDatabase.TABLE_NAME + "." + ReactionDatabase.MESSAGE_ID + ", " +
@@ -122,6 +125,9 @@ public class SmsDatabase extends MessagingDatabase {
public static String CREATE_REACTIONS_UNREAD_COMMAND = "ALTER TABLE "+ TABLE_NAME + " " +
"ADD COLUMN " + REACTIONS_UNREAD + " INTEGER DEFAULT 0;";
+ public static String CREATE_HAS_MENTION_COMMAND = "ALTER TABLE "+ TABLE_NAME + " " +
+ "ADD COLUMN " + HAS_MENTION + " INTEGER DEFAULT 0;";
+
private static final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache();
private static final EarlyReceiptCache earlyReadReceiptCache = new EarlyReceiptCache();
@@ -197,6 +203,21 @@ public class SmsDatabase extends MessagingDatabase {
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE);
}
+ @Override
+ public void markAsSyncing(long id) {
+ updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SYNCING_TYPE);
+ }
+
+ @Override
+ public void markAsResyncing(long id) {
+ updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_RESYNCING_TYPE);
+ }
+
+ @Override
+ public void markAsSyncFailed(long id) {
+ updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SYNC_FAILED_TYPE);
+ }
+
@Override
public void markUnidentified(long id, boolean unidentified) {
ContentValues contentValues = new ContentValues(1);
@@ -207,20 +228,23 @@ public class SmsDatabase extends MessagingDatabase {
}
@Override
- public void markAsDeleted(long messageId, boolean read) {
+ public void markAsDeleted(long messageId, boolean read, boolean hasMention) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(READ, 1);
contentValues.put(BODY, "");
+ contentValues.put(HAS_MENTION, 0);
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(messageId)});
long threadId = getThreadIdForMessage(messageId);
- if (!read) { DatabaseComponent.get(context).threadDatabase().decrementUnread(threadId, 1); }
+ if (!read) {
+ DatabaseComponent.get(context).threadDatabase().decrementUnread(threadId, 1, (hasMention ? 1 : 0));
+ }
updateTypeBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_DELETED_TYPE);
}
@Override
public void markExpireStarted(long id) {
- markExpireStarted(id, System.currentTimeMillis());
+ markExpireStarted(id, SnodeAPI.getNowWithOffset());
}
@Override
@@ -433,6 +457,7 @@ public class SmsDatabase extends MessagingDatabase {
values.put(EXPIRES_IN, message.getExpiresIn());
values.put(EXPIRE_STARTED, message.getExpireStartedAt());
values.put(UNIDENTIFIED, message.isUnidentified());
+ values.put(HAS_MENTION, message.hasMention());
if (!TextUtils.isEmpty(message.getPseudoSubject()))
values.put(SUBJECT, message.getPseudoSubject());
@@ -451,7 +476,7 @@ public class SmsDatabase extends MessagingDatabase {
long messageId = db.insert(TABLE_NAME, null, values);
if (unread && runIncrement) {
- DatabaseComponent.get(context).threadDatabase().incrementUnread(threadId, 1);
+ DatabaseComponent.get(context).threadDatabase().incrementUnread(threadId, 1, (message.hasMention() ? 1 : 0));
}
if (runThreadUpdate) {
@@ -529,7 +554,7 @@ public class SmsDatabase extends MessagingDatabase {
contentValues.put(ADDRESS, address.serialize());
contentValues.put(THREAD_ID, threadId);
contentValues.put(BODY, message.getMessageBody());
- contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
+ contentValues.put(DATE_RECEIVED, SnodeAPI.getNowWithOffset());
contentValues.put(DATE_SENT, message.getSentTimestampMillis());
contentValues.put(READ, 1);
contentValues.put(TYPE, type);
@@ -610,6 +635,30 @@ public class SmsDatabase extends MessagingDatabase {
return threadDeleted;
}
+ @Override
+ public boolean deleteMessages(long[] messageIds, long threadId) {
+ String[] argsArray = new String[messageIds.length];
+ String[] argValues = new String[messageIds.length];
+ Arrays.fill(argsArray, "?");
+
+ for (int i = 0; i < messageIds.length; i++) {
+ argValues[i] = (messageIds[i] + "");
+ }
+
+ String combinedMessageIdArgss = StringUtils.join(messageIds, ',');
+ String combinedMessageIds = StringUtils.join(messageIds, ',');
+ Log.i("MessageDatabase", "Deleting: " + combinedMessageIds);
+ SQLiteDatabase db = databaseHelper.getWritableDatabase();
+ db.delete(
+ TABLE_NAME,
+ ID + " IN (" + StringUtils.join(argsArray, ',') + ")",
+ argValues
+ );
+ boolean threadDeleted = DatabaseComponent.get(context).threadDatabase().update(threadId, false);
+ notifyConversationListeners(threadId);
+ return threadDeleted;
+ }
+
@Override
public void updateThreadId(long fromId, long toId) {
ContentValues contentValues = new ContentValues(1);
@@ -752,11 +801,11 @@ public class SmsDatabase extends MessagingDatabase {
public MessageRecord getCurrent() {
return new SmsMessageRecord(id, message.getMessageBody(),
message.getRecipient(), message.getRecipient(),
- System.currentTimeMillis(), System.currentTimeMillis(),
+ SnodeAPI.getNowWithOffset(), SnodeAPI.getNowWithOffset(),
0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(),
threadId, 0, new LinkedList(),
message.getExpiresIn(),
- System.currentTimeMillis(), 0, false, Collections.emptyList());
+ SnodeAPI.getNowWithOffset(), 0, false, Collections.emptyList(), false);
}
}
@@ -797,6 +846,7 @@ public class SmsDatabase extends MessagingDatabase {
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.UNIDENTIFIED)) == 1;
+ boolean hasMention = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.HAS_MENTION)) == 1;
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
readReceiptCount = 0;
@@ -810,7 +860,7 @@ public class SmsDatabase extends MessagingDatabase {
recipient,
dateSent, dateReceived, deliveryReceiptCount, type,
threadId, status, mismatches,
- expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
+ expiresIn, expireStarted, readReceiptCount, unidentified, reactions, hasMention);
}
private List getMismatches(String document) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
index 75660f7ecc..c1a1d4c1ef 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.database
import android.content.Context
import android.net.Uri
+import org.session.libsession.avatars.AvatarHelper
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.BlindedIdMapping
import org.session.libsession.messaging.calls.CallMessageType
@@ -24,10 +25,12 @@ import org.session.libsession.messaging.messages.signal.OutgoingGroupMediaMessag
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
import org.session.libsession.messaging.messages.visible.Attachment
+import org.session.libsession.messaging.messages.visible.Profile
import org.session.libsession.messaging.messages.visible.Reaction
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.GroupMember
import org.session.libsession.messaging.open_groups.OpenGroup
+import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
@@ -52,15 +55,15 @@ import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.guava.Optional
-import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.ReactionRecord
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.groups.OpenGroupManager
-import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
+import org.session.libsession.messaging.jobs.RetrieveProfileAvatarJob
import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.util.SessionMetaProtocol
+import java.security.MessageDigest
class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol {
@@ -72,25 +75,16 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
return DatabaseComponent.get(context).lokiAPIDatabase().getUserX25519KeyPair()
}
- override fun getUserDisplayName(): String? {
- return TextSecurePreferences.getProfileName(context)
+ override fun getUserProfile(): Profile {
+ val displayName = TextSecurePreferences.getProfileName(context)!!
+ val profileKey = ProfileKeyUtil.getProfileKey(context)
+ val profilePictureUrl = TextSecurePreferences.getProfilePictureURL(context)
+ return Profile(displayName, profileKey, profilePictureUrl)
}
- override fun getUserProfileKey(): ByteArray? {
- return ProfileKeyUtil.getProfileKey(context)
- }
-
- override fun getUserProfilePictureURL(): String? {
- return TextSecurePreferences.getProfilePictureURL(context)
- }
-
- override fun setUserProfilePictureURL(newValue: String) {
- val ourRecipient = fromSerialized(getUserPublicKey()!!).let {
- Recipient.from(context, it, false)
- }
- TextSecurePreferences.setProfilePictureURL(context, newValue)
- RetrieveProfileAvatarJob(ourRecipient, newValue)
- ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(ourRecipient, newValue))
+ override fun setProfileAvatar(recipient: Recipient, profileAvatar: String?) {
+ val database = DatabaseComponent.get(context).recipientDatabase()
+ database.setProfileAvatar(recipient, profileAvatar)
}
override fun getOrGenerateRegistrationID(): Int {
@@ -118,9 +112,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
threadDb.setRead(threadId, updateLastSeen)
}
- override fun incrementUnread(threadId: Long, amount: Int) {
+ override fun incrementUnread(threadId: Long, amount: Int, unreadMentionAmount: Int) {
val threadDb = DatabaseComponent.get(context).threadDatabase()
- threadDb.incrementUnread(threadId, amount)
+ threadDb.incrementUnread(threadId, amount, unreadMentionAmount)
}
override fun updateThread(threadId: Long, unarchive: Boolean) {
@@ -239,7 +233,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
override fun getAllPendingJobs(type: String): Map {
- return DatabaseComponent.get(context).sessionJobDatabase().getAllPendingJobs(type)
+ return DatabaseComponent.get(context).sessionJobDatabase().getAllJobs(type)
}
override fun getAttachmentUploadJob(attachmentID: Long): AttachmentUploadJob? {
@@ -254,8 +248,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
return DatabaseComponent.get(context).sessionJobDatabase().getMessageReceiveJob(messageReceiveJobID)
}
- override fun getGroupAvatarDownloadJob(server: String, room: String): GroupAvatarDownloadJob? {
- return DatabaseComponent.get(context).sessionJobDatabase().getGroupAvatarDownloadJob(server, room)
+ override fun getGroupAvatarDownloadJob(server: String, room: String, imageId: String?): GroupAvatarDownloadJob? {
+ return DatabaseComponent.get(context).sessionJobDatabase().getGroupAvatarDownloadJob(server, room, imageId)
}
override fun resumeMessageSendJobIfNeeded(messageSendJobID: String) {
@@ -352,6 +346,14 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
DatabaseComponent.get(context).groupDatabase().updateProfilePicture(groupID, newValue)
}
+ override fun removeProfilePicture(groupID: String) {
+ DatabaseComponent.get(context).groupDatabase().removeProfilePicture(groupID)
+ }
+
+ override fun hasDownloadedProfilePicture(groupID: String): Boolean {
+ return DatabaseComponent.get(context).groupDatabase().hasDownloadedProfilePicture(groupID)
+ }
+
override fun getReceivedMessageTimestamps(): Set {
return SessionMetaProtocol.getTimestamps()
}
@@ -397,6 +399,22 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
}
+ override fun markAsSyncing(timestamp: Long, author: String) {
+ DatabaseComponent.get(context).mmsSmsDatabase()
+ .getMessageFor(timestamp, author)
+ ?.run { getMmsDatabaseElseSms(isMms).markAsSyncing(id) }
+ }
+
+ private fun getMmsDatabaseElseSms(isMms: Boolean) =
+ if (isMms) DatabaseComponent.get(context).mmsDatabase()
+ else DatabaseComponent.get(context).smsDatabase()
+
+ override fun markAsResyncing(timestamp: Long, author: String) {
+ DatabaseComponent.get(context).mmsSmsDatabase()
+ .getMessageFor(timestamp, author)
+ ?.run { getMmsDatabaseElseSms(isMms).markAsResyncing(id) }
+ }
+
override fun markAsSending(timestamp: Long, author: String) {
val database = DatabaseComponent.get(context).mmsSmsDatabase()
val messageRecord = database.getMessageFor(timestamp, author) ?: return
@@ -422,7 +440,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
}
- override fun setErrorMessage(timestamp: Long, author: String, error: Exception) {
+ override fun markAsSentFailed(timestamp: Long, author: String, error: Exception) {
val database = DatabaseComponent.get(context).mmsSmsDatabase()
val messageRecord = database.getMessageFor(timestamp, author) ?: return
if (messageRecord.isMms) {
@@ -445,6 +463,26 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
}
+ override fun markAsSyncFailed(timestamp: Long, author: String, error: Exception) {
+ val database = DatabaseComponent.get(context).mmsSmsDatabase()
+ val messageRecord = database.getMessageFor(timestamp, author) ?: return
+
+ database.getMessageFor(timestamp, author)
+ ?.run { getMmsDatabaseElseSms(isMms).markAsSyncFailed(id) }
+
+ if (error.localizedMessage != null) {
+ val message: String
+ if (error is OnionRequestAPI.HTTPRequestFailedAtDestinationException && error.statusCode == 429) {
+ message = "429: Rate limited."
+ } else {
+ message = error.localizedMessage!!
+ }
+ DatabaseComponent.get(context).lokiMessageDatabase().setErrorMessage(messageRecord.getId(), message)
+ } else {
+ DatabaseComponent.get(context).lokiMessageDatabase().setErrorMessage(messageRecord.getId(), error.javaClass.simpleName)
+ }
+ }
+
override fun clearErrorMessage(messageID: Long) {
val db = DatabaseComponent.get(context).lokiMessageDatabase()
db.clearErrorMessage(messageID)
@@ -494,7 +532,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val expirationConfig = getExpirationConfiguration(threadId)
val expiresInMillis = (expirationConfig?.durationSeconds ?: 0) * 100L
val expireStartedAt = if (expirationConfig?.expirationType == ExpirationType.DELETE_AFTER_SEND) sentTimestamp else 0
- val m = IncomingTextMessage(fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), expiresInMillis, expireStartedAt, true)
+ val m = IncomingTextMessage(fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), expiresInMillis, expireStartedAt, true, false)
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
val infoMessage = IncomingGroupMessage(m, groupID, updateData, true)
val smsDB = DatabaseComponent.get(context).smsDatabase()
@@ -601,8 +639,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
return DatabaseComponent.get(context).groupDatabase().allGroups
}
- override fun addOpenGroup(urlAsString: String) {
- OpenGroupManager.addOpenGroup(urlAsString, context)
+ override fun addOpenGroup(urlAsString: String): OpenGroupApi.RoomInfo? {
+ return OpenGroupManager.addOpenGroup(urlAsString, context)
}
override fun onOpenGroupAdded(server: String) {
@@ -714,8 +752,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
recipientDatabase.setApproved(recipient, true)
threadDatabase.setHasSent(threadId, true)
}
- if (contact.isBlocked == true) {
- recipientDatabase.setBlocked(recipient, true)
+
+ val contactIsBlocked: Boolean? = contact.isBlocked
+ if (contactIsBlocked != null && recipient.isBlocked != contactIsBlocked) {
+ recipientDatabase.setBlocked(recipient, contactIsBlocked)
threadDatabase.deleteConversation(threadId)
}
}
@@ -744,6 +784,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
return mmsSmsDb.getConversationCount(threadID)
}
+ override fun deleteConversation(threadId: Long) {
+ val threadDB = DatabaseComponent.get(context).threadDatabase()
+ threadDB.deleteConversation(threadId)
+ }
+
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
@@ -773,6 +818,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
false,
false,
false,
+ false,
Optional.absent(),
Optional.absent(),
Optional.absent(),
@@ -805,6 +851,25 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val smsDb = DatabaseComponent.get(context).smsDatabase()
val sender = Recipient.from(context, fromSerialized(senderPublicKey), false)
val threadId = threadDB.getOrCreateThreadIdFor(sender)
+ val profile = response.profile
+ if (profile != null) {
+ val profileManager = SSKEnvironment.shared.profileManager
+ val name = profile.displayName!!
+ if (name.isNotEmpty()) {
+ profileManager.setName(context, sender, name)
+ }
+ val newProfileKey = profile.profileKey
+
+ val needsProfilePicture = !AvatarHelper.avatarFileExists(context, sender.address)
+ val profileKeyValid = newProfileKey?.isNotEmpty() == true && (newProfileKey.size == 16 || newProfileKey.size == 32) && profile.profilePictureURL?.isNotEmpty() == true
+ val profileKeyChanged = (sender.profileKey == null || !MessageDigest.isEqual(sender.profileKey, newProfileKey))
+
+ if ((profileKeyValid && profileKeyChanged) || (profileKeyValid && needsProfilePicture)) {
+ profileManager.setProfileKey(context, sender, newProfileKey!!)
+ profileManager.setUnidentifiedAccessMode(context, sender, Recipient.UnidentifiedAccessMode.UNKNOWN)
+ profileManager.setProfilePictureURL(context, sender, profile.profilePictureURL!!)
+ }
+ }
threadDB.setHasSent(threadId, true)
val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase()
val mappings = mutableMapOf()
@@ -855,6 +920,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
false,
false,
true,
+ false,
Optional.absent(),
Optional.absent(),
Optional.absent(),
@@ -1010,7 +1076,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
DatabaseComponent.get(context).reactionDatabase().deleteMessageReactions(MessageId(messageId, mms))
}
- override fun unblock(toUnblock: List) {
+ override fun unblock(toUnblock: Iterable) {
val recipientDb = DatabaseComponent.get(context).recipientDatabase()
recipientDb.setBlocked(toUnblock, false)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
index a0c701fc99..52d914af08 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
@@ -32,9 +32,10 @@ import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
-import net.sqlcipher.database.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
import org.jetbrains.annotations.NotNull;
+import org.session.libsession.snode.SnodeAPI;
import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.Contact;
import org.session.libsession.utilities.DelimiterUtil;
@@ -57,7 +58,6 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
-import org.thoughtcrime.securesms.groups.OpenGroupMigrator;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
@@ -87,6 +87,7 @@ public class ThreadDatabase extends Database {
private static final String SNIPPET_CHARSET = "snippet_cs";
public static final String READ = "read";
public static final String UNREAD_COUNT = "unread_count";
+ public static final String UNREAD_MENTION_COUNT = "unread_mention_count";
public static final String TYPE = "type";
private static final String ERROR = "error";
public static final String SNIPPET_TYPE = "snippet_type";
@@ -117,7 +118,7 @@ public class ThreadDatabase extends Database {
};
private static final String[] THREAD_PROJECTION = {
- ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, UNREAD_COUNT, TYPE, ERROR, SNIPPET_TYPE,
+ ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, UNREAD_COUNT, UNREAD_MENTION_COUNT, TYPE, ERROR, SNIPPET_TYPE,
SNIPPET_URI, ARCHIVED, STATUS, DELIVERY_RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN, READ_RECEIPT_COUNT, IS_PINNED
};
@@ -135,13 +136,18 @@ public class ThreadDatabase extends Database {
"ADD COLUMN " + IS_PINNED + " INTEGER DEFAULT 0;";
}
+ public static String getUnreadMentionCountCommand() {
+ return "ALTER TABLE "+ TABLE_NAME + " " +
+ "ADD COLUMN " + UNREAD_MENTION_COUNT + " INTEGER DEFAULT 0;";
+ }
+
public ThreadDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
}
private long createThreadForRecipient(Address address, boolean group, int distributionType) {
ContentValues contentValues = new ContentValues(4);
- long date = System.currentTimeMillis();
+ long date = SnodeAPI.getNowWithOffset();
contentValues.put(DATE, date - date % 1000);
contentValues.put(ADDRESS, address.serialize());
@@ -293,9 +299,10 @@ public class ThreadDatabase extends Database {
ContentValues contentValues = new ContentValues(1);
contentValues.put(READ, 1);
contentValues.put(UNREAD_COUNT, 0);
+ contentValues.put(UNREAD_MENTION_COUNT, 0);
if (lastSeen) {
- contentValues.put(LAST_SEEN, System.currentTimeMillis());
+ contentValues.put(LAST_SEEN, SnodeAPI.getNowWithOffset());
}
SQLiteDatabase db = databaseHelper.getWritableDatabase();
@@ -312,20 +319,28 @@ public class ThreadDatabase extends Database {
}};
}
- public void incrementUnread(long threadId, int amount) {
+ public void incrementUnread(long threadId, int amount, int unreadMentionAmount) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.execSQL("UPDATE " + TABLE_NAME + " SET " + READ + " = 0, " +
- UNREAD_COUNT + " = " + UNREAD_COUNT + " + ? WHERE " + ID + " = ?",
- new String[] {String.valueOf(amount),
- String.valueOf(threadId)});
+ UNREAD_COUNT + " = " + UNREAD_COUNT + " + ?, " +
+ UNREAD_MENTION_COUNT + " = " + UNREAD_MENTION_COUNT + " + ? WHERE " + ID + " = ?",
+ new String[] {
+ String.valueOf(amount),
+ String.valueOf(unreadMentionAmount),
+ String.valueOf(threadId)
+ });
}
- public void decrementUnread(long threadId, int amount) {
+ public void decrementUnread(long threadId, int amount, int unreadMentionAmount) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.execSQL("UPDATE " + TABLE_NAME + " SET " + READ + " = 0, " +
- UNREAD_COUNT + " = " + UNREAD_COUNT + " - ? WHERE " + ID + " = ? AND " + UNREAD_COUNT + " > 0",
- new String[] {String.valueOf(amount),
- String.valueOf(threadId)});
+ UNREAD_COUNT + " = " + UNREAD_COUNT + " - ?, " +
+ UNREAD_MENTION_COUNT + " = " + UNREAD_MENTION_COUNT + " - ? WHERE " + ID + " = ? AND " + UNREAD_COUNT + " > 0",
+ new String[] {
+ String.valueOf(amount),
+ String.valueOf(unreadMentionAmount),
+ String.valueOf(threadId)
+ });
}
public void setDistributionType(long threadId, int distributionType) {
@@ -506,7 +521,7 @@ public class ThreadDatabase extends Database {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues(1);
if (timestamp == -1) {
- contentValues.put(LAST_SEEN, System.currentTimeMillis());
+ contentValues.put(LAST_SEEN, SnodeAPI.getNowWithOffset());
} else {
contentValues.put(LAST_SEEN, timestamp);
}
@@ -785,77 +800,6 @@ public class ThreadDatabase extends Database {
return query;
}
- @NotNull
- public List getHttpOxenOpenGroups() {
- String where = TABLE_NAME+"."+ADDRESS+" LIKE ?";
- String selection = OpenGroupMigrator.HTTP_PREFIX+OpenGroupMigrator.OPEN_GET_SESSION_TRAILING_DOT_ENCODED +"%";
- SQLiteDatabase db = databaseHelper.getReadableDatabase();
- String query = createQuery(where, 0);
- Cursor cursor = db.rawQuery(query, new String[]{selection});
-
- if (cursor == null) {
- return Collections.emptyList();
- }
- List threads = new ArrayList<>();
- try {
- Reader reader = readerFor(cursor);
- ThreadRecord record;
- while ((record = reader.getNext()) != null) {
- threads.add(record);
- }
- } finally {
- cursor.close();
- }
- return threads;
- }
-
- @NotNull
- public List getLegacyOxenOpenGroups() {
- String where = TABLE_NAME+"."+ADDRESS+" LIKE ?";
- String selection = OpenGroupMigrator.LEGACY_GROUP_ENCODED_ID+"%";
- SQLiteDatabase db = databaseHelper.getReadableDatabase();
- String query = createQuery(where, 0);
- Cursor cursor = db.rawQuery(query, new String[]{selection});
-
- if (cursor == null) {
- return Collections.emptyList();
- }
- List threads = new ArrayList<>();
- try {
- Reader reader = readerFor(cursor);
- ThreadRecord record;
- while ((record = reader.getNext()) != null) {
- threads.add(record);
- }
- } finally {
- cursor.close();
- }
- return threads;
- }
-
- @NotNull
- public List getHttpsOxenOpenGroups() {
- String where = TABLE_NAME+"."+ADDRESS+" LIKE ?";
- String selection = OpenGroupMigrator.NEW_GROUP_ENCODED_ID+"%";
- SQLiteDatabase db = databaseHelper.getReadableDatabase();
- String query = createQuery(where, 0);
- Cursor cursor = db.rawQuery(query, new String[]{selection});
- if (cursor == null) {
- return Collections.emptyList();
- }
- List threads = new ArrayList<>();
- try {
- Reader reader = readerFor(cursor);
- ThreadRecord record;
- while ((record = reader.getNext()) != null) {
- threads.add(record);
- }
- } finally {
- cursor.close();
- }
- return threads;
- }
-
public void migrateEncodedGroup(long threadId, @NotNull String newEncodedGroupId) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(ADDRESS, newEncodedGroupId);
@@ -911,6 +855,7 @@ public class ThreadDatabase extends Database {
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));
int unreadCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.UNREAD_COUNT));
+ int unreadMentionCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.UNREAD_MENTION_COUNT));
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
boolean archived = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.ARCHIVED)) != 0;
int status = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS));
@@ -926,7 +871,7 @@ public class ThreadDatabase extends Database {
}
return new ThreadRecord(body, snippetUri, recipient, date, count,
- unreadCount, threadId, deliveryReceiptCount, status, type,
+ unreadCount, unreadMentionCount, threadId, deliveryReceiptCount, status, type,
distributionType, archived, expiresIn, lastSeen, readReceiptCount, pinned);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
index fff5459288..70e551b5ea 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
@@ -1,14 +1,18 @@
package org.thoughtcrime.securesms.database.helpers;
-
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.Context;
import android.database.Cursor;
import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
-import net.sqlcipher.database.SQLiteDatabase;
-import net.sqlcipher.database.SQLiteDatabaseHook;
-import net.sqlcipher.database.SQLiteOpenHelper;
+import net.zetetic.database.sqlcipher.SQLiteConnection;
+import net.zetetic.database.sqlcipher.SQLiteDatabase;
+import net.zetetic.database.sqlcipher.SQLiteDatabaseHook;
+import net.zetetic.database.sqlcipher.SQLiteException;
+import net.zetetic.database.sqlcipher.SQLiteOpenHelper;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsignal.utilities.Log;
@@ -21,7 +25,6 @@ import org.thoughtcrime.securesms.database.ExpirationConfigurationDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupMemberDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
-import org.thoughtcrime.securesms.database.JobDatabase;
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.database.LokiBackupFilesDatabase;
import org.thoughtcrime.securesms.database.LokiMessageDatabase;
@@ -36,6 +39,11 @@ import org.thoughtcrime.securesms.database.SessionContactDatabase;
import org.thoughtcrime.securesms.database.SessionJobDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
+import org.thoughtcrime.securesms.notifications.NotificationChannels;
+
+import java.io.File;
+
+import network.loki.messenger.R;
public class SQLCipherOpenHelper extends SQLiteOpenHelper {
@@ -77,40 +85,191 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int lokiV37 = 58;
private static final int lokiV38 = 59;
private static final int lokiV39 = 60;
+ private static final int lokiV40 = 61;
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
- private static final int DATABASE_VERSION = lokiV39;
- private static final String DATABASE_NAME = "signal.db";
+ private static final int DATABASE_VERSION = lokiV40;
+ private static final int MIN_DATABASE_VERSION = lokiV7;
+ private static final String CIPHER3_DATABASE_NAME = "signal.db";
+ public static final String DATABASE_NAME = "signal_v4.db";
private final Context context;
private final DatabaseSecret databaseSecret;
public SQLCipherOpenHelper(@NonNull Context context, @NonNull DatabaseSecret databaseSecret) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION, new SQLiteDatabaseHook() {
- @Override
- public void preKey(SQLiteDatabase db) {
- db.rawExecSQL("PRAGMA cipher_default_kdf_iter = 1;");
- db.rawExecSQL("PRAGMA cipher_default_page_size = 4096;");
- }
-
- @Override
- public void postKey(SQLiteDatabase db) {
- db.rawExecSQL("PRAGMA kdf_iter = '1';");
- db.rawExecSQL("PRAGMA cipher_page_size = 4096;");
- // if not vacuumed in a while, perform that operation
- long currentTime = System.currentTimeMillis();
- // 7 days
- if (currentTime - TextSecurePreferences.getLastVacuumTime(context) > 604_800_000) {
- db.rawExecSQL("VACUUM;");
- TextSecurePreferences.setLastVacuumNow(context);
+ super(
+ context,
+ DATABASE_NAME,
+ databaseSecret.asString(),
+ null,
+ DATABASE_VERSION,
+ MIN_DATABASE_VERSION,
+ null,
+ new SQLiteDatabaseHook() {
+ @Override
+ public void preKey(SQLiteConnection connection) {
+ SQLCipherOpenHelper.applySQLCipherPragmas(connection, true);
}
- }
- });
+
+ @Override
+ public void postKey(SQLiteConnection connection) {
+ SQLCipherOpenHelper.applySQLCipherPragmas(connection, true);
+
+ // if not vacuumed in a while, perform that operation
+ long currentTime = System.currentTimeMillis();
+ // 7 days
+ if (currentTime - TextSecurePreferences.getLastVacuumTime(context) > 604_800_000) {
+ connection.execute("VACUUM;", null, null);
+ TextSecurePreferences.setLastVacuumNow(context);
+ }
+ }
+ },
+ // Note: Now that we support concurrent database reads the migrations are actually non-blocking
+ // because of this we need to initially open the database with writeAheadLogging (WAL mode) disabled
+ // and enable it once the database officially opens it's connection (which will cause it to re-connect
+ // in WAL mode) - this is a little inefficient but will prevent SQL-related errors/crashes due to
+ // incomplete migrations
+ false
+ );
this.context = context.getApplicationContext();
this.databaseSecret = databaseSecret;
}
+ private static void applySQLCipherPragmas(SQLiteConnection connection, boolean useSQLCipher4) {
+ if (useSQLCipher4) {
+ connection.execute("PRAGMA kdf_iter = '256000';", null, null);
+ }
+ else {
+ connection.execute("PRAGMA cipher_compatibility = 3;", null, null);
+ connection.execute("PRAGMA kdf_iter = '1';", null, null);
+ }
+
+ connection.execute("PRAGMA cipher_page_size = 4096;", null, null);
+ }
+
+ private static SQLiteDatabase open(String path, DatabaseSecret databaseSecret, boolean useSQLCipher4) throws SQLiteException {
+ return SQLiteDatabase.openDatabase(path, databaseSecret.asString(), null, SQLiteDatabase.OPEN_READWRITE, new SQLiteDatabaseHook() {
+ @Override
+ public void preKey(SQLiteConnection connection) { SQLCipherOpenHelper.applySQLCipherPragmas(connection, useSQLCipher4); }
+
+ @Override
+ public void postKey(SQLiteConnection connection) { SQLCipherOpenHelper.applySQLCipherPragmas(connection, useSQLCipher4); }
+ });
+ }
+
+ public static void migrateSqlCipher3To4IfNeeded(@NonNull Context context, @NonNull DatabaseSecret databaseSecret) throws Exception {
+ String oldDbPath = context.getDatabasePath(CIPHER3_DATABASE_NAME).getPath();
+ File oldDbFile = new File(oldDbPath);
+
+ // If the old SQLCipher3 database file doesn't exist then no need to do anything
+ if (!oldDbFile.exists()) { return; }
+
+ // Define the location for the new database
+ String newDbPath = context.getDatabasePath(DATABASE_NAME).getPath();
+ File newDbFile = new File(newDbPath);
+
+ try {
+ // If the new database file already exists then check if it's valid first, if it's in an
+ // invalid state we should delete it and try to migrate again
+ if (newDbFile.exists()) {
+ // If the old database hasn't been modified since the new database was created, then we can
+ // assume the user hasn't downgraded for some reason and made changes to the old database and
+ // can remove the old database file (it won't be used anymore)
+ if (oldDbFile.lastModified() <= newDbFile.lastModified()) {
+ try {
+ SQLiteDatabase newDb = SQLCipherOpenHelper.open(newDbPath, databaseSecret, true);
+ int version = newDb.getVersion();
+ newDb.close();
+
+ // Make sure the new database has it's version set correctly (if not then the migration didn't
+ // fully succeed and the database will try to create all it's tables and immediately fail so
+ // we will need to remove and remigrate)
+ if (version > 0) {
+ // TODO: Delete 'CIPHER3_DATABASE_NAME' once enough time has past
+// //noinspection ResultOfMethodCallIgnored
+// oldDbFile.delete();
+ return;
+ }
+ }
+ catch (Exception e) {
+ Log.i(TAG, "Failed to retrieve version from new database, assuming invalid and remigrating");
+ }
+ }
+
+ // If the old database does have newer changes then the new database could have stale/invalid
+ // data and we should re-migrate to avoid losing any data or issues
+ if (!newDbFile.delete()) {
+ throw new Exception("Failed to remove invalid new database");
+ }
+ }
+
+ if (!newDbFile.createNewFile()) {
+ throw new Exception("Failed to create new database");
+ }
+
+ // Open the old database and extract it's version
+ SQLiteDatabase oldDb = SQLCipherOpenHelper.open(oldDbPath, databaseSecret, false);
+ int oldDbVersion = oldDb.getVersion();
+
+ // Export the old database to the new one (will have the default 'kdf_iter' and 'page_size' settings)
+ oldDb.rawExecSQL(
+ String.format("ATTACH DATABASE '%s' AS sqlcipher4 KEY '%s'", newDbPath, databaseSecret.asString())
+ );
+ Cursor cursor = oldDb.rawQuery("SELECT sqlcipher_export('sqlcipher4')");
+ cursor.moveToLast();
+ cursor.close();
+ oldDb.rawExecSQL("DETACH DATABASE sqlcipher4");
+ oldDb.close();
+
+ // Open the newly migrated database (to ensure it works) and set it's version so we don't try
+ // to run any of our custom migrations
+ SQLiteDatabase newDb = SQLCipherOpenHelper.open(newDbPath, databaseSecret, true);
+ newDb.setVersion(oldDbVersion);
+ newDb.close();
+
+ // TODO: Delete 'CIPHER3_DATABASE_NAME' once enough time has past
+ // Remove the old database file since it will no longer be used
+// //noinspection ResultOfMethodCallIgnored
+// oldDbFile.delete();
+ }
+ catch (Exception e) {
+ Log.e(TAG, "Migration from SQLCipher3 to SQLCipher4 failed", e);
+
+ // If an exception was thrown then we should remove the new database file (it's probably invalid)
+ if (!newDbFile.delete()) {
+ Log.e(TAG, "Unable to delete invalid new database file");
+ }
+
+ // Notify the user of the issue so they know they can downgrade until the issue is fixed
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ String channelId = context.getString(R.string.NotificationChannel_failures);
+
+ if (NotificationChannels.supported()) {
+ NotificationChannel channel = new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_HIGH);
+ channel.enableVibration(true);
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
+ .setSmallIcon(R.drawable.ic_notification)
+ .setColor(context.getResources().getColor(R.color.textsecure_primary))
+ .setCategory(NotificationCompat.CATEGORY_ERROR)
+ .setContentTitle(context.getString(R.string.ErrorNotifier_migration))
+ .setContentText(context.getString(R.string.ErrorNotifier_migration_downgrade))
+ .setAutoCancel(true);
+
+ if (!NotificationChannels.supported()) {
+ builder.setPriority(NotificationCompat.PRIORITY_HIGH);
+ }
+
+ notificationManager.notify(5874, builder.build());
+
+ // Throw the error (app will crash but there is nothing else we can do unfortunately)
+ throw e;
+ }
+ }
+
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SmsDatabase.CREATE_TABLE);
@@ -125,9 +284,6 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
for (String sql : SearchDatabase.CREATE_TABLE) {
db.execSQL(sql);
}
- for (String sql : JobDatabase.CREATE_TABLE) {
- db.execSQL(sql);
- }
db.execSQL(LokiAPIDatabase.getCreateSnodePoolTableCommand());
db.execSQL(LokiAPIDatabase.getCreateOnionRequestPathTableCommand());
db.execSQL(LokiAPIDatabase.getCreateSwarmTableCommand());
@@ -183,6 +339,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(LokiAPIDatabase.RESET_SEQ_NO); // probably not needed but consistent with all migrations
db.execSQL(EmojiSearchDatabase.CREATE_EMOJI_SEARCH_TABLE_COMMAND);
db.execSQL(ReactionDatabase.CREATE_REACTION_TABLE_COMMAND);
+ db.execSQL(ThreadDatabase.getUnreadMentionCountCommand());
+ db.execSQL(SmsDatabase.CREATE_HAS_MENTION_COMMAND);
+ db.execSQL(MmsDatabase.CREATE_HAS_MENTION_COMMAND);
db.execSQL(ExpirationConfigurationDatabase.CREATE_EXPIRATION_CONFIGURATION_TABLE_COMMAND);
executeStatements(db, SmsDatabase.CREATE_INDEXS);
@@ -192,6 +351,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
executeStatements(db, DraftDatabase.CREATE_INDEXS);
executeStatements(db, GroupDatabase.CREATE_INDEXS);
executeStatements(db, GroupReceiptDatabase.CREATE_INDEXES);
+ executeStatements(db, ReactionDatabase.CREATE_INDEXS);
executeStatements(db, ReactionDatabase.CREATE_REACTION_TRIGGERS);
}
@@ -199,9 +359,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
@Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
- // Loki - Enable write ahead logging mode and increase the cache size.
- // This should be disabled if we ever run into serious race condition bugs.
- db.enableWriteAheadLogging();
+
db.execSQL("PRAGMA cache_size = 10000");
}
@@ -419,6 +577,16 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
}
if (oldVersion < lokiV39) {
+ executeStatements(db, ReactionDatabase.CREATE_INDEXS);
+ }
+
+ if (oldVersion < lokiV40) {
+ db.execSQL(ThreadDatabase.getUnreadMentionCountCommand());
+ db.execSQL(SmsDatabase.CREATE_HAS_MENTION_COMMAND);
+ db.execSQL(MmsDatabase.CREATE_HAS_MENTION_COMMAND);
+ }
+
+ if (oldVersion < lokiV41) {
db.execSQL(RecipientDatabase.getCreateDisappearingStateCommand());
db.execSQL(ExpirationConfigurationDatabase.CREATE_EXPIRATION_CONFIGURATION_TABLE_COMMAND);
db.execSQL(ExpirationConfigurationDatabase.MIGRATE_GROUP_CONVERSATION_EXPIRY_TYPE_COMMAND);
@@ -431,12 +599,13 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
}
}
- public SQLiteDatabase getReadableDatabase() {
- return getReadableDatabase(databaseSecret.asString());
- }
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ super.onOpen(db);
- public SQLiteDatabase getWritableDatabase() {
- return getWritableDatabase(databaseSecret.asString());
+ // Now that the database is officially open (ie. the migrations are completed) we want to enable
+ // write ahead logging (WAL mode) to officially support concurrent read connections
+ db.enableWriteAheadLogging();
}
public void markCurrent(SQLiteDatabase db) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java
index ef0f4b54f3..39fba182aa 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java
@@ -80,6 +80,18 @@ public abstract class DisplayRecord {
return !isFailed() && !isPending();
}
+ public boolean isSyncing() {
+ return MmsSmsColumns.Types.isSyncingType(type);
+ }
+
+ public boolean isResyncing() {
+ return MmsSmsColumns.Types.isResyncingType(type);
+ }
+
+ public boolean isSyncFailed() {
+ return MmsSmsColumns.Types.isSyncFailedMessageType(type);
+ }
+
public boolean isFailed() {
return MmsSmsColumns.Types.isFailedMessageType(type)
|| MmsSmsColumns.Types.isPendingSecureSmsFallbackType(type)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java
index 570cb48bce..1b566169d7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java
@@ -57,12 +57,12 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
long expiresIn, long expireStarted, int readReceiptCount,
@Nullable Quote quote, @NonNull List contacts,
@NonNull List linkPreviews,
- @NonNull List reactions, boolean unidentified)
+ @NonNull List reactions, boolean unidentified, boolean hasMention)
{
super(id, body, conversationRecipient, individualRecipient, dateSent,
dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
expiresIn, expireStarted, slideDeck, readReceiptCount, quote, contacts,
- linkPreviews, unidentified, reactions);
+ linkPreviews, unidentified, reactions, hasMention);
this.partCount = partCount;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java
index 1d78314dea..ba01ffd9c5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java
@@ -51,7 +51,8 @@ public abstract class MessageRecord extends DisplayRecord {
private final long expireStarted;
private final boolean unidentified;
public final long id;
- private final List reactions;
+ private final List reactions;
+ private final boolean hasMention;
public abstract boolean isMms();
public abstract boolean isMmsNotification();
@@ -63,7 +64,7 @@ public abstract class MessageRecord extends DisplayRecord {
List mismatches,
List networkFailures,
long expiresIn, long expireStarted,
- int readReceiptCount, boolean unidentified, List reactions)
+ int readReceiptCount, boolean unidentified, List reactions, boolean hasMention)
{
super(body, conversationRecipient, dateSent, dateReceived,
threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount);
@@ -75,6 +76,7 @@ public abstract class MessageRecord extends DisplayRecord {
this.expireStarted = expireStarted;
this.unidentified = unidentified;
this.reactions = reactions;
+ this.hasMention = hasMention;
}
public long getId() {
@@ -97,6 +99,8 @@ public abstract class MessageRecord extends DisplayRecord {
}
public long getExpireStarted() { return expireStarted; }
+ public boolean getHasMention() { return hasMention; }
+
public boolean isMediaPending() {
return false;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java
index b186e668eb..9f34f3fa0e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java
@@ -27,9 +27,9 @@ public abstract class MmsMessageRecord extends MessageRecord {
List networkFailures, long expiresIn,
long expireStarted, @NonNull SlideDeck slideDeck, int readReceiptCount,
@Nullable Quote quote, @NonNull List contacts,
- @NonNull List linkPreviews, boolean unidentified, List reactions)
+ @NonNull List linkPreviews, boolean unidentified, List reactions, boolean hasMention)
{
- super(id, body, conversationRecipient, individualRecipient, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
+ super(id, body, conversationRecipient, individualRecipient, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, expiresIn, expireStarted, readReceiptCount, unidentified, reactions, hasMention);
this.slideDeck = slideDeck;
this.quote = quote;
this.contacts.addAll(contacts);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java
index c1c87800d2..9fb4047879 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java
@@ -50,12 +50,12 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
long dateSent, long dateReceived, int deliveryReceiptCount,
long threadId, byte[] contentLocation, long messageSize,
long expiry, int status, byte[] transactionId, long mailbox,
- SlideDeck slideDeck, int readReceiptCount)
+ SlideDeck slideDeck, int readReceiptCount, boolean hasMention)
{
super(id, "", conversationRecipient, individualRecipient,
dateSent, dateReceived, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
emptyList(), emptyList(),
- 0, 0, slideDeck, readReceiptCount, null, emptyList(), emptyList(), false, emptyList());
+ 0, 0, slideDeck, readReceiptCount, null, emptyList(), emptyList(), false, emptyList(), hasMention);
this.contentLocation = contentLocation;
this.messageSize = messageSize;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
index c1d50def2f..83ee921a2a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
@@ -43,12 +43,12 @@ public class SmsMessageRecord extends MessageRecord {
long type, long threadId,
int status, List mismatches,
long expiresIn, long expireStarted,
- int readReceiptCount, boolean unidentified, List reactions)
+ int readReceiptCount, boolean unidentified, List reactions, boolean hasMention)
{
super(id, body, recipient, individualRecipient,
dateSent, dateReceived, threadId, status, deliveryReceiptCount, type,
mismatches, new LinkedList<>(),
- expiresIn, expireStarted, readReceiptCount, unidentified, reactions);
+ expiresIn, expireStarted, readReceiptCount, unidentified, reactions, hasMention);
}
public long getType() {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java
index 6ce69a591a..f3e72a8747 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java
@@ -45,39 +45,37 @@ public class ThreadRecord extends DisplayRecord {
private @Nullable final Uri snippetUri;
private final long count;
private final int unreadCount;
+ private final int unreadMentionCount;
private final int distributionType;
private final boolean archived;
private final long expiresIn;
private final long lastSeen;
private final boolean pinned;
- private final int recipientHash;
+ private final int initialRecipientHash;
public ThreadRecord(@NonNull String body, @Nullable Uri snippetUri,
@NonNull Recipient recipient, long date, long count, int unreadCount,
- long threadId, int deliveryReceiptCount, int status, long snippetType,
- int distributionType, boolean archived, long expiresIn, long lastSeen,
- int readReceiptCount, boolean pinned)
+ int unreadMentionCount, long threadId, int deliveryReceiptCount, int status,
+ long snippetType, int distributionType, boolean archived, long expiresIn,
+ long lastSeen, int readReceiptCount, boolean pinned)
{
super(body, recipient, date, date, threadId, status, deliveryReceiptCount, snippetType, readReceiptCount);
- this.snippetUri = snippetUri;
- this.count = count;
- this.unreadCount = unreadCount;
- this.distributionType = distributionType;
- this.archived = archived;
- this.expiresIn = expiresIn;
- this.lastSeen = lastSeen;
- this.pinned = pinned;
- this.recipientHash = recipient.hashCode();
+ this.snippetUri = snippetUri;
+ this.count = count;
+ this.unreadCount = unreadCount;
+ this.unreadMentionCount = unreadMentionCount;
+ this.distributionType = distributionType;
+ this.archived = archived;
+ this.expiresIn = expiresIn;
+ this.lastSeen = lastSeen;
+ this.pinned = pinned;
+ this.initialRecipientHash = recipient.hashCode();
}
public @Nullable Uri getSnippetUri() {
return snippetUri;
}
- public int getRecipientHash() {
- return recipientHash;
- }
-
@Override
public SpannableString getDisplayBody(@NonNull Context context) {
if (isGroupUpdateMessage()) {
@@ -153,6 +151,10 @@ public class ThreadRecord extends DisplayRecord {
return unreadCount;
}
+ public int getUnreadMentionCount() {
+ return unreadMentionCount;
+ }
+
public long getDate() {
return getDateReceived();
}
@@ -176,4 +178,8 @@ public class ThreadRecord extends DisplayRecord {
public boolean isPinned() {
return pinned;
}
+
+ public int getInitialRecipientHash() {
+ return initialRecipientHash;
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt
index 49b414366f..a4b98b6852 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseComponent.kt
@@ -32,7 +32,6 @@ interface DatabaseComponent {
fun recipientDatabase(): RecipientDatabase
fun groupReceiptDatabase(): GroupReceiptDatabase
fun searchDatabase(): SearchDatabase
- fun jobDatabase(): JobDatabase
fun lokiAPIDatabase(): LokiAPIDatabase
fun lokiMessageDatabase(): LokiMessageDatabase
fun lokiThreadDatabase(): LokiThreadDatabase
diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt
index d34cc3f25b..3a6357fa52 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/DatabaseModule.kt
@@ -6,7 +6,7 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
-import net.sqlcipher.database.SQLiteDatabase
+import net.zetetic.database.sqlcipher.SQLiteDatabase
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.utilities.SSKEnvironment
import org.thoughtcrime.securesms.attachments.DatabaseAttachmentProvider
@@ -24,7 +24,7 @@ object DatabaseModule {
@JvmStatic
fun init(context: Context) {
- SQLiteDatabase.loadLibs(context)
+ System.loadLibrary("sqlcipher")
}
@Provides
@@ -39,6 +39,7 @@ object DatabaseModule {
@Singleton
fun provideOpenHelper(@ApplicationContext context: Context): SQLCipherOpenHelper {
val dbSecret = DatabaseSecretProvider(context).orCreateDatabaseSecret
+ SQLCipherOpenHelper.migrateSqlCipher3To4IfNeeded(context, dbSecret)
return SQLCipherOpenHelper(context, dbSecret)
}
@@ -91,10 +92,6 @@ object DatabaseModule {
@Singleton
fun searchDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = SearchDatabase(context,openHelper)
- @Provides
- @Singleton
- fun provideJobDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = JobDatabase(context, openHelper)
-
@Provides
@Singleton
fun provideLokiApiDatabase(@ApplicationContext context: Context, openHelper: SQLCipherOpenHelper) = LokiAPIDatabase(context,openHelper)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt
index d39ba709df..dbdf2615ae 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt
@@ -15,7 +15,7 @@ import java.util.concurrent.Executors
object OpenGroupManager {
private val executorService = Executors.newScheduledThreadPool(4)
- private var pollers = mutableMapOf() // One for each server
+ private val pollers = mutableMapOf() // One for each server
private var isPolling = false
private val pollUpdaterLock = Any()
@@ -41,11 +41,11 @@ object OpenGroupManager {
isPolling = true
val storage = MessagingModuleConfiguration.shared.storage
val servers = storage.getAllOpenGroups().values.map { it.server }.toSet()
- servers.forEach { server ->
- pollers[server]?.stop() // Shouldn't be necessary
- val poller = OpenGroupPoller(server, executorService)
- poller.startIfNeeded()
- pollers[server] = poller
+ synchronized(pollUpdaterLock) {
+ servers.forEach { server ->
+ pollers[server]?.stop() // Shouldn't be necessary
+ pollers[server] = OpenGroupPoller(server, executorService).apply { startIfNeeded() }
+ }
}
}
@@ -58,14 +58,14 @@ object OpenGroupManager {
}
@WorkerThread
- fun add(server: String, room: String, publicKey: String, context: Context) {
+ fun add(server: String, room: String, publicKey: String, context: Context): OpenGroupApi.RoomInfo? {
val openGroupID = "$server.$room"
- var threadID = GroupManager.getOpenGroupThreadID(openGroupID, context)
+ val threadID = GroupManager.getOpenGroupThreadID(openGroupID, context)
val storage = MessagingModuleConfiguration.shared.storage
val threadDB = DatabaseComponent.get(context).lokiThreadDatabase()
// Check it it's added already
val existingOpenGroup = threadDB.getOpenGroupChat(threadID)
- if (existingOpenGroup != null) { return }
+ if (existingOpenGroup != null) { return null }
// Clear any existing data if needed
storage.removeLastDeletionServerID(room, server)
storage.removeLastMessageServerID(room, server)
@@ -73,18 +73,20 @@ object OpenGroupManager {
storage.removeLastOutboxMessageId(server)
// Store the public key
storage.setOpenGroupPublicKey(server, publicKey)
- // Get capabilities
- val capabilities = OpenGroupApi.getCapabilities(server).get()
+ // Get capabilities & room info
+ val (capabilities, info) = OpenGroupApi.getCapabilitiesAndRoomInfo(room, server).get()
storage.setServerCapabilities(server, capabilities.capabilities)
- // Get room info
- val info = OpenGroupApi.getRoomInfo(room, server).get()
- storage.setUserCount(room, server, info.activeUsers)
// Create the group locally if not available already
if (threadID < 0) {
- threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId
+ GroupManager.createOpenGroup(openGroupID, context, null, info.name)
}
- val openGroup = OpenGroup(server, room, info.name, info.infoUpdates, publicKey)
- threadDB.setOpenGroupChat(openGroup, threadID)
+ OpenGroupPoller.handleRoomPollInfo(
+ server = server,
+ roomToken = room,
+ pollInfo = info.toPollInfo(),
+ createGroupIfMissingWithPublicKey = publicKey
+ )
+ return info
}
fun restartPollerForServer(server: String) {
@@ -130,12 +132,13 @@ object OpenGroupManager {
}
}
- fun addOpenGroup(urlAsString: String, context: Context) {
- val url = HttpUrl.parse(urlAsString) ?: return
+ fun addOpenGroup(urlAsString: String, context: Context): OpenGroupApi.RoomInfo? {
+ val url = HttpUrl.parse(urlAsString) ?: return null
val server = OpenGroup.getServer(urlAsString)
- val room = url.pathSegments().firstOrNull() ?: return
- val publicKey = url.queryParameter("public_key") ?: return
- add(server.toString().removeSuffix("/"), room, publicKey, context) // assume migrated from calling function
+ val room = url.pathSegments().firstOrNull() ?: return null
+ val publicKey = url.queryParameter("public_key") ?: return null
+
+ return add(server.toString().removeSuffix("/"), room, publicKey, context) // assume migrated from calling function
}
fun updateOpenGroup(openGroup: OpenGroup, context: Context) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupMigrator.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupMigrator.kt
deleted file mode 100644
index 642d191614..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupMigrator.kt
+++ /dev/null
@@ -1,139 +0,0 @@
-package org.thoughtcrime.securesms.groups
-
-import androidx.annotation.VisibleForTesting
-import org.session.libsession.messaging.open_groups.OpenGroupApi
-import org.session.libsession.utilities.recipients.Recipient
-import org.session.libsignal.utilities.Hex
-import org.thoughtcrime.securesms.database.model.ThreadRecord
-import org.thoughtcrime.securesms.dependencies.DatabaseComponent
-
-object OpenGroupMigrator {
- const val HTTP_PREFIX = "__loki_public_chat_group__!687474703a2f2f"
- private const val HTTPS_PREFIX = "__loki_public_chat_group__!68747470733a2f2f"
- const val OPEN_GET_SESSION_TRAILING_DOT_ENCODED = "6f70656e2e67657473657373696f6e2e6f72672e"
- const val LEGACY_GROUP_ENCODED_ID = "__loki_public_chat_group__!687474703a2f2f3131362e3230332e37302e33332e" // old IP based toByteArray()
- const val NEW_GROUP_ENCODED_ID = "__loki_public_chat_group__!68747470733a2f2f6f70656e2e67657473657373696f6e2e6f72672e" // new URL based toByteArray()
-
- data class OpenGroupMapping(val stub: String, val legacyThreadId: Long, val newThreadId: Long?)
-
- @VisibleForTesting
- fun Recipient.roomStub(): String? {
- if (!isOpenGroupRecipient) return null
- val serialized = address.serialize()
- if (serialized.startsWith(LEGACY_GROUP_ENCODED_ID)) {
- return serialized.replace(LEGACY_GROUP_ENCODED_ID,"")
- } else if (serialized.startsWith(NEW_GROUP_ENCODED_ID)) {
- return serialized.replace(NEW_GROUP_ENCODED_ID,"")
- } else if (serialized.startsWith(HTTP_PREFIX + OPEN_GET_SESSION_TRAILING_DOT_ENCODED)) {
- return serialized.replace(HTTP_PREFIX + OPEN_GET_SESSION_TRAILING_DOT_ENCODED, "")
- }
- return null
- }
-
- @VisibleForTesting
- fun getExistingMappings(legacy: List, new: List): List {
- val legacyStubsMapping = legacy.mapNotNull { thread ->
- val stub = thread.recipient.roomStub()
- stub?.let { it to thread.threadId }
- }
- val newStubsMapping = new.mapNotNull { thread ->
- val stub = thread.recipient.roomStub()
- stub?.let { it to thread.threadId }
- }
- return legacyStubsMapping.map { (legacyEncodedStub, legacyId) ->
- // get 'new' open group thread ID if stubs match
- OpenGroupMapping(
- legacyEncodedStub,
- legacyId,
- newStubsMapping.firstOrNull { (newEncodedStub, _) -> newEncodedStub == legacyEncodedStub }?.second
- )
- }
- }
-
- @JvmStatic
- fun migrate(databaseComponent: DatabaseComponent) {
- // migrate thread db
- val threadDb = databaseComponent.threadDatabase()
-
- val legacyOpenGroups = threadDb.legacyOxenOpenGroups
- val httpBasedNewGroups = threadDb.httpOxenOpenGroups
- if (legacyOpenGroups.isEmpty() && httpBasedNewGroups.isEmpty()) return // no need to migrate
-
- val newOpenGroups = threadDb.httpsOxenOpenGroups
- val firstStepMigration = getExistingMappings(legacyOpenGroups, newOpenGroups)
-
- val secondStepMigration = getExistingMappings(httpBasedNewGroups, newOpenGroups)
-
- val groupDb = databaseComponent.groupDatabase()
- val lokiApiDb = databaseComponent.lokiAPIDatabase()
- val smsDb = databaseComponent.smsDatabase()
- val mmsDb = databaseComponent.mmsDatabase()
- val lokiMessageDatabase = databaseComponent.lokiMessageDatabase()
- val lokiThreadDatabase = databaseComponent.lokiThreadDatabase()
-
- firstStepMigration.forEach { (stub, old, new) ->
- val legacyEncodedGroupId = LEGACY_GROUP_ENCODED_ID+stub
- if (new == null) {
- val newEncodedGroupId = NEW_GROUP_ENCODED_ID+stub
- // migrate thread and group encoded values
- threadDb.migrateEncodedGroup(old, newEncodedGroupId)
- groupDb.migrateEncodedGroup(legacyEncodedGroupId, newEncodedGroupId)
- // migrate Loki API DB values
- // decode the hex to bytes, decode byte array to string i.e. "oxen" or "session"
- val decodedStub = Hex.fromStringCondensed(stub).decodeToString()
- val legacyLokiServerId = "${OpenGroupApi.legacyDefaultServer}.$decodedStub"
- val newLokiServerId = "${OpenGroupApi.defaultServer}.$decodedStub"
- lokiApiDb.migrateLegacyOpenGroup(legacyLokiServerId, newLokiServerId)
- // migrate loki thread db server info
- val oldServerInfo = lokiThreadDatabase.getOpenGroupChat(old)
- val newServerInfo = oldServerInfo!!.copy(server = OpenGroupApi.defaultServer, id = newLokiServerId)
- lokiThreadDatabase.setOpenGroupChat(newServerInfo, old)
- } else {
- // has a legacy and a new one
- // migrate SMS and MMS tables
- smsDb.migrateThreadId(old, new)
- mmsDb.migrateThreadId(old, new)
- lokiMessageDatabase.migrateThreadId(old, new)
- // delete group for legacy ID
- groupDb.delete(legacyEncodedGroupId)
- // delete thread for legacy ID
- threadDb.deleteConversation(old)
- lokiThreadDatabase.removeOpenGroupChat(old)
- }
- // maybe migrate jobs here
- }
-
- secondStepMigration.forEach { (stub, old, new) ->
- val legacyEncodedGroupId = HTTP_PREFIX + OPEN_GET_SESSION_TRAILING_DOT_ENCODED + stub
- if (new == null) {
- val newEncodedGroupId = NEW_GROUP_ENCODED_ID+stub
- // migrate thread and group encoded values
- threadDb.migrateEncodedGroup(old, newEncodedGroupId)
- groupDb.migrateEncodedGroup(legacyEncodedGroupId, newEncodedGroupId)
- // migrate Loki API DB values
- // decode the hex to bytes, decode byte array to string i.e. "oxen" or "session"
- val decodedStub = Hex.fromStringCondensed(stub).decodeToString()
- val legacyLokiServerId = "${OpenGroupApi.httpDefaultServer}.$decodedStub"
- val newLokiServerId = "${OpenGroupApi.defaultServer}.$decodedStub"
- lokiApiDb.migrateLegacyOpenGroup(legacyLokiServerId, newLokiServerId)
- // migrate loki thread db server info
- val oldServerInfo = lokiThreadDatabase.getOpenGroupChat(old)
- val newServerInfo = oldServerInfo!!.copy(server = OpenGroupApi.defaultServer, id = newLokiServerId)
- lokiThreadDatabase.setOpenGroupChat(newServerInfo, old)
- } else {
- // has a legacy and a new one
- // migrate SMS and MMS tables
- smsDb.migrateThreadId(old, new)
- mmsDb.migrateThreadId(old, new)
- lokiMessageDatabase.migrateThreadId(old, new)
- // delete group for legacy ID
- groupDb.delete(legacyEncodedGroupId)
- // delete thread for legacy ID
- threadDb.deleteConversation(old)
- lokiThreadDatabase.removeOpenGroupChat(old)
- }
- // maybe migrate jobs here
- }
-
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt
index 0b3c44a548..7e9d2640a1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt
@@ -20,6 +20,7 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto
lateinit var thread: ThreadRecord
var onViewDetailsTapped: (() -> Unit?)? = null
+ var onCopyConversationId: (() -> Unit?)? = null
var onPinTapped: (() -> Unit)? = null
var onUnpinTapped: (() -> Unit)? = null
var onBlockTapped: (() -> Unit)? = null
@@ -37,6 +38,8 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto
override fun onClick(v: View?) {
when (v) {
binding.detailsTextView -> onViewDetailsTapped?.invoke()
+ binding.copyConversationId -> onCopyConversationId?.invoke()
+ binding.copyCommunityUrl -> onCopyConversationId?.invoke()
binding.pinTextView -> onPinTapped?.invoke()
binding.unpinTextView -> onUnpinTapped?.invoke()
binding.blockTextView -> onBlockTapped?.invoke()
@@ -63,6 +66,10 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto
} else {
binding.detailsTextView.visibility = View.GONE
}
+ binding.copyConversationId.visibility = if (!recipient.isGroupRecipient && !recipient.isLocalNumber) View.VISIBLE else View.GONE
+ binding.copyConversationId.setOnClickListener(this)
+ binding.copyCommunityUrl.visibility = if (recipient.isOpenGroupRecipient) View.VISIBLE else View.GONE
+ binding.copyCommunityUrl.setOnClickListener(this)
binding.unMuteNotificationsTextView.isVisible = recipient.isMuted && !recipient.isLocalNumber
binding.muteNotificationsTextView.isVisible = !recipient.isMuted && !recipient.isLocalNumber
binding.unMuteNotificationsTextView.setOnClickListener(this)
@@ -81,7 +88,6 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto
override fun onStart() {
super.onStart()
val window = dialog?.window ?: return
- val isLightMode = UiModeUtilities.isDayUiMode(requireContext())
- window.setDimAmount(if (isLightMode) 0.1f else 0.75f)
+ window.setDimAmount(0.6f)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt
index bfa9b14489..c6a6e1f7f5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationView.kt
@@ -25,17 +25,17 @@ import org.thoughtcrime.securesms.util.getAccentColor
import java.util.Locale
class ConversationView : LinearLayout {
- private lateinit var binding: ViewConversationBinding
+ private val binding: ViewConversationBinding by lazy { ViewConversationBinding.bind(this) }
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
var thread: ThreadRecord? = null
// region Lifecycle
- constructor(context: Context) : super(context) { initialize() }
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
- private fun initialize() {
- binding = ViewConversationBinding.inflate(LayoutInflater.from(context), this, true)
+ override fun onFinishInflate() {
+ super.onFinishInflate()
layoutParams = RecyclerView.LayoutParams(screenWidth, RecyclerView.LayoutParams.WRAP_CONTENT)
}
// endregion
@@ -53,7 +53,7 @@ class ConversationView : LinearLayout {
} else {
binding.conversationViewDisplayNameTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
}
- background = if (thread.unreadCount > 0) {
+ binding.root.background = if (thread.unreadCount > 0) {
ContextCompat.getDrawable(context, R.drawable.conversation_unread_background)
} else {
ContextCompat.getDrawable(context, R.drawable.conversation_view_background)
@@ -79,8 +79,9 @@ class ConversationView : LinearLayout {
binding.unreadCountTextView.text = formattedUnreadCount
val textSize = if (unreadCount < 1000) 12.0f else 10.0f
binding.unreadCountTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
- binding.unreadCountIndicator.background.setTint(context.getAccentColor())
binding.unreadCountIndicator.isVisible = (unreadCount != 0 && !thread.isRead)
+ binding.unreadMentionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize)
+ binding.unreadMentionIndicator.isVisible = (thread.unreadMentionCount != 0 && thread.recipient.address.isGroup)
val senderDisplayName = getUserDisplayName(thread.recipient)
?: thread.recipient.address.toString()
binding.conversationViewDisplayNameTextView.text = senderDisplayName
@@ -99,11 +100,11 @@ class ConversationView : LinearLayout {
binding.snippetTextView.typeface = if (unreadCount > 0 && !thread.isRead) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
binding.snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE
if (isTyping) {
- binding.typingIndicatorView.startAnimation()
+ binding.typingIndicatorView.root.startAnimation()
} else {
- binding.typingIndicatorView.stopAnimation()
+ binding.typingIndicatorView.root.stopAnimation()
}
- binding.typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
+ binding.typingIndicatorView.root.visibility = if (isTyping) View.VISIBLE else View.GONE
binding.statusIndicatorImageView.visibility = View.VISIBLE
when {
!thread.isOutgoing -> binding.statusIndicatorImageView.visibility = View.GONE
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt
index 45f3b4a63f..0215040d37 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt
@@ -4,6 +4,8 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.ClipData
+import android.content.ClipboardManager
import android.os.Bundle
import android.text.SpannableString
import android.widget.Toast
@@ -202,7 +204,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
OpenGroupManager.startPolling()
JobQueue.shared.resumePendingJobs()
}
- // Set up typing observer
+
withContext(Dispatchers.Main) {
updateProfileButton()
TextSecurePreferences.events.filter { it == TextSecurePreferences.PROFILE_NAME_PREF }.collect {
@@ -365,6 +367,10 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
setupMessageRequestsBanner()
updateEmptyState()
}
+
+ ApplicationContext.getInstance(this@HomeActivity).typingStatusRepository.typingThreads.observe(this) { threadIds ->
+ homeAdapter.typingThreadIDs = (threadIds ?: setOf())
+ }
}
private fun updateEmptyState() {
@@ -422,6 +428,24 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
userDetailsBottomSheet.arguments = bundle
userDetailsBottomSheet.show(supportFragmentManager, userDetailsBottomSheet.tag)
}
+ bottomSheet.onCopyConversationId = onCopyConversationId@{
+ bottomSheet.dismiss()
+ if (!thread.recipient.isGroupRecipient && !thread.recipient.isLocalNumber) {
+ val clip = ClipData.newPlainText("Session ID", thread.recipient.address.toString())
+ val manager = getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
+ manager.setPrimaryClip(clip)
+ Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
+ }
+ else if (thread.recipient.isOpenGroupRecipient) {
+ val threadId = threadDb.getThreadIdIfExistsFor(thread.recipient) ?: return@onCopyConversationId Unit
+ val openGroup = DatabaseComponent.get(this@HomeActivity).lokiThreadDatabase().getOpenGroupChat(threadId) ?: return@onCopyConversationId Unit
+
+ val clip = ClipData.newPlainText("Community URL", openGroup.joinURL)
+ val manager = getSystemService(PassphraseRequiredActionBarActivity.CLIPBOARD_SERVICE) as ClipboardManager
+ manager.setPrimaryClip(clip)
+ Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
+ }
+ }
bottomSheet.onBlockTapped = {
bottomSheet.dismiss()
if (!thread.recipient.isBlocked) {
@@ -471,6 +495,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
.setPositiveButton(R.string.RecipientPreferenceActivity_block) { dialog, _ ->
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setBlocked(thread.recipient, true)
+ // TODO: Remove in UserConfig branch
+ ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@HomeActivity)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()
dialog.dismiss()
@@ -487,6 +513,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock) { dialog, _ ->
lifecycleScope.launch(Dispatchers.IO) {
recipientDatabase.setBlocked(thread.recipient, false)
+ // TODO: Remove in UserConfig branch
+ ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@HomeActivity)
withContext(Dispatchers.Main) {
binding.recyclerView.adapter!!.notifyDataSetChanged()
dialog.dismiss()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt
index 3efa841b54..4273794f5e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt
@@ -1,12 +1,14 @@
package org.thoughtcrime.securesms.home
import android.content.Context
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_ID
+import network.loki.messenger.R
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.mms.GlideRequests
@@ -63,6 +65,8 @@ class HomeAdapter(
lateinit var glide: GlideRequests
var typingThreadIDs = setOf()
set(value) {
+ if (field == value) { return }
+
field = value
// TODO: replace this with a diffed update or a partial change set with payloads
notifyDataSetChanged()
@@ -74,19 +78,20 @@ class HomeAdapter(
HeaderFooterViewHolder(header!!)
}
ITEM -> {
- val view = ConversationView(context)
- view.setOnClickListener { view.thread?.let { listener.onConversationClick(it) } }
- view.setOnLongClickListener {
- view.thread?.let { listener.onLongConversationClick(it) }
+ val conversationView = LayoutInflater.from(parent.context).inflate(R.layout.view_conversation, parent, false) as ConversationView
+ val viewHolder = ConversationViewHolder(conversationView)
+ viewHolder.view.setOnClickListener { viewHolder.view.thread?.let { listener.onConversationClick(it) } }
+ viewHolder.view.setOnLongClickListener {
+ viewHolder.view.thread?.let { listener.onLongConversationClick(it) }
true
}
- ViewHolder(view)
+ viewHolder
}
else -> throw Exception("viewType $viewType isn't valid")
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- if (holder is ViewHolder) {
+ if (holder is ConversationViewHolder) {
val offset = if (hasHeaderView()) position - 1 else position
val thread = data[offset]
val isTyping = typingThreadIDs.contains(thread.threadId)
@@ -95,7 +100,7 @@ class HomeAdapter(
}
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
- if (holder is ViewHolder) {
+ if (holder is ConversationViewHolder) {
holder.view.recycle()
} else {
super.onViewRecycled(holder)
@@ -108,7 +113,7 @@ class HomeAdapter(
override fun getItemCount(): Int = data.size + if (hasHeaderView()) 1 else 0
- class ViewHolder(val view: ConversationView) : RecyclerView.ViewHolder(view)
+ class ConversationViewHolder(val view: ConversationView) : RecyclerView.ViewHolder(view)
class HeaderFooterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt
index fcaf565e0d..b883709c0a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt
@@ -22,22 +22,31 @@ class HomeDiffUtil(
val newItem = new[newItemPosition]
// return early to save getDisplayBody or expensive calls
- val sameCount = oldItem.count == newItem.count
- if (!sameCount) return false
- val sameUnreads = oldItem.unreadCount == newItem.unreadCount
- if (!sameUnreads) return false
- val samePinned = oldItem.isPinned == newItem.isPinned
- if (!samePinned) return false
- val sameRecipientHash = oldItem.recipientHash == newItem.recipientHash
- if (!sameRecipientHash) return false
- val sameSnippet = oldItem.getDisplayBody(context) == newItem.getDisplayBody(context)
- if (!sameSnippet) return false
- val sameSendStatus = oldItem.isFailed == newItem.isFailed && oldItem.isDelivered == newItem.isDelivered
- && oldItem.isSent == newItem.isSent && oldItem.isPending == newItem.isPending
- if (!sameSendStatus) return false
+ var isSameItem = true
- // all same
- return true
+ if (isSameItem) { isSameItem = (oldItem.count == newItem.count) }
+ if (isSameItem) { isSameItem = (oldItem.unreadCount == newItem.unreadCount) }
+ if (isSameItem) { isSameItem = (oldItem.isPinned == newItem.isPinned) }
+
+ // The recipient is passed as a reference and changes to recipients update the reference so we
+ // need to cache the hashCode for the recipient and use that for diffing - unfortunately
+ // recipient data is also loaded asyncronously which means every thread will refresh at least
+ // once when the initial recipient data is loaded
+ if (isSameItem) { isSameItem = (oldItem.initialRecipientHash == newItem.initialRecipientHash) }
+
+ // Note: Two instances of 'SpannableString' may not equate even though their content matches
+ if (isSameItem) { isSameItem = (oldItem.getDisplayBody(context).toString() == newItem.getDisplayBody(context).toString()) }
+
+ if (isSameItem) {
+ isSameItem = (
+ oldItem.isFailed == newItem.isFailed &&
+ oldItem.isDelivered == newItem.isDelivered &&
+ oldItem.isSent == newItem.isSent &&
+ oldItem.isPending == newItem.isPending
+ )
+ }
+
+ return isSameItem
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt
index f3915abff6..bc9a9beced 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/home/UserDetailsBottomSheet.kt
@@ -117,8 +117,7 @@ class UserDetailsBottomSheet: BottomSheetDialogFragment() {
override fun onStart() {
super.onStart()
val window = dialog?.window ?: return
- val isLightMode = UiModeUtilities.isDayUiMode(requireContext())
- window.setDimAmount(if (isLightMode) 0.1f else 0.75f)
+ window.setDimAmount(0.6f)
}
fun saveNickName(recipient: Recipient) = with(binding) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java
deleted file mode 100644
index dc1d2afcf1..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/AlarmManagerScheduler.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import android.app.AlarmManager;
-import android.app.Application;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-import androidx.annotation.NonNull;
-
-import com.annimon.stream.Stream;
-
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.ApplicationContext;
-
-import java.util.List;
-import java.util.UUID;
-
-import network.loki.messenger.BuildConfig;
-
-/**
- * Schedules tasks using the {@link AlarmManager}.
- *
- * Given that this scheduler is only used when {@link KeepAliveService} is also used (which keeps
- * all of the {@link ConstraintObserver}s running), this only needs to schedule future runs in
- * situations where all constraints are already met. Otherwise, the {@link ConstraintObserver}s will
- * trigger future runs when the constraints are met.
- *
- * For the same reason, this class also doesn't have to schedule jobs that don't have delays.
- *
- * Important: Only use on API < 26.
- */
-public class AlarmManagerScheduler implements Scheduler {
-
- private static final String TAG = AlarmManagerScheduler.class.getSimpleName();
-
- private final Application application;
-
- AlarmManagerScheduler(@NonNull Application application) {
- this.application = application;
- }
-
- @Override
- public void schedule(long delay, @NonNull List constraints) {
- if (delay > 0 && Stream.of(constraints).allMatch(Constraint::isMet)) {
- setUniqueAlarm(application, System.currentTimeMillis() + delay);
- }
- }
-
- private void setUniqueAlarm(@NonNull Context context, long time) {
- AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(context, RetryReceiver.class);
-
- intent.setAction(BuildConfig.APPLICATION_ID + UUID.randomUUID().toString());
- alarmManager.set(AlarmManager.RTC_WAKEUP, time, PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE));
-
- Log.i(TAG, "Set an alarm to retry a job in " + (time - System.currentTimeMillis()) + " ms.");
- }
-
- public static class RetryReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "Received an alarm to retry a job.");
- ApplicationContext.getInstance(context).getJobManager().wakeUp();
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java
deleted file mode 100644
index 322366f4f4..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/CompositeScheduler.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import androidx.annotation.NonNull;
-
-import java.util.Arrays;
-import java.util.List;
-
-class CompositeScheduler implements Scheduler {
-
- private final List schedulers;
-
- CompositeScheduler(@NonNull Scheduler... schedulers) {
- this.schedulers = Arrays.asList(schedulers);
- }
-
- @Override
- public void schedule(long delay, @NonNull List constraints) {
- for (Scheduler scheduler : schedulers) {
- scheduler.schedule(delay, constraints);
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java
deleted file mode 100644
index b0a67e3d19..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintInstantiator.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import androidx.annotation.NonNull;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class ConstraintInstantiator {
-
- private final Map constraintFactories;
-
- ConstraintInstantiator(@NonNull Map constraintFactories) {
- this.constraintFactories = new HashMap<>(constraintFactories);
- }
-
- public @NonNull Constraint instantiate(@NonNull String constraintFactoryKey) {
- if (constraintFactories.containsKey(constraintFactoryKey)) {
- return constraintFactories.get(constraintFactoryKey).create();
- } else {
- throw new IllegalStateException("Tried to instantiate a constraint with key '" + constraintFactoryKey + "', but no matching factory was found.");
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java
deleted file mode 100644
index fd7f4fd43c..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ConstraintObserver.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import androidx.annotation.NonNull;
-
-public interface ConstraintObserver {
-
- void register(@NonNull Notifier notifier);
-
- interface Notifier {
- void onConstraintMet(@NonNull String reason);
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java
deleted file mode 100644
index c8a266bd87..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/DependencyInjector.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (C) 2014 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms.jobmanager;
-
-/**
- * Interface responsible for injecting dependencies into Jobs.
- */
-public interface DependencyInjector {
- void injectDependencies(Object object);
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java
deleted file mode 100644
index b0c2b974de..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/ExecutorFactory.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import androidx.annotation.NonNull;
-
-import java.util.concurrent.ExecutorService;
-
-public interface ExecutorFactory {
- @NonNull ExecutorService newSingleThreadExecutor(@NonNull String name);
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java
deleted file mode 100644
index b0f314eaa6..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/InAppScheduler.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import android.os.Handler;
-import android.os.HandlerThread;
-import androidx.annotation.NonNull;
-
-import com.annimon.stream.Stream;
-
-import org.session.libsignal.utilities.Log;
-
-import java.util.List;
-
-/**
- * Schedules future runs on an in-app handler. Intended to be used in combination with a persistent
- * {@link Scheduler} to improve responsiveness when the app is open.
- *
- * This should only schedule runs when all constraints are met. Because this only works when the
- * app is foregrounded, jobs that don't have their constraints met will be run when the relevant
- * {@link ConstraintObserver} is triggered.
- *
- * Similarly, this does not need to schedule retries with no delay, as this doesn't provide any
- * persistence, and other mechanisms will take care of that.
- */
-class InAppScheduler implements Scheduler {
-
- private static final String TAG = InAppScheduler.class.getSimpleName();
-
- private final JobManager jobManager;
- private final Handler handler;
-
- InAppScheduler(@NonNull JobManager jobManager) {
- HandlerThread handlerThread = new HandlerThread("InAppScheduler");
- handlerThread.start();
-
- this.jobManager = jobManager;
- this.handler = new Handler(handlerThread.getLooper());
- }
-
- @Override
- public void schedule(long delay, @NonNull List constraints) {
- if (delay > 0 && Stream.of(constraints).allMatch(Constraint::isMet)) {
- Log.i(TAG, "Scheduling a retry in " + delay + " ms.");
- handler.postDelayed(() -> {
- Log.i(TAG, "Triggering a job retry.");
- jobManager.wakeUp();
- }, delay);
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java
deleted file mode 100644
index 990207779d..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/Job.java
+++ /dev/null
@@ -1,286 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import android.content.Context;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.WorkerThread;
-
-import org.session.libsession.messaging.utilities.Data;
-import org.session.libsignal.utilities.Log;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A durable unit of work.
- *
- * Jobs have {@link Parameters} that describe the conditions upon when you'd like them to run, how
- * often they should be retried, and how long they should be retried for.
- *
- * Never rely on a specific instance of this class being run. It can be created and destroyed as the
- * job is retried. State that you want to save is persisted to a {@link Data} object in
- * {@link #serialize()}. Your job is then recreated using a {@link Factory} that you register in
- * {@link JobManager.Configuration.Builder#setJobFactories(Map)}, which is given the saved
- * {@link Data} bundle.
- *
- * @deprecated
- * use WorkManager
- * API instead.
- */
-public abstract class Job {
-
- private static final String TAG = Log.tag(Job.class);
-
- private final Parameters parameters;
-
- private String id;
- private int runAttempt;
- private long nextRunAttemptTime;
-
- protected Context context;
-
- public Job(@NonNull Parameters parameters) {
- this.parameters = parameters;
- }
-
- public final String getId() {
- return id;
- }
-
- public final @NonNull Parameters getParameters() {
- return parameters;
- }
-
- public final int getRunAttempt() {
- return runAttempt;
- }
-
- public final long getNextRunAttemptTime() {
- return nextRunAttemptTime;
- }
-
- /**
- * This is already called by {@link JobController} during job submission, but if you ever run a
- * job without submitting it to the {@link JobManager}, then you'll need to invoke this yourself.
- */
- public final void setContext(@NonNull Context context) {
- this.context = context;
- }
-
- /** Should only be invoked by {@link JobController} */
- final void setId(@NonNull String id) {
- this.id = id;
- }
-
- /** Should only be invoked by {@link JobController} */
- final void setRunAttempt(int runAttempt) {
- this.runAttempt = runAttempt;
- }
-
- /** Should only be invoked by {@link JobController} */
- final void setNextRunAttemptTime(long nextRunAttemptTime) {
- this.nextRunAttemptTime = nextRunAttemptTime;
- }
-
- @WorkerThread
- final void onSubmit() {
- Log.i(TAG, JobLogger.format(this, "onSubmit()"));
- onAdded();
- }
-
- /**
- * Called when the job is first submitted to the {@link JobManager}.
- */
- @WorkerThread
- public void onAdded() {
- }
-
- /**
- * Called after a job has run and its determined that a retry is required.
- */
- @WorkerThread
- public void onRetry() {
- }
-
- /**
- * Serialize your job state so that it can be recreated in the future.
- */
- public abstract @NonNull Data serialize();
-
- /**
- * Returns the key that can be used to find the relevant factory needed to create your job.
- */
- public abstract @NonNull String getFactoryKey();
-
- /**
- * Called to do your actual work.
- */
- @WorkerThread
- public abstract @NonNull Result run();
-
- /**
- * Called when your job has completely failed.
- */
- @WorkerThread
- public abstract void onCanceled();
-
- public interface Factory {
- @NonNull T create(@NonNull Parameters parameters, @NonNull Data data);
- }
-
- public enum Result {
- SUCCESS, FAILURE, RETRY
- }
-
- public static final class Parameters {
-
- public static final int IMMORTAL = -1;
- public static final int UNLIMITED = -1;
-
- private final long createTime;
- private final long lifespan;
- private final int maxAttempts;
- private final long maxBackoff;
- private final int maxInstances;
- private final String queue;
- private final List constraintKeys;
-
- private Parameters(long createTime,
- long lifespan,
- int maxAttempts,
- long maxBackoff,
- int maxInstances,
- @Nullable String queue,
- @NonNull List constraintKeys)
- {
- this.createTime = createTime;
- this.lifespan = lifespan;
- this.maxAttempts = maxAttempts;
- this.maxBackoff = maxBackoff;
- this.maxInstances = maxInstances;
- this.queue = queue;
- this.constraintKeys = constraintKeys;
- }
-
- public long getCreateTime() {
- return createTime;
- }
-
- public long getLifespan() {
- return lifespan;
- }
-
- public int getMaxAttempts() {
- return maxAttempts;
- }
-
- public long getMaxBackoff() {
- return maxBackoff;
- }
-
- public int getMaxInstances() {
- return maxInstances;
- }
-
- public @Nullable String getQueue() {
- return queue;
- }
-
- public List getConstraintKeys() {
- return constraintKeys;
- }
-
-
- public static final class Builder {
-
- private long createTime = System.currentTimeMillis();
- private long maxBackoff = TimeUnit.SECONDS.toMillis(30);
- private long lifespan = IMMORTAL;
- private int maxAttempts = 1;
- private int maxInstances = UNLIMITED;
- private String queue = null;
- private List constraintKeys = new LinkedList<>();
-
- /** Should only be invoked by {@link JobController} */
- Builder setCreateTime(long createTime) {
- this.createTime = createTime;
- return this;
- }
-
- /**
- * Specify the amount of time this job is allowed to be retried. Defaults to {@link #IMMORTAL}.
- */
- public @NonNull Builder setLifespan(long lifespan) {
- this.lifespan = lifespan;
- return this;
- }
-
- /**
- * Specify the maximum number of times you want to attempt this job. Defaults to 1.
- */
- public @NonNull Builder setMaxAttempts(int maxAttempts) {
- this.maxAttempts = maxAttempts;
- return this;
- }
-
- /**
- * Specify the longest amount of time to wait between retries. No guarantees that this will
- * be respected on API >= 26.
- */
- public @NonNull Builder setMaxBackoff(long maxBackoff) {
- this.maxBackoff = maxBackoff;
- return this;
- }
-
- /**
- * Specify the maximum number of instances you'd want of this job at any given time. If
- * enqueueing this job would put it over that limit, it will be ignored.
- *
- * Duplicates are determined by two jobs having the same {@link Job#getFactoryKey()}.
- *
- * This property is ignored if the job is submitted as part of a {@link JobManager.Chain}.
- *
- * Defaults to {@link #UNLIMITED}.
- */
- public @NonNull Builder setMaxInstances(int maxInstances) {
- this.maxInstances = maxInstances;
- return this;
- }
-
- /**
- * Specify a string representing a queue. All jobs within the same queue are run in a
- * serialized fashion -- one after the other, in order of insertion. Failure of a job earlier
- * in the queue has no impact on the execution of jobs later in the queue.
- */
- public @NonNull Builder setQueue(@Nullable String queue) {
- this.queue = queue;
- return this;
- }
-
- /**
- * Add a constraint via the key that was used to register its factory in
- * {@link JobManager.Configuration)};
- */
- public @NonNull Builder addConstraint(@NonNull String constraintKey) {
- constraintKeys.add(constraintKey);
- return this;
- }
-
- /**
- * Set constraints via the key that was used to register its factory in
- * {@link JobManager.Configuration)};
- */
- public @NonNull Builder setConstraints(@NonNull List constraintKeys) {
- this.constraintKeys.clear();
- this.constraintKeys.addAll(constraintKeys);
- return this;
- }
-
- public @NonNull Parameters build() {
- return new Parameters(createTime, lifespan, maxAttempts, maxBackoff, maxInstances, queue, constraintKeys);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java
deleted file mode 100644
index 33345a03e1..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobController.java
+++ /dev/null
@@ -1,354 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import android.app.Application;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.WorkerThread;
-
-import com.annimon.stream.Stream;
-
-import org.session.libsession.messaging.utilities.Data;
-import org.session.libsession.utilities.Debouncer;
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
-import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * Manages the queue of jobs. This is the only class that should write to {@link JobStorage} to
- * ensure consistency.
- */
-class JobController {
-
- private static final String TAG = JobController.class.getSimpleName();
-
- private final Application application;
- private final JobStorage jobStorage;
- private final JobInstantiator jobInstantiator;
- private final ConstraintInstantiator constraintInstantiator;
- private final Data.Serializer dataSerializer;
- private final Scheduler scheduler;
- private final Debouncer debouncer;
- private final Callback callback;
- private final Set runningJobs;
-
- JobController(@NonNull Application application,
- @NonNull JobStorage jobStorage,
- @NonNull JobInstantiator jobInstantiator,
- @NonNull ConstraintInstantiator constraintInstantiator,
- @NonNull Data.Serializer dataSerializer,
- @NonNull Scheduler scheduler,
- @NonNull Debouncer debouncer,
- @NonNull Callback callback)
- {
- this.application = application;
- this.jobStorage = jobStorage;
- this.jobInstantiator = jobInstantiator;
- this.constraintInstantiator = constraintInstantiator;
- this.dataSerializer = dataSerializer;
- this.scheduler = scheduler;
- this.debouncer = debouncer;
- this.callback = callback;
- this.runningJobs = new HashSet<>();
- }
-
- @WorkerThread
- synchronized void init() {
- jobStorage.init();
- jobStorage.updateAllJobsToBePending();
- notifyAll();
- }
-
- synchronized void wakeUp() {
- notifyAll();
- }
-
- @WorkerThread
- synchronized void submitNewJobChain(@NonNull List> chain) {
- chain = Stream.of(chain).filterNot(List::isEmpty).toList();
-
- if (chain.isEmpty()) {
- Log.w(TAG, "Tried to submit an empty job chain. Skipping.");
- return;
- }
-
- if (chainExceedsMaximumInstances(chain)) {
- Job solo = chain.get(0).get(0);
- Log.w(TAG, JobLogger.format(solo, "Already at the max instance count of " + solo.getParameters().getMaxInstances() + ". Skipping."));
- return;
- }
-
- insertJobChain(chain);
- scheduleJobs(chain.get(0));
- triggerOnSubmit(chain);
- notifyAll();
- }
-
- @WorkerThread
- synchronized void onRetry(@NonNull Job job) {
- int nextRunAttempt = job.getRunAttempt() + 1;
- long nextRunAttemptTime = calculateNextRunAttemptTime(System.currentTimeMillis(), nextRunAttempt, job.getParameters().getMaxBackoff());
-
- jobStorage.updateJobAfterRetry(job.getId(), false, nextRunAttempt, nextRunAttemptTime);
-
- List constraints = Stream.of(jobStorage.getConstraintSpecs(job.getId()))
- .map(ConstraintSpec::getFactoryKey)
- .map(constraintInstantiator::instantiate)
- .toList();
-
-
- long delay = Math.max(0, nextRunAttemptTime - System.currentTimeMillis());
-
- Log.i(TAG, JobLogger.format(job, "Scheduling a retry in " + delay + " ms."));
- scheduler.schedule(delay, constraints);
-
- notifyAll();
- }
-
- synchronized void onJobFinished(@NonNull Job job) {
- runningJobs.remove(job.getId());
- }
-
- @WorkerThread
- synchronized void onSuccess(@NonNull Job job) {
- jobStorage.deleteJob(job.getId());
- notifyAll();
- }
-
- /**
- * @return The list of all dependent jobs that should also be failed.
- */
- @WorkerThread
- synchronized @NonNull List onFailure(@NonNull Job job) {
- List dependents = Stream.of(jobStorage.getDependencySpecsThatDependOnJob(job.getId()))
- .map(DependencySpec::getJobId)
- .map(jobStorage::getJobSpec)
- .withoutNulls()
- .map(jobSpec -> {
- List constraintSpecs = jobStorage.getConstraintSpecs(jobSpec.getId());
- return createJob(jobSpec, constraintSpecs);
- })
- .toList();
-
- List all = new ArrayList<>(dependents.size() + 1);
- all.add(job);
- all.addAll(dependents);
-
- jobStorage.deleteJobs(Stream.of(all).map(Job::getId).toList());
-
- return dependents;
- }
-
- /**
- * Retrieves the next job that is eligible for execution. To be 'eligible' means that the job:
- * - Has no dependencies
- * - Has no unmet constraints
- *
- * This method will block until a job is available.
- * When the job returned from this method has been run, you must call {@link #onJobFinished(Job)}.
- */
- @WorkerThread
- synchronized @NonNull Job pullNextEligibleJobForExecution() {
- try {
- Job job;
-
- while ((job = getNextEligibleJobForExecution()) == null) {
- if (runningJobs.isEmpty()) {
- debouncer.publish(callback::onEmpty);
- }
-
- wait();
- }
-
- jobStorage.updateJobRunningState(job.getId(), true);
- runningJobs.add(job.getId());
-
- return job;
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted.");
- throw new AssertionError(e);
- }
- }
-
- /**
- * Retrieves a string representing the state of the job queue. Intended for debugging.
- */
- @WorkerThread
- synchronized @NonNull String getDebugInfo() {
- List jobs = jobStorage.getAllJobSpecs();
- List constraints = jobStorage.getAllConstraintSpecs();
- List dependencies = jobStorage.getAllDependencySpecs();
-
- StringBuilder info = new StringBuilder();
-
- info.append("-- Jobs\n");
- if (!jobs.isEmpty()) {
- Stream.of(jobs).forEach(j -> info.append(j.toString()).append('\n'));
- } else {
- info.append("None\n");
- }
-
- info.append("\n-- Constraints\n");
- if (!constraints.isEmpty()) {
- Stream.of(constraints).forEach(c -> info.append(c.toString()).append('\n'));
- } else {
- info.append("None\n");
- }
-
- info.append("\n-- Dependencies\n");
- if (!dependencies.isEmpty()) {
- Stream.of(dependencies).forEach(d -> info.append(d.toString()).append('\n'));
- } else {
- info.append("None\n");
- }
-
- return info.toString();
- }
-
- @WorkerThread
- private boolean chainExceedsMaximumInstances(@NonNull List> chain) {
- if (chain.size() == 1 && chain.get(0).size() == 1) {
- Job solo = chain.get(0).get(0);
-
- if (solo.getParameters().getMaxInstances() != Job.Parameters.UNLIMITED &&
- jobStorage.getJobInstanceCount(solo.getFactoryKey()) >= solo.getParameters().getMaxInstances())
- {
- return true;
- }
- }
- return false;
- }
-
- @WorkerThread
- private void triggerOnSubmit(@NonNull List> chain) {
- Stream.of(chain)
- .forEach(list -> Stream.of(list).forEach(job -> {
- job.setContext(application);
- job.onSubmit();
- }));
- }
-
- @WorkerThread
- private void insertJobChain(@NonNull List> chain) {
- List fullSpecs = new LinkedList<>();
- List dependsOn = Collections.emptyList();
-
- for (List jobList : chain) {
- for (Job job : jobList) {
- fullSpecs.add(buildFullSpec(job, dependsOn));
- }
- dependsOn = jobList;
- }
-
- jobStorage.insertJobs(fullSpecs);
- }
-
- @WorkerThread
- private @NonNull FullSpec buildFullSpec(@NonNull Job job, @NonNull List dependsOn) {
- String id = UUID.randomUUID().toString();
-
- job.setId(id);
- job.setRunAttempt(0);
-
- JobSpec jobSpec = new JobSpec(job.getId(),
- job.getFactoryKey(),
- job.getParameters().getQueue(),
- job.getParameters().getCreateTime(),
- job.getNextRunAttemptTime(),
- job.getRunAttempt(),
- job.getParameters().getMaxAttempts(),
- job.getParameters().getMaxBackoff(),
- job.getParameters().getLifespan(),
- job.getParameters().getMaxInstances(),
- dataSerializer.serialize(job.serialize()),
- false);
-
- List constraintSpecs = Stream.of(job.getParameters().getConstraintKeys())
- .map(key -> new ConstraintSpec(jobSpec.getId(), key))
- .toList();
-
- List dependencySpecs = Stream.of(dependsOn)
- .map(depends -> new DependencySpec(job.getId(), depends.getId()))
- .toList();
-
- return new FullSpec(jobSpec, constraintSpecs, dependencySpecs);
- }
-
- @WorkerThread
- private void scheduleJobs(@NonNull List jobs) {
- for (Job job : jobs) {
- List constraints = Stream.of(job.getParameters().getConstraintKeys())
- .map(key -> new ConstraintSpec(job.getId(), key))
- .map(ConstraintSpec::getFactoryKey)
- .map(constraintInstantiator::instantiate)
- .toList();
-
- scheduler.schedule(0, constraints);
- }
- }
-
- @WorkerThread
- private @Nullable Job getNextEligibleJobForExecution() {
- List jobSpecs = jobStorage.getPendingJobsWithNoDependenciesInCreatedOrder(System.currentTimeMillis());
-
- for (JobSpec jobSpec : jobSpecs) {
- List constraintSpecs = jobStorage.getConstraintSpecs(jobSpec.getId());
- List constraints = Stream.of(constraintSpecs)
- .map(ConstraintSpec::getFactoryKey)
- .map(constraintInstantiator::instantiate)
- .toList();
-
- if (Stream.of(constraints).allMatch(Constraint::isMet)) {
- return createJob(jobSpec, constraintSpecs);
- }
- }
-
- return null;
- }
-
- private @NonNull Job createJob(@NonNull JobSpec jobSpec, @NonNull List constraintSpecs) {
- Job.Parameters parameters = buildJobParameters(jobSpec, constraintSpecs);
- Data data = dataSerializer.deserialize(jobSpec.getSerializedData());
- Job job = jobInstantiator.instantiate(jobSpec.getFactoryKey(), parameters, data);
-
- job.setId(jobSpec.getId());
- job.setRunAttempt(jobSpec.getRunAttempt());
- job.setNextRunAttemptTime(jobSpec.getNextRunAttemptTime());
- job.setContext(application);
-
- return job;
- }
-
- private @NonNull Job.Parameters buildJobParameters(@NonNull JobSpec jobSpec, @NonNull List constraintSpecs) {
- return new Job.Parameters.Builder()
- .setCreateTime(jobSpec.getCreateTime())
- .setLifespan(jobSpec.getLifespan())
- .setMaxAttempts(jobSpec.getMaxAttempts())
- .setQueue(jobSpec.getQueueKey())
- .setConstraints(Stream.of(constraintSpecs).map(ConstraintSpec::getFactoryKey).toList())
- .build();
- }
-
- private long calculateNextRunAttemptTime(long currentTime, int nextAttempt, long maxBackoff) {
- int boundedAttempt = Math.min(nextAttempt, 30);
- long exponentialBackoff = (long) Math.pow(2, boundedAttempt) * 1000;
- long actualBackoff = Math.min(exponentialBackoff, maxBackoff);
-
- return currentTime + actualBackoff;
- }
-
- interface Callback {
- void onEmpty();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java
deleted file mode 100644
index 6d1527d131..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/JobInstantiator.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.thoughtcrime.securesms.jobmanager;
-
-import androidx.annotation.NonNull;
-
-import org.session.libsession.messaging.utilities.Data;
-
-import java.util.HashMap;
-import java.util.Map;
-
-class JobInstantiator {
-
- private final Map