Save the SMS setting on a per-conversation basis.

This commit is contained in:
Alan Evans 2019-04-12 16:22:38 -03:00 committed by Greyson Parrelli
parent 11a2ed0743
commit 9c40de5bf1
6 changed files with 71 additions and 12 deletions

View File

@ -135,6 +135,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus; import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types; 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.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.identity.IdentityRecordList; import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
@ -1179,8 +1180,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE); if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE);
if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS); if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS);
if (recipient.isForceSmsSelection()) {
sendButton.setDefaultTransport(Type.SMS);
} else {
if (isSecureText || isPushGroupConversation()) sendButton.setDefaultTransport(Type.TEXTSECURE); if (isSecureText || isPushGroupConversation()) sendButton.setDefaultTransport(Type.TEXTSECURE);
else sendButton.setDefaultTransport(Type.SMS); else sendButton.setDefaultTransport(Type.SMS);
}
calculateCharactersRemaining(); calculateCharactersRemaining();
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
@ -1517,7 +1522,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
composeText.setTransport(newTransport); composeText.setTransport(newTransport);
buttonToggle.getBackground().setColorFilter(newTransport.getBackgroundColor(), Mode.MULTIPLY); buttonToggle.getBackground().setColorFilter(newTransport.getBackgroundColor(), Mode.MULTIPLY);
buttonToggle.getBackground().invalidateSelf(); buttonToggle.getBackground().invalidateSelf();
if (manuallySelected) recordSubscriptionIdPreference(newTransport.getSimSubscriptionId()); if (manuallySelected) recordTransportPreference(newTransport);
}); });
titleView.setOnClickListener(v -> handleConversationSettings()); titleView.setOnClickListener(v -> handleConversationSettings());
@ -2213,12 +2218,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
} }
private void recordSubscriptionIdPreference(final Optional<Integer> subscriptionId) { private void recordTransportPreference(TransportOption transportOption) {
new AsyncTask<Void, Void, Void>() { new AsyncTask<Void, Void, Void>() {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this) RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(ConversationActivity.this);
.setDefaultSubscriptionId(recipient, subscriptionId.or(-1));
recipientDatabase.setDefaultSubscriptionId(recipient, transportOption.getSimSubscriptionId().or(-1));
recipientDatabase.setForceSmsSelection(recipient, recipient.getRegistered() == RegisteredState.REGISTERED && transportOption.isSms());
return null; return null;
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

View File

@ -57,12 +57,14 @@ public class RecipientDatabase extends Database {
private static final String CALL_VIBRATE = "call_vibrate"; private static final String CALL_VIBRATE = "call_vibrate";
private static final String NOTIFICATION_CHANNEL = "notification_channel"; private static final String NOTIFICATION_CHANNEL = "notification_channel";
private static final String UNIDENTIFIED_ACCESS_MODE = "unidentified_access_mode"; 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[] { 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, 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, PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI,
SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL, SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL,
UNIDENTIFIED_ACCESS_MODE UNIDENTIFIED_ACCESS_MODE,
FORCE_SMS_SELECTION,
}; };
static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION) static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
@ -147,7 +149,8 @@ public class RecipientDatabase extends Database {
CALL_RINGTONE + " TEXT DEFAULT NULL, " + CALL_RINGTONE + " TEXT DEFAULT NULL, " +
CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " + CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " + 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) { public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper); super(context, databaseHelper);
@ -211,6 +214,7 @@ public class RecipientDatabase extends Database {
boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1; boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1;
String notificationChannel = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION_CHANNEL)); String notificationChannel = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION_CHANNEL));
int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE)); int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE));
boolean forceSmsSelection = cursor.getInt(cursor.getColumnIndexOrThrow(FORCE_SMS_SELECTION)) == 1;
MaterialColor color; MaterialColor color;
byte[] profileKey = null; byte[] profileKey = null;
@ -241,7 +245,8 @@ public class RecipientDatabase extends Database {
profileKey, systemDisplayName, systemContactPhoto, profileKey, systemDisplayName, systemContactPhoto,
systemPhoneLabel, systemContactUri, systemPhoneLabel, systemContactUri,
signalProfileName, signalProfileAvatar, profileSharing, signalProfileName, signalProfileAvatar, profileSharing,
notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode))); notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
forceSmsSelection));
} }
public BulkOperationsHandle resetAllSystemContactInfo() { public BulkOperationsHandle resetAllSystemContactInfo() {
@ -273,6 +278,13 @@ public class RecipientDatabase extends Database {
recipient.resolve().setDefaultSubscriptionId(Optional.of(defaultSubscriptionId)); 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) { public void setBlocked(@NonNull Recipient recipient, boolean blocked) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(BLOCK, blocked ? 1 : 0); values.put(BLOCK, blocked ? 1 : 0);
@ -556,6 +568,7 @@ public class RecipientDatabase extends Database {
private final boolean profileSharing; private final boolean profileSharing;
private final String notificationChannel; private final String notificationChannel;
private final UnidentifiedAccessMode unidentifiedAccessMode; private final UnidentifiedAccessMode unidentifiedAccessMode;
private final boolean forceSmsSelection;
RecipientSettings(boolean blocked, long muteUntil, RecipientSettings(boolean blocked, long muteUntil,
@NonNull VibrateState messageVibrateState, @NonNull VibrateState messageVibrateState,
@ -576,7 +589,8 @@ public class RecipientDatabase extends Database {
@Nullable String signalProfileAvatar, @Nullable String signalProfileAvatar,
boolean profileSharing, boolean profileSharing,
@Nullable String notificationChannel, @Nullable String notificationChannel,
@NonNull UnidentifiedAccessMode unidentifiedAccessMode) @NonNull UnidentifiedAccessMode unidentifiedAccessMode,
boolean forceSmsSelection)
{ {
this.blocked = blocked; this.blocked = blocked;
this.muteUntil = muteUntil; this.muteUntil = muteUntil;
@ -599,6 +613,7 @@ public class RecipientDatabase extends Database {
this.profileSharing = profileSharing; this.profileSharing = profileSharing;
this.notificationChannel = notificationChannel; this.notificationChannel = notificationChannel;
this.unidentifiedAccessMode = unidentifiedAccessMode; this.unidentifiedAccessMode = unidentifiedAccessMode;
this.forceSmsSelection = forceSmsSelection;
} }
public @Nullable MaterialColor getColor() { public @Nullable MaterialColor getColor() {
@ -684,6 +699,10 @@ public class RecipientDatabase extends Database {
public @NonNull UnidentifiedAccessMode getUnidentifiedAccessMode() { public @NonNull UnidentifiedAccessMode getUnidentifiedAccessMode() {
return unidentifiedAccessMode; return unidentifiedAccessMode;
} }
public boolean isForceSmsSelection() {
return forceSmsSelection;
}
} }
public static class RecipientReader implements Closeable { public static class RecipientReader implements Closeable {

View File

@ -62,8 +62,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int PREVIEWS = 16; private static final int PREVIEWS = 16;
private static final int CONVERSATION_SEARCH = 17; private static final int CONVERSATION_SEARCH = 17;
private static final int SELF_ATTACHMENT_CLEANUP = 18; 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 static final String DATABASE_NAME = "signal.db";
private final Context context; 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(); db.setTransactionSuccessful();
} finally { } finally {
db.endTransaction(); db.endTransaction();

View File

@ -284,6 +284,8 @@ public class PushDecryptJob extends ContextJob {
Log.w(TAG, "Got unrecognized message..."); Log.w(TAG, "Got unrecognized message...");
} }
resetRecipientToPush(Recipient.from(context, Address.fromExternal(context, content.getSender()), false));
if (envelope.isPreKeySignalMessage()) { if (envelope.isPreKeySignalMessage()) {
ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context)); ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context));
} }
@ -1163,6 +1165,12 @@ public class PushDecryptJob extends ContextJob {
return false; return false;
} }
private void resetRecipientToPush(@NonNull Recipient recipient) {
if (recipient.isForceSmsSelection()) {
DatabaseFactory.getRecipientDatabase(context).setForceSmsSelection(recipient, false);
}
}
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
private static class StorageFailedException extends Exception { private static class StorageFailedException extends Exception {
private final String sender; private final String sender;

View File

@ -95,6 +95,7 @@ public class Recipient implements RecipientModifiedListener {
private @Nullable String profileAvatar; private @Nullable String profileAvatar;
private boolean profileSharing; private boolean profileSharing;
private String notificationChannel; private String notificationChannel;
private boolean forceSmsSelection;
private @NonNull UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED; private @NonNull UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED;
@ -148,6 +149,7 @@ public class Recipient implements RecipientModifiedListener {
this.profileAvatar = stale.profileAvatar; this.profileAvatar = stale.profileAvatar;
this.profileSharing = stale.profileSharing; this.profileSharing = stale.profileSharing;
this.unidentifiedAccessMode = stale.unidentifiedAccessMode; this.unidentifiedAccessMode = stale.unidentifiedAccessMode;
this.forceSmsSelection = stale.forceSmsSelection;
this.participants.clear(); this.participants.clear();
this.participants.addAll(stale.participants); this.participants.addAll(stale.participants);
@ -175,6 +177,7 @@ public class Recipient implements RecipientModifiedListener {
this.profileAvatar = details.get().profileAvatar; this.profileAvatar = details.get().profileAvatar;
this.profileSharing = details.get().profileSharing; this.profileSharing = details.get().profileSharing;
this.unidentifiedAccessMode = details.get().unidentifiedAccessMode; this.unidentifiedAccessMode = details.get().unidentifiedAccessMode;
this.forceSmsSelection = details.get().forceSmsSelection;
this.participants.clear(); this.participants.clear();
this.participants.addAll(details.get().participants); this.participants.addAll(details.get().participants);
@ -207,8 +210,8 @@ public class Recipient implements RecipientModifiedListener {
Recipient.this.profileName = result.profileName; Recipient.this.profileName = result.profileName;
Recipient.this.profileAvatar = result.profileAvatar; Recipient.this.profileAvatar = result.profileAvatar;
Recipient.this.profileSharing = result.profileSharing; Recipient.this.profileSharing = result.profileSharing;
Recipient.this.profileName = result.profileName;
Recipient.this.unidentifiedAccessMode = result.unidentifiedAccessMode; Recipient.this.unidentifiedAccessMode = result.unidentifiedAccessMode;
Recipient.this.forceSmsSelection = result.forceSmsSelection;
Recipient.this.participants.clear(); Recipient.this.participants.clear();
Recipient.this.participants.addAll(result.participants); Recipient.this.participants.addAll(result.participants);
@ -257,6 +260,7 @@ public class Recipient implements RecipientModifiedListener {
this.profileAvatar = details.profileAvatar; this.profileAvatar = details.profileAvatar;
this.profileSharing = details.profileSharing; this.profileSharing = details.profileSharing;
this.unidentifiedAccessMode = details.unidentifiedAccessMode; this.unidentifiedAccessMode = details.unidentifiedAccessMode;
this.forceSmsSelection = details.forceSmsSelection;
this.participants.addAll(details.participants); this.participants.addAll(details.participants);
this.resolving = false; this.resolving = false;
@ -625,6 +629,18 @@ public class Recipient implements RecipientModifiedListener {
if (notify) notifyListeners(); if (notify) notifyListeners();
} }
public boolean isForceSmsSelection() {
return forceSmsSelection;
}
public void setForceSmsSelection(boolean value) {
synchronized (this) {
this.forceSmsSelection = value;
}
notifyListeners();
}
public synchronized @Nullable byte[] getProfileKey() { public synchronized @Nullable byte[] getProfileKey() {
return profileKey; return profileKey;
} }

View File

@ -181,6 +181,7 @@ class RecipientProvider {
final boolean isLocalNumber; final boolean isLocalNumber;
@Nullable final String notificationChannel; @Nullable final String notificationChannel;
@NonNull final UnidentifiedAccessMode unidentifiedAccessMode; @NonNull final UnidentifiedAccessMode unidentifiedAccessMode;
final boolean forceSmsSelection;
RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId, RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId,
boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings, boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings,
@ -210,6 +211,7 @@ class RecipientProvider {
this.isLocalNumber = isLocalNumber; this.isLocalNumber = isLocalNumber;
this.notificationChannel = settings != null ? settings.getNotificationChannel() : null; this.notificationChannel = settings != null ? settings.getNotificationChannel() : null;
this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED; this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED;
this.forceSmsSelection = settings != null && settings.isForceSmsSelection();
if (name == null && settings != null) this.name = settings.getSystemDisplayName(); if (name == null && settings != null) this.name = settings.getSystemDisplayName();
else this.name = name; else this.name = name;