diff --git a/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionActivity.java index cf3ca932e..980bc87c8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionActivity.java @@ -70,7 +70,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit @Override protected void onCreate(Bundle icicle, boolean ready) { if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) { - boolean includeSms = Util.isDefaultSmsProvider(this) && SignalStore.misc().getSmsExportPhase().isSmsSupported(); + boolean includeSms = SignalStore.misc().getSmsExportPhase().allowSmsFeatures(); int displayMode = includeSms ? DisplayMode.FLAG_ALL : DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF; getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java index 6fcc10074..07de6d4dd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/NewConversationActivity.java @@ -106,7 +106,7 @@ public class NewConversationActivity extends ContactSelectionActivity @Override public void onBeforeContactSelected(@NonNull Optional recipientId, String number, @NonNull Consumer callback) { - boolean smsSupported = Util.isDefaultSmsProvider(this) && SignalStore.misc().getSmsExportPhase().isSmsSupported(); + boolean smsSupported = SignalStore.misc().getSmsExportPhase().allowSmsFeatures(); if (recipientId.isPresent()) { launch(Recipient.resolved(recipientId.get())); @@ -283,7 +283,7 @@ public class NewConversationActivity extends ContactSelectionActivity return null; } - if (recipient.isRegistered() || (Util.isDefaultSmsProvider(this) && SignalStore.misc().getSmsExportPhase().isSmsSupported())) { + if (recipient.isRegistered() || (SignalStore.misc().getSmsExportPhase().allowSmsFeatures())) { return new ActionItem( R.drawable.ic_phone_right_24, getString(R.string.NewConversationActivity__audio_call), diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/SendButton.kt b/app/src/main/java/org/thoughtcrime/securesms/components/SendButton.kt index 1bc79feaf..975fe81a5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/SendButton.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/SendButton.kt @@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.components.menu.ActionItem import org.thoughtcrime.securesms.components.menu.SignalContextMenu import org.thoughtcrime.securesms.conversation.MessageSendType import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.ViewUtil import java.lang.AssertionError import java.util.concurrent.CopyOnWriteArrayList @@ -157,7 +156,7 @@ class SendButton(context: Context, attributeSet: AttributeSet?) : AppCompatImage } if (availableSendTypes.size == 1) { - return if (!Util.isDefaultSmsProvider(context) || !SignalStore.misc().smsExportPhase.isSmsSupported()) { + return if (!SignalStore.misc().smsExportPhase.allowSmsFeatures()) { Snackbar.make(snackbarContainer, R.string.InputPanel__sms_messaging_is_no_longer_supported_in_signal, Snackbar.LENGTH_SHORT).show() true } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt index 2f4369217..1217eba5c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.components.settings.app.chats.sms.SmsExportSta import org.thoughtcrime.securesms.components.settings.configure import org.thoughtcrime.securesms.exporter.flow.SmsExportActivity import org.thoughtcrime.securesms.exporter.flow.SmsExportDialogs +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter import org.thoughtcrime.securesms.util.navigation.safeNavigate @@ -45,7 +46,7 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch private fun getConfiguration(state: ChatsSettingsState): DSLConfiguration { return configure { - if (!state.useAsDefaultSmsApp) { + if (!state.useAsDefaultSmsApp && SignalStore.misc().smsExportPhase.isAtLeastPhase1()) { when (state.smsExportState) { SmsExportState.FETCHING -> Unit SmsExportState.HAS_UNEXPORTED_MESSAGES -> { @@ -73,9 +74,7 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch SmsExportState.NO_SMS_MESSAGES_IN_DATABASE -> Unit SmsExportState.NOT_AVAILABLE -> Unit } - } - - if (state.useAsDefaultSmsApp) { + } else { clickPref( title = DSLSettingsText.from(R.string.preferences__sms_mms), onClick = { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt index 696501331..78132c1f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt @@ -19,6 +19,8 @@ import org.thoughtcrime.securesms.components.settings.models.OutlinedLearnMore import org.thoughtcrime.securesms.exporter.flow.SmsExportActivity import org.thoughtcrime.securesms.exporter.flow.SmsExportDialogs import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.keyvalue.SmsExportPhase +import org.thoughtcrime.securesms.util.SmsUtil import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter import org.thoughtcrime.securesms.util.navigation.safeNavigate @@ -56,14 +58,16 @@ class SmsSettingsFragment : DSLSettingsFragment(R.string.preferences__sms_mms) { SignalStore.settings().setDefaultSms(true) } else { SignalStore.settings().setDefaultSms(false) - findNavController().navigateUp() + if (SignalStore.misc().smsExportPhase.isAtLeastPhase1()) { + findNavController().navigateUp() + } } } private fun getConfiguration(state: SmsSettingsState): DSLConfiguration { return configure { - if (state.useAsDefaultSmsApp) { + if (state.useAsDefaultSmsApp && SignalStore.misc().smsExportPhase.isAtLeastPhase1()) { customPref( OutlinedLearnMore.Model( summary = DSLSettingsText.from(R.string.SmsSettingsFragment__sms_support_will_be_removed_soon_to_focus_on_encrypted_messaging), @@ -100,13 +104,17 @@ class SmsSettingsFragment : DSLSettingsFragment(R.string.preferences__sms_mms) { SmsExportState.NOT_AVAILABLE -> Unit } - if (state.useAsDefaultSmsApp) { + if (state.useAsDefaultSmsApp || SignalStore.misc().smsExportPhase == SmsExportPhase.PHASE_0) { @Suppress("DEPRECATION") clickPref( title = DSLSettingsText.from(R.string.SmsSettingsFragment__use_as_default_sms_app), - summary = DSLSettingsText.from(R.string.arrays__enabled), + summary = DSLSettingsText.from(if (state.useAsDefaultSmsApp) R.string.arrays__enabled else R.string.arrays__disabled), onClick = { - startDefaultAppSelectionIntent() + if (state.useAsDefaultSmsApp) { + startDefaultAppSelectionIntent() + } else { + startActivityForResult(SmsUtil.getSmsRoleIntent(requireContext()), SMS_REQUEST_CODE.toInt()) + } } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt index 01f3eb137..b305a39f0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/SelectRecipientsFragment.kt @@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.groups.SelectionLimits import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.LifecycleDisposable -import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.ViewUtil import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton import java.util.Optional @@ -106,7 +105,7 @@ class SelectRecipientsFragment : LoggingFragment(), ContactSelectionListFragment ContactsCursorLoader.DisplayMode.FLAG_HIDE_RECENT_HEADER or ContactsCursorLoader.DisplayMode.FLAG_GROUPS_AFTER_CONTACTS - if (Util.isDefaultSmsProvider(requireContext()) && SignalStore.misc().smsExportPhase.isSmsSupported()) { + if (SignalStore.misc().smsExportPhase.allowSmsFeatures()) { mode = mode or ContactsCursorLoader.DisplayMode.FLAG_SMS } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt index 116cdfac9..27ff70892 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsViewModel.kt @@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.components.settings.conversation.preferences.L import org.thoughtcrime.securesms.database.AttachmentDatabase import org.thoughtcrime.securesms.database.RecipientDatabase import org.thoughtcrime.securesms.database.model.StoryViewState -import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.groups.LiveGroup import org.thoughtcrime.securesms.groups.v2.GroupAddMembersResult @@ -26,7 +25,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.recipients.RecipientUtil import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.SingleLiveEvent -import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.livedata.LiveDataUtil import org.thoughtcrime.securesms.util.livedata.Store import java.util.Optional @@ -141,7 +139,7 @@ sealed class ConversationSettingsViewModel( } store.update(liveRecipient.liveData) { recipient, state -> - val isAudioAvailable = (recipient.isRegistered || (Util.isDefaultSmsProvider(ApplicationDependencies.getApplication()) && SignalStore.misc().smsExportPhase.isSmsSupported())) && + val isAudioAvailable = (recipient.isRegistered || SignalStore.misc().smsExportPhase.allowSmsFeatures()) && !recipient.isGroup && !recipient.isBlocked && !recipient.isSelf && diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index d09b7f964..1ec3b1dc6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -929,7 +929,7 @@ public class ConversationParentFragment extends Fragment if (isSingleConversation()) { if (viewModel.isPushAvailable()) { inflater.inflate(R.menu.conversation_callable_secure, menu); - } else if (!recipient.get().isReleaseNotes() && Util.isDefaultSmsProvider(requireContext()) && SignalStore.misc().getSmsExportPhase().isSmsSupported()) { + } else if (!recipient.get().isReleaseNotes() && SignalStore.misc().getSmsExportPhase().allowSmsFeatures()) { inflater.inflate(R.menu.conversation_callable_insecure, menu); } } else if (isGroupConversation()) { @@ -2742,7 +2742,14 @@ public class ConversationParentFragment extends Fragment TextView message = smsExportStub.get().findViewById(R.id.export_sms_message); MaterialButton actionButton = smsExportStub.get().findViewById(R.id.export_sms_button); boolean isPhase1 = SignalStore.misc().getSmsExportPhase() == SmsExportPhase.PHASE_1; - if (conversationSecurityInfo.getHasUnexportedInsecureMessages()) { + + if (SignalStore.misc().getSmsExportPhase() == SmsExportPhase.PHASE_0) { + message.setText(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, recipient.getDisplayName(requireContext()))); + actionButton.setText(R.string.conversation_activity__enable_signal_for_sms); + actionButton.setOnClickListener(v -> { + handleMakeDefaultSms(); + }); + } else if (conversationSecurityInfo.getHasUnexportedInsecureMessages()) { message.setText(isPhase1 ? R.string.ConversationActivity__sms_messaging_is_currently_disabled_you_can_export_your_messages_to_another_app_on_your_phone : R.string.ConversationActivity__sms_messaging_is_no_longer_supported_in_signal_you_can_export_your_messages_to_another_app_on_your_phone); actionButton.setText(R.string.ConversationActivity__export_sms_messages); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java index ec389890f..7d9723660 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java @@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.database.DatabaseObserver; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.StoryViewState; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.MediaRepository; import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile; @@ -443,7 +444,9 @@ public class ConversationViewModel extends ViewModel { } public void insertSmsExportUpdateEvent(@NonNull Recipient recipient) { - conversationRepository.insertSmsExportUpdateEvent(recipient); + if (SignalStore.misc().getSmsExportPhase().isAtLeastPhase1()) { + conversationRepository.insertSmsExportUpdateEvent(recipient); + } } enum Event { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageSendType.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageSendType.kt index 555541630..f4415ad43 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageSendType.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/MessageSendType.kt @@ -14,7 +14,6 @@ import org.thoughtcrime.securesms.util.CharacterCalculator import org.thoughtcrime.securesms.util.MmsCharacterCalculator import org.thoughtcrime.securesms.util.PushCharacterCalculator import org.thoughtcrime.securesms.util.SmsCharacterCalculator -import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat import org.thoughtcrime.securesms.util.dualsim.SubscriptionManagerCompat import java.lang.IllegalArgumentException @@ -140,7 +139,7 @@ sealed class MessageSendType( options += SignalMessageSendType - if (Util.isDefaultSmsProvider(context) && SignalStore.misc().smsExportPhase.isSmsSupported()) { + if (SignalStore.misc().smsExportPhase.allowSmsFeatures()) { try { val subscriptions: Collection = SubscriptionManagerCompat(context).activeAndReadySubscriptionInfos diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java index b433c4a3e..22c07d1f6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java @@ -51,7 +51,7 @@ public class CreateGroupActivity extends ContactSelectionActivity { intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false); intent.putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.create_group_activity); - boolean smsEnabled = Util.isDefaultSmsProvider(context) && SignalStore.misc().getSmsExportPhase().isSmsSupported(); + boolean smsEnabled = SignalStore.misc().getSmsExportPhase().allowSmsFeatures(); int displayMode = smsEnabled ? ContactsCursorLoader.DisplayMode.FLAG_SMS | ContactsCursorLoader.DisplayMode.FLAG_PUSH : ContactsCursorLoader.DisplayMode.FLAG_PUSH; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/details/AddGroupDetailsFragment.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/details/AddGroupDetailsFragment.java index 6a78ae19a..273a7689f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/details/AddGroupDetailsFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/details/AddGroupDetailsFragment.java @@ -100,6 +100,7 @@ public class AddGroupDetailsFragment extends LoggingFragment { GroupMemberListView members = view.findViewById(R.id.member_list); ImageView avatar = view.findViewById(R.id.group_avatar); View mmsWarning = view.findViewById(R.id.mms_warning); + TextView mmsWarningText = view.findViewById(R.id.mms_warning_text); View addLater = view.findViewById(R.id.add_later); TextView disappearingMessageValue = view.findViewById(R.id.group_disappearing_messages_value); @@ -127,6 +128,8 @@ public class AddGroupDetailsFragment extends LoggingFragment { viewModel.getIsMms().observe(getViewLifecycleOwner(), isMms -> { disappearingMessagesRow.setVisibility(isMms ? View.GONE : View.VISIBLE); mmsWarning.setVisibility(isMms ? View.VISIBLE : View.GONE); + mmsWarningText.setText(SignalStore.misc().getSmsExportPhase().isAtLeastPhase1() ? R.string.AddGroupDetailsFragment__youve_selected_a_contact_that_doesnt_support_signal_groups_mms_removal + : R.string.AddGroupDetailsFragment__youve_selected_a_contact_that_doesnt_support); name.setHint(isMms ? R.string.AddGroupDetailsFragment__group_name_optional : R.string.AddGroupDetailsFragment__group_name_required); toolbar.setTitle(isMms ? R.string.AddGroupDetailsFragment__create_group : R.string.AddGroupDetailsFragment__name_this_group); }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java index b904ba17c..a41a65f37 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java @@ -26,7 +26,8 @@ public final class MiscellaneousValues extends SignalStoreValues { private static final String LAST_FCM_FOREGROUND_TIME = "misc.last_fcm_foreground_time"; private static final String LAST_FOREGROUND_TIME = "misc.last_foreground_time"; private static final String PNI_INITIALIZED_DEVICES = "misc.pni_initialized_devices"; - private static final String SMS_EXPORT_TIME = "misc.sms_export_time"; + private static final String SMS_PHASE_1_START_MS = "misc.sms_export.phase_1_start"; + private static final String STORIES_FEATURE_AVAILABLE_MS = "misc.stories_feature_available_ms"; MiscellaneousValues(@NonNull KeyValueStore store) { super(store); @@ -40,7 +41,8 @@ public final class MiscellaneousValues extends SignalStoreValues { @Override @NonNull List getKeysToIncludeInBackup() { return Arrays.asList( - SMS_EXPORT_TIME + SMS_PHASE_1_START_MS, + STORIES_FEATURE_AVAILABLE_MS ); } @@ -188,14 +190,26 @@ public final class MiscellaneousValues extends SignalStoreValues { putBoolean(PNI_INITIALIZED_DEVICES, value); } - public void setHasSeenSmsExportMegaphone() { - if (!getStore().containsKey(SMS_EXPORT_TIME)) { - putLong(SMS_EXPORT_TIME, System.currentTimeMillis()); + public void startSmsPhase1() { + if (!getStore().containsKey(SMS_PHASE_1_START_MS)) { + putLong(SMS_PHASE_1_START_MS, System.currentTimeMillis()); } } + public long getStoriesFeatureAvailableTimestamp() { + return getLong(STORIES_FEATURE_AVAILABLE_MS, 0); + } + + public void setStoriesFeatureAvailableTimestamp(long timestamp) { + putLong(STORIES_FEATURE_AVAILABLE_MS, timestamp); + } + public @NonNull SmsExportPhase getSmsExportPhase() { + if (getLong(SMS_PHASE_1_START_MS, 0) == 0) { + return SmsExportPhase.PHASE_0; + } + long now = System.currentTimeMillis(); - return SmsExportPhase.getCurrentPhase(now - getLong(SMS_EXPORT_TIME, now)); + return SmsExportPhase.getCurrentPhase(now - getLong(SMS_PHASE_1_START_MS, now)); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SmsExportPhase.kt b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SmsExportPhase.kt index bca6f13f8..84fd5971d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SmsExportPhase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SmsExportPhase.kt @@ -1,24 +1,35 @@ package org.thoughtcrime.securesms.keyvalue +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.util.Util import kotlin.time.Duration.Companion.days enum class SmsExportPhase(val duration: Long) { + PHASE_0(-1), PHASE_1(0.days.inWholeMilliseconds), PHASE_2(45.days.inWholeMilliseconds), PHASE_3(105.days.inWholeMilliseconds); + fun allowSmsFeatures(): Boolean { + return this == PHASE_0 || (Util.isDefaultSmsProvider(ApplicationDependencies.getApplication()) && SignalStore.misc().smsExportPhase.isSmsSupported()) + } + fun isSmsSupported(): Boolean { return this != PHASE_3 } fun isFullscreen(): Boolean { - return this != PHASE_1 + return this.ordinal > PHASE_1.ordinal } fun isBlockingUi(): Boolean { return this == PHASE_3 } + fun isAtLeastPhase1(): Boolean { + return this.ordinal >= PHASE_1.ordinal + } + companion object { @JvmStatic fun getCurrentPhase(duration: Long): SmsExportPhase { diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java index 9d1e8c01d..2c75a7d63 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java @@ -362,14 +362,16 @@ public final class Megaphones { private static @NonNull Megaphone buildSmsExportMegaphone(@NonNull Context context) { SmsExportPhase phase = SignalStore.misc().getSmsExportPhase(); - if (phase == SmsExportPhase.PHASE_1) { + if (phase == SmsExportPhase.PHASE_0) { + throw new AssertionError("Should not be showing megaphone for Phase 0"); + } else if (phase == SmsExportPhase.PHASE_1) { return new Megaphone.Builder(Event.SMS_EXPORT, Megaphone.Style.BASIC) .setTitle(R.string.SmsExportMegaphone__sms_support_going_away) .setImage(R.drawable.sms_megaphone) .setBody(R.string.SmsExportMegaphone__sms_support_will_be_removed_soon_to_focus_on_encrypted_messaging) .setActionButton(R.string.SmsExportMegaphone__export_sms, (megaphone, controller) -> controller.onMegaphoneNavigationRequested(SmsExportActivity.createIntent(context), SmsExportMegaphoneActivity.REQUEST_CODE)) .setSecondaryButton(R.string.Megaphones_remind_me_later, (megaphone, controller) -> controller.onMegaphoneSnooze(Event.SMS_EXPORT)) - .setOnVisibleListener((megaphone, controller) -> SignalStore.misc().setHasSeenSmsExportMegaphone()) + .setOnVisibleListener((megaphone, controller) -> SignalStore.misc().startSmsPhase1()) .build(); } else { Megaphone.Builder builder = new Megaphone.Builder(Event.SMS_EXPORT, Megaphone.Style.FULLSCREEN) diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule.kt b/app/src/main/java/org/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule.kt index f6c0da0b2..5aa3c06ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/SmsExportReminderSchedule.kt @@ -2,9 +2,9 @@ package org.thoughtcrime.securesms.megaphone import android.content.Context import androidx.annotation.WorkerThread -import org.thoughtcrime.securesms.database.SignalDatabase.Companion.mmsSms import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.SmsExportPhase +import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.Util import kotlin.time.Duration.Companion.days @@ -23,6 +23,7 @@ class SmsExportReminderSchedule(private val context: Context) : MegaphoneSchedul override fun shouldDisplay(seenCount: Int, lastSeen: Long, firstVisible: Long, currentTime: Long): Boolean { return if (shouldShowMegaphone()) { when (SignalStore.misc().smsExportPhase) { + SmsExportPhase.PHASE_0 -> false SmsExportPhase.PHASE_1 -> basicMegaphoneSchedule.shouldDisplay(seenCount, lastSeen, firstVisible, currentTime) SmsExportPhase.PHASE_2 -> fullScreenSchedule.shouldDisplay(seenCount, lastSeen, firstVisible, currentTime) SmsExportPhase.PHASE_3 -> showPhase3Megaphone @@ -32,8 +33,17 @@ class SmsExportReminderSchedule(private val context: Context) : MegaphoneSchedul } } + @Suppress("UsePropertyAccessSyntax") @WorkerThread fun shouldShowMegaphone(): Boolean { - return FeatureFlags.smsExporter() && (Util.isDefaultSmsProvider(context) || mmsSms.unexportedInsecureMessagesCount > 0) + return if (Stories.isFeatureFlagEnabled() && SignalStore.misc().storiesFeatureAvailableTimestamp == 0L) { + SignalStore.misc().storiesFeatureAvailableTimestamp = System.currentTimeMillis() + false + } else if (System.currentTimeMillis() > (SignalStore.misc().storiesFeatureAvailableTimestamp + FeatureFlags.smsExportMegaphoneDelayDays().days.inWholeMilliseconds)) { + SignalStore.misc().startSmsPhase1() + FeatureFlags.smsExporter() && Util.isDefaultSmsProvider(context) + } else { + false + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java index 476a105e6..be3ddd4b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java @@ -222,7 +222,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF unblockButton.setVisibility(View.GONE); } - boolean isAudioAvailable = (recipient.isRegistered() || (Util.isDefaultSmsProvider(requireContext()) && SignalStore.misc().getSmsExportPhase().isSmsSupported())) && + boolean isAudioAvailable = (recipient.isRegistered() || SignalStore.misc().getSmsExportPhase().allowSmsFeatures()) && !recipient.isGroup() && !recipient.isBlocked() && !recipient.isSelf() && diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index 31f22f746..5364b43e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -104,7 +104,8 @@ public final class FeatureFlags { private static final String CDS_V2_COMPAT = "android.cdsV2Compat.4"; public static final String STORIES_LOCALE = "android.stories.locale"; private static final String HIDE_CONTACTS = "android.hide.contacts"; - public static final String MEDIA_PREVIEW_V2 = "android.mediaPreviewV2"; + private static final String MEDIA_PREVIEW_V2 = "android.mediaPreviewV2"; + private static final String SMS_EXPORT_MEGAPHONE_DELAY_DAYS = "android.smsExport.megaphoneDelayDays"; /** * We will only store remote values for flags in this set. If you want a flag to be controllable @@ -161,7 +162,8 @@ public final class FeatureFlags { CDS_V2_COMPAT, STORIES_LOCALE, HIDE_CONTACTS, - MEDIA_PREVIEW_V2 + MEDIA_PREVIEW_V2, + SMS_EXPORT_MEGAPHONE_DELAY_DAYS ); @VisibleForTesting @@ -225,7 +227,8 @@ public final class FeatureFlags { CDS_V2_LOAD_TEST, CDS_V2_COMPAT, STORIES, - MEDIA_PREVIEW_V2 + MEDIA_PREVIEW_V2, + SMS_EXPORT_MEGAPHONE_DELAY_DAYS ); /** @@ -585,6 +588,13 @@ public final class FeatureFlags { return getBoolean(MEDIA_PREVIEW_V2, false); } + /** + * Number of days to postpone the sms export megaphone and Phase 1 start. + */ + public static int smsExportMegaphoneDelayDays() { + return getInteger(SMS_EXPORT_MEGAPHONE_DELAY_DAYS, 14); + } + /** Only for rendering debug info. */ public static synchronized @NonNull Map getMemoryValues() { return new TreeMap<>(REMOTE_VALUES); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/views/Stub.java b/app/src/main/java/org/thoughtcrime/securesms/util/views/Stub.java index dd20d35fa..9020423a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/views/Stub.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/views/Stub.java @@ -30,7 +30,7 @@ public class Stub { } public void setVisibility(int visibility) { - if (resolved()) { + if (resolved() || visibility == View.VISIBLE) { get().setVisibility(visibility); } } diff --git a/app/src/main/res/layout/add_group_details_fragment.xml b/app/src/main/res/layout/add_group_details_fragment.xml index b6dc6a0c0..e276f7334 100644 --- a/app/src/main/res/layout/add_group_details_fragment.xml +++ b/app/src/main/res/layout/add_group_details_fragment.xml @@ -104,6 +104,7 @@ tools:visibility="visible"> Remove SMS contact Remove %1$s from this group? - + + You\'ve selected a contact that doesn\'t support Signal groups, so this group will be MMS. Custom MMS group names and photos will only be visible to you. + You\'ve selected a contact that dosen\'t support Signal groups, this group will be MMS. Custom MMS group names and photos will only be visible to you. Support for MMS groups will be removed soon to focus on encrypted messaging.