From 9c40de5bf127f4d13a4640cdc747826f80cfad93 Mon Sep 17 00:00:00 2001 From: Alan Evans Date: Fri, 12 Apr 2019 16:22:38 -0300 Subject: [PATCH] Save the SMS setting on a per-conversation basis. --- .../conversation/ConversationActivity.java | 21 ++++++++++----- .../securesms/database/RecipientDatabase.java | 27 ++++++++++++++++--- .../database/helpers/SQLCipherOpenHelper.java | 7 ++++- .../securesms/jobs/PushDecryptJob.java | 8 ++++++ .../securesms/recipients/Recipient.java | 18 ++++++++++++- .../recipients/RecipientProvider.java | 2 ++ 6 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 0b1379864e..65d588819d 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -135,6 +135,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MmsSmsColumns.Types; +import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.identity.IdentityRecordList; @@ -1179,8 +1180,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE); if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS); - if (isSecureText || isPushGroupConversation()) sendButton.setDefaultTransport(Type.TEXTSECURE); - else sendButton.setDefaultTransport(Type.SMS); + if (recipient.isForceSmsSelection()) { + sendButton.setDefaultTransport(Type.SMS); + } else { + if (isSecureText || isPushGroupConversation()) sendButton.setDefaultTransport(Type.TEXTSECURE); + else sendButton.setDefaultTransport(Type.SMS); + } calculateCharactersRemaining(); supportInvalidateOptionsMenu(); @@ -1517,7 +1522,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity composeText.setTransport(newTransport); buttonToggle.getBackground().setColorFilter(newTransport.getBackgroundColor(), Mode.MULTIPLY); buttonToggle.getBackground().invalidateSelf(); - if (manuallySelected) recordSubscriptionIdPreference(newTransport.getSimSubscriptionId()); + if (manuallySelected) recordTransportPreference(newTransport); }); titleView.setOnClickListener(v -> handleConversationSettings()); @@ -2213,12 +2218,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } - private void recordSubscriptionIdPreference(final Optional subscriptionId) { + private void recordTransportPreference(TransportOption transportOption) { new AsyncTask() { @Override protected Void doInBackground(Void... params) { - DatabaseFactory.getRecipientDatabase(ConversationActivity.this) - .setDefaultSubscriptionId(recipient, subscriptionId.or(-1)); + RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(ConversationActivity.this); + + recipientDatabase.setDefaultSubscriptionId(recipient, transportOption.getSimSubscriptionId().or(-1)); + + recipientDatabase.setForceSmsSelection(recipient, recipient.getRegistered() == RegisteredState.REGISTERED && transportOption.isSms()); + return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); diff --git a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java index d77976bd75..28c9611d6a 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -57,12 +57,14 @@ public class RecipientDatabase extends Database { private static final String CALL_VIBRATE = "call_vibrate"; private static final String NOTIFICATION_CHANNEL = "notification_channel"; private static final String UNIDENTIFIED_ACCESS_MODE = "unidentified_access_mode"; + private static final String FORCE_SMS_SELECTION = "force_sms_selection"; private static final String[] RECIPIENT_PROJECTION = new String[] { BLOCK, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED, PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI, SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL, - UNIDENTIFIED_ACCESS_MODE + UNIDENTIFIED_ACCESS_MODE, + FORCE_SMS_SELECTION, }; static final List TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION) @@ -147,7 +149,8 @@ public class RecipientDatabase extends Database { CALL_RINGTONE + " TEXT DEFAULT NULL, " + CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " + NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " + - UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0);"; + UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " + + FORCE_SMS_SELECTION + " INTEGER DEFAULT 0);"; public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) { super(context, databaseHelper); @@ -211,6 +214,7 @@ public class RecipientDatabase extends Database { boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1; String notificationChannel = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION_CHANNEL)); int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE)); + boolean forceSmsSelection = cursor.getInt(cursor.getColumnIndexOrThrow(FORCE_SMS_SELECTION)) == 1; MaterialColor color; byte[] profileKey = null; @@ -241,7 +245,8 @@ public class RecipientDatabase extends Database { profileKey, systemDisplayName, systemContactPhoto, systemPhoneLabel, systemContactUri, signalProfileName, signalProfileAvatar, profileSharing, - notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode))); + notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode), + forceSmsSelection)); } public BulkOperationsHandle resetAllSystemContactInfo() { @@ -273,6 +278,13 @@ public class RecipientDatabase extends Database { recipient.resolve().setDefaultSubscriptionId(Optional.of(defaultSubscriptionId)); } + public void setForceSmsSelection(@NonNull Recipient recipient, boolean forceSmsSelection) { + ContentValues contentValues = new ContentValues(1); + contentValues.put(FORCE_SMS_SELECTION, forceSmsSelection ? 1 : 0); + updateOrInsert(recipient.getAddress(), contentValues); + recipient.resolve().setForceSmsSelection(forceSmsSelection); + } + public void setBlocked(@NonNull Recipient recipient, boolean blocked) { ContentValues values = new ContentValues(); values.put(BLOCK, blocked ? 1 : 0); @@ -556,6 +568,7 @@ public class RecipientDatabase extends Database { private final boolean profileSharing; private final String notificationChannel; private final UnidentifiedAccessMode unidentifiedAccessMode; + private final boolean forceSmsSelection; RecipientSettings(boolean blocked, long muteUntil, @NonNull VibrateState messageVibrateState, @@ -576,7 +589,8 @@ public class RecipientDatabase extends Database { @Nullable String signalProfileAvatar, boolean profileSharing, @Nullable String notificationChannel, - @NonNull UnidentifiedAccessMode unidentifiedAccessMode) + @NonNull UnidentifiedAccessMode unidentifiedAccessMode, + boolean forceSmsSelection) { this.blocked = blocked; this.muteUntil = muteUntil; @@ -599,6 +613,7 @@ public class RecipientDatabase extends Database { this.profileSharing = profileSharing; this.notificationChannel = notificationChannel; this.unidentifiedAccessMode = unidentifiedAccessMode; + this.forceSmsSelection = forceSmsSelection; } public @Nullable MaterialColor getColor() { @@ -684,6 +699,10 @@ public class RecipientDatabase extends Database { public @NonNull UnidentifiedAccessMode getUnidentifiedAccessMode() { return unidentifiedAccessMode; } + + public boolean isForceSmsSelection() { + return forceSmsSelection; + } } public static class RecipientReader implements Closeable { diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index c7b3268cbc..609ce7afdd 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -62,8 +62,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int PREVIEWS = 16; private static final int CONVERSATION_SEARCH = 17; private static final int SELF_ATTACHMENT_CLEANUP = 18; + private static final int RECIPIENT_FORCE_SMS_SELECTION = 19; - private static final int DATABASE_VERSION = 18; + private static final int DATABASE_VERSION = 19; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -402,6 +403,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { } } + if (oldVersion < RECIPIENT_FORCE_SMS_SELECTION) { + db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN force_sms_selection INTEGER DEFAULT 0"); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 13e3d77361..a33d07121a 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -284,6 +284,8 @@ public class PushDecryptJob extends ContextJob { Log.w(TAG, "Got unrecognized message..."); } + resetRecipientToPush(Recipient.from(context, Address.fromExternal(context, content.getSender()), false)); + if (envelope.isPreKeySignalMessage()) { ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context)); } @@ -1163,6 +1165,12 @@ public class PushDecryptJob extends ContextJob { return false; } + private void resetRecipientToPush(@NonNull Recipient recipient) { + if (recipient.isForceSmsSelection()) { + DatabaseFactory.getRecipientDatabase(context).setForceSmsSelection(recipient, false); + } + } + @SuppressWarnings("WeakerAccess") private static class StorageFailedException extends Exception { private final String sender; diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index a26e857693..222e8bf99d 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -95,6 +95,7 @@ public class Recipient implements RecipientModifiedListener { private @Nullable String profileAvatar; private boolean profileSharing; private String notificationChannel; + private boolean forceSmsSelection; private @NonNull UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED; @@ -148,6 +149,7 @@ public class Recipient implements RecipientModifiedListener { this.profileAvatar = stale.profileAvatar; this.profileSharing = stale.profileSharing; this.unidentifiedAccessMode = stale.unidentifiedAccessMode; + this.forceSmsSelection = stale.forceSmsSelection; this.participants.clear(); this.participants.addAll(stale.participants); @@ -175,6 +177,7 @@ public class Recipient implements RecipientModifiedListener { this.profileAvatar = details.get().profileAvatar; this.profileSharing = details.get().profileSharing; this.unidentifiedAccessMode = details.get().unidentifiedAccessMode; + this.forceSmsSelection = details.get().forceSmsSelection; this.participants.clear(); this.participants.addAll(details.get().participants); @@ -207,8 +210,8 @@ public class Recipient implements RecipientModifiedListener { Recipient.this.profileName = result.profileName; Recipient.this.profileAvatar = result.profileAvatar; Recipient.this.profileSharing = result.profileSharing; - Recipient.this.profileName = result.profileName; Recipient.this.unidentifiedAccessMode = result.unidentifiedAccessMode; + Recipient.this.forceSmsSelection = result.forceSmsSelection; Recipient.this.participants.clear(); Recipient.this.participants.addAll(result.participants); @@ -257,6 +260,7 @@ public class Recipient implements RecipientModifiedListener { this.profileAvatar = details.profileAvatar; this.profileSharing = details.profileSharing; this.unidentifiedAccessMode = details.unidentifiedAccessMode; + this.forceSmsSelection = details.forceSmsSelection; this.participants.addAll(details.participants); this.resolving = false; @@ -625,6 +629,18 @@ public class Recipient implements RecipientModifiedListener { if (notify) notifyListeners(); } + public boolean isForceSmsSelection() { + return forceSmsSelection; + } + + public void setForceSmsSelection(boolean value) { + synchronized (this) { + this.forceSmsSelection = value; + } + + notifyListeners(); + } + public synchronized @Nullable byte[] getProfileKey() { return profileKey; } diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index 47aae97c96..9c4d72f0dd 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -181,6 +181,7 @@ class RecipientProvider { final boolean isLocalNumber; @Nullable final String notificationChannel; @NonNull final UnidentifiedAccessMode unidentifiedAccessMode; + final boolean forceSmsSelection; RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId, boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings, @@ -210,6 +211,7 @@ class RecipientProvider { this.isLocalNumber = isLocalNumber; this.notificationChannel = settings != null ? settings.getNotificationChannel() : null; this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED; + this.forceSmsSelection = settings != null && settings.isForceSmsSelection(); if (name == null && settings != null) this.name = settings.getSystemDisplayName(); else this.name = name;