diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a939785036..298775a112 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -523,6 +523,11 @@
+
+
diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
index fbb8a4e804..b1a13a1eb7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java
@@ -198,7 +198,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
public void checkBuildExpiration() {
if (Util.getTimeUntilBuildExpiry() <= 0 && !SignalStore.misc().isClientDeprecated()) {
Log.w(TAG, "Build expired!");
- SignalStore.misc().markDeprecated();
+ SignalStore.misc().markClientDeprecated();
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ExpiredBuildReminder.java b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ExpiredBuildReminder.java
index 5a3b911d8e..b5089cf4b5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ExpiredBuildReminder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ExpiredBuildReminder.java
@@ -2,16 +2,25 @@ package org.thoughtcrime.securesms.components.reminder;
import android.content.Context;
+import androidx.annotation.NonNull;
+
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.PlayStoreUtil;
+import java.util.List;
+
+/**
+ * Showed when a build has fully expired (either via the compile-time constant, or remote
+ * deprecation).
+ */
public class ExpiredBuildReminder extends Reminder {
public ExpiredBuildReminder(final Context context) {
- super(context.getString(R.string.reminder_header_expired_build),
- context.getString(R.string.reminder_header_expired_build_details));
+ super(null, context.getString(R.string.ExpiredBuildReminder_this_version_of_signal_has_expired));
+
setOkListener(v -> PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(context));
+ addAction(new Action(context.getString(R.string.ExpiredBuildReminder_update_now), R.id.reminder_action_update_now));
}
@Override
@@ -19,8 +28,17 @@ public class ExpiredBuildReminder extends Reminder {
return false;
}
+ @Override
+ public List getActions() {
+ return super.getActions();
+ }
+
+ @Override
+ public @NonNull Importance getImportance() {
+ return Importance.TERMINAL;
+ }
+
public static boolean isEligible() {
return SignalStore.misc().isClientDeprecated();
}
-
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/OutdatedBuildReminder.java b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/OutdatedBuildReminder.java
index 3bcbecb5a5..93d4853d45 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/OutdatedBuildReminder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/OutdatedBuildReminder.java
@@ -8,20 +8,22 @@ import org.thoughtcrime.securesms.util.Util;
import java.util.concurrent.TimeUnit;
+/**
+ * Reminder that is shown when a build is getting close to expiry (either because of the
+ * compile-time constant, or remote deprecation).
+ */
public class OutdatedBuildReminder extends Reminder {
public OutdatedBuildReminder(final Context context) {
- super(context.getString(R.string.reminder_header_outdated_build),
- getPluralsText(context));
+ super(null, getPluralsText(context));
+
setOkListener(v -> PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(context));
+ addAction(new Action(context.getString(R.string.OutdatedBuildReminder_update_now), R.id.reminder_action_update_now));
}
private static CharSequence getPluralsText(final Context context) {
int days = getDaysUntilExpiry() - 1;
- if (days == 0) {
- return context.getString(R.string.reminder_header_outdated_build_details_today);
- }
- return context.getResources().getQuantityString(R.plurals.reminder_header_outdated_build_details, days, days);
+ return context.getResources().getQuantityString(R.plurals.OutdatedBuildReminder_your_version_of_signal_will_expire_in_n_days, days, days);
}
@Override
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/Reminder.java b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/Reminder.java
index 109d9f4497..df3c946fcf 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/Reminder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/Reminder.java
@@ -58,7 +58,7 @@ public abstract class Reminder {
return Importance.NORMAL;
}
- public void addAction(@NonNull Action action) {
+ protected void addAction(@NonNull Action action) {
actions.add(action);
}
@@ -71,7 +71,7 @@ public abstract class Reminder {
}
public enum Importance {
- NORMAL, ERROR
+ NORMAL, ERROR, TERMINAL
}
public final class Action {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ReminderView.java b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ReminderView.java
index 2ea65728d8..a87d499854 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ReminderView.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/ReminderView.java
@@ -1,8 +1,6 @@
package org.thoughtcrime.securesms.components.reminder;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build.VERSION_CODES;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -19,7 +17,6 @@ import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.List;
@@ -48,7 +45,6 @@ public final class ReminderView extends FrameLayout {
initialize();
}
- @TargetApi(VERSION_CODES.HONEYCOMB)
public ReminderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
@@ -56,14 +52,14 @@ public final class ReminderView extends FrameLayout {
private void initialize() {
LayoutInflater.from(getContext()).inflate(R.layout.reminder_header, this, true);
- progressBar = ViewUtil.findById(this, R.id.reminder_progress);
- progressText = ViewUtil.findById(this, R.id.reminder_progress_text);
- container = ViewUtil.findById(this, R.id.container);
- closeButton = ViewUtil.findById(this, R.id.cancel);
- title = ViewUtil.findById(this, R.id.reminder_title);
- text = ViewUtil.findById(this, R.id.reminder_text);
- space = ViewUtil.findById(this, R.id.reminder_space);
- actionsRecycler = ViewUtil.findById(this, R.id.reminder_actions);
+ progressBar = findViewById(R.id.reminder_progress);
+ progressText = findViewById(R.id.reminder_progress_text);
+ container = findViewById(R.id.container);
+ closeButton = findViewById(R.id.cancel);
+ title = findViewById(R.id.reminder_title);
+ text = findViewById(R.id.reminder_text);
+ space = findViewById(R.id.reminder_space);
+ actionsRecycler = findViewById(R.id.reminder_actions);
}
public void showReminder(final Reminder reminder) {
@@ -76,9 +72,26 @@ public final class ReminderView extends FrameLayout {
title.setVisibility(GONE);
space.setVisibility(VISIBLE);
}
+
+ if (!reminder.isDismissable()) {
+ space.setVisibility(GONE);
+ }
+
text.setText(reminder.getText());
- container.setBackgroundResource(reminder.getImportance() == Reminder.Importance.ERROR ? R.drawable.reminder_background_error
- : R.drawable.reminder_background_normal);
+
+ switch (reminder.getImportance()) {
+ case NORMAL:
+ container.setBackgroundResource(R.drawable.reminder_background_normal);
+ break;
+ case ERROR:
+ container.setBackgroundResource(R.drawable.reminder_background_error);
+ break;
+ case TERMINAL:
+ container.setBackgroundResource(R.drawable.reminder_background_terminal);
+ break;
+ default:
+ throw new IllegalStateException();
+ }
setOnClickListener(reminder.getOkListener());
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java
index b33b619edd..f59a7aa03a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java
@@ -240,6 +240,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.MessageUtil;
+import org.thoughtcrime.securesms.util.PlayStoreUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.TextSecurePreferences.MediaKeyboardMode;
@@ -1685,6 +1686,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
reminderView.get().showReminder(new UnauthorizedReminder(this));
} else if (ExpiredBuildReminder.isEligible()) {
reminderView.get().showReminder(new ExpiredBuildReminder(this));
+ reminderView.get().setOnActionClickListener(this::handleReminderAction);
} else if (ServiceOutageReminder.isEligible(this)) {
ApplicationDependencies.getJobManager().add(new ServiceOutageDetectionJob());
reminderView.get().showReminder(new ServiceOutageReminder(this));
@@ -1710,6 +1712,9 @@ public class ConversationActivity extends PassphraseRequiredActivity
case R.id.reminder_action_view_insights:
InsightsLauncher.showInsightsDashboard(getSupportFragmentManager());
break;
+ case R.id.reminder_action_update_now:
+ PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(this);
+ break;
default:
throw new IllegalArgumentException("Unknown ID: " + reminderActionId);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java
index e8021604f5..b200b30557 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java
@@ -56,6 +56,7 @@ import androidx.appcompat.widget.TooltipCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.view.ViewCompat;
import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.lifecycle.ViewModelProviders;
@@ -117,6 +118,7 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.AvatarUtil;
+import org.thoughtcrime.securesms.util.PlayStoreUtil;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.SnapToTopDataObserver;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
@@ -176,6 +178,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
private ViewGroup megaphoneContainer;
private SnapToTopDataObserver snapToTopDataObserver;
private Drawable archiveDrawable;
+ private LifecycleObserver visibilityLifecycleObserver;
public static ConversationListFragment newInstance() {
return new ConversationListFragment();
@@ -214,6 +217,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
cameraFab.show();
reminderView.setOnDismissListener(this::updateReminders);
+ reminderView.setOnActionClickListener(this::onReminderAction);
list.setLayoutManager(new LinearLayoutManager(requireActivity()));
list.setItemAnimator(new DeleteItemAnimator());
@@ -272,6 +276,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
public void onStart() {
super.onStart();
ConversationFragment.prepare(requireContext());
+ ProcessLifecycleOwner.get().getLifecycle().addObserver(visibilityLifecycleObserver);
}
@Override
@@ -283,6 +288,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
EventBus.getDefault().unregister(this);
}
+ @Override
+ public void onStop() {
+ super.onStop();
+ ProcessLifecycleOwner.get().getLifecycle().removeObserver(visibilityLifecycleObserver);
+ }
+
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
@@ -412,6 +423,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
viewModel.onMegaphoneCompleted(event);
}
+ private void onReminderAction(@IdRes int reminderActionId) {
+ if (reminderActionId == R.id.reminder_action_update_now) {
+ PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
+ }
+ }
+
private void hideKeyboard() {
InputMethodManager imm = ServiceUtil.getInputMethodManager(requireContext());
imm.hideSoftInputFromWindow(requireView().getWindowToken(), 0);
@@ -508,12 +525,12 @@ public class ConversationListFragment extends MainFragment implements ActionMode
viewModel.getConversationList().observe(getViewLifecycleOwner(), this::onSubmitList);
viewModel.hasNoConversations().observe(getViewLifecycleOwner(), this::updateEmptyState);
- ProcessLifecycleOwner.get().getLifecycle().addObserver(new DefaultLifecycleObserver() {
+ visibilityLifecycleObserver = new DefaultLifecycleObserver() {
@Override
public void onStart(@NonNull LifecycleOwner owner) {
viewModel.onVisible();
}
- });
+ };
}
private void onSearchResultChanged(@Nullable SearchResult result) {
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 975a114ada..1a49d01f62 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java
@@ -51,7 +51,11 @@ public final class MiscellaneousValues extends SignalStoreValues {
return getBoolean(CLIENT_DEPRECATED, false);
}
- public void markDeprecated() {
+ public void markClientDeprecated() {
putBoolean(CLIENT_DEPRECATED, true);
}
+
+ public void clearClientDeprecated() {
+ putBoolean(CLIENT_DEPRECATED, false);
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/ClientDeprecatedActivity.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/ClientDeprecatedActivity.java
new file mode 100644
index 0000000000..7ab4bd66d5
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/ClientDeprecatedActivity.java
@@ -0,0 +1,62 @@
+package org.thoughtcrime.securesms.megaphone;
+
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+
+import org.thoughtcrime.securesms.PassphraseRequiredActivity;
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
+import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
+import org.thoughtcrime.securesms.util.DynamicTheme;
+import org.thoughtcrime.securesms.util.PlayStoreUtil;
+import org.thoughtcrime.securesms.util.Util;
+
+/**
+ * Shown when a users build fully expires. Controlled by {@link Megaphones.Event#CLIENT_DEPRECATED}.
+ */
+public class ClientDeprecatedActivity extends PassphraseRequiredActivity {
+
+ private final DynamicTheme theme = new DynamicNoActionBarTheme();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState, boolean ready) {
+ setContentView(R.layout.client_deprecated_activity);
+
+ findViewById(R.id.client_deprecated_update_button).setOnClickListener(v -> onUpdateClicked());
+ findViewById(R.id.client_deprecated_dont_update_button).setOnClickListener(v -> onDontUpdateClicked());
+ }
+
+ @Override
+ protected void onPreCreate() {
+ theme.onCreate(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ theme.onResume(this);
+ }
+
+ @Override
+ public void onBackPressed() {
+ // Disabled
+ }
+
+ private void onUpdateClicked() {
+ PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(this);
+ }
+
+ private void onDontUpdateClicked() {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.ClientDeprecatedActivity_warning)
+ .setMessage(R.string.ClientDeprecatedActivity_your_version_of_signal_has_expired_you_can_view_your_message_history)
+ .setPositiveButton(R.string.ClientDeprecatedActivity_dont_update, (dialog, which) -> {
+ ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.CLIENT_DEPRECATED, () -> {
+ Util.runOnMain(this::finish);
+ });
+ })
+ .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss())
+ .show();
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java
index 1b6094229a..a001cb3e36 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphone.java
@@ -20,7 +20,7 @@ public class Megaphone {
private final Event event;
private final Style style;
- private final boolean mandatory;
+ private final Priority priority;
private final boolean canSnooze;
private final int titleRes;
private final int bodyRes;
@@ -33,7 +33,7 @@ public class Megaphone {
private Megaphone(@NonNull Builder builder) {
this.event = builder.event;
this.style = builder.style;
- this.mandatory = builder.mandatory;
+ this.priority = builder.priority;
this.canSnooze = builder.canSnooze;
this.titleRes = builder.titleRes;
this.bodyRes = builder.bodyRes;
@@ -48,8 +48,8 @@ public class Megaphone {
return event;
}
- public boolean isMandatory() {
- return mandatory;
+ public @NonNull Priority getPriority() {
+ return priority;
}
public boolean canSnooze() {
@@ -97,7 +97,7 @@ public class Megaphone {
private final Event event;
private final Style style;
- private boolean mandatory;
+ private Priority priority;
private boolean canSnooze;
private int titleRes;
private int bodyRes;
@@ -111,13 +111,14 @@ public class Megaphone {
public Builder(@NonNull Event event, @NonNull Style style) {
this.event = event;
this.style = style;
+ this.priority = Priority.DEFAULT;
}
/**
* Prioritizes this megaphone over others that do not set this flag.
*/
- public @NonNull Builder setMandatory(boolean mandatory) {
- this.mandatory = mandatory;
+ public @NonNull Builder setPriority(@NonNull Priority priority) {
+ this.priority = priority;
return this;
}
@@ -192,6 +193,20 @@ public class Megaphone {
POPUP
}
+ enum Priority {
+ DEFAULT(0), HIGH(1), CLIENT_EXPIRATION(1000);
+
+ int priorityValue;
+
+ Priority(int priorityValue) {
+ this.priorityValue = priorityValue;
+ }
+
+ public int getPriorityValue() {
+ return priorityValue;
+ }
+ }
+
public interface EventListener {
void onEvent(@NonNull Megaphone megaphone, @NonNull MegaphoneActionController listener);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java
index 95ff61eba0..a0d4c73c8a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java
@@ -5,6 +5,7 @@ import android.content.Context;
import androidx.annotation.AnyThread;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.annimon.stream.Collectors;
@@ -100,6 +101,11 @@ public class MegaphoneRepository {
@AnyThread
public void markFinished(@NonNull Event event) {
+ markFinished(event, null);
+ }
+
+ @AnyThread
+ public void markFinished(@NonNull Event event, @Nullable Runnable onComplete) {
executor.execute(() -> {
MegaphoneRecord record = databaseCache.get(event);
if (record != null && record.isFinished()) {
@@ -108,6 +114,10 @@ public class MegaphoneRepository {
database.markFinished(event);
resetDatabaseCache();
+
+ if (onComplete != null) {
+ onComplete.run();
+ }
});
}
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 0721ae3b08..4f5766a62c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java
@@ -34,12 +34,12 @@ import java.util.Objects;
* Creating a new megaphone:
* - Add an enum to {@link Event}
* - Return a megaphone in {@link #forRecord(Context, MegaphoneRecord)}
- * - Include the event in {@link #buildDisplayOrder()}
+ * - Include the event in {@link #buildDisplayOrder(Context)}
*
* Common patterns:
* - For events that have a snooze-able recurring display schedule, use a {@link RecurringSchedule}.
* - For events guarded by feature flags, set a {@link ForeverSchedule} with false in
- * {@link #buildDisplayOrder()}.
+ * {@link #buildDisplayOrder(Context)}.
* - For events that change, return different megaphones in {@link #forRecord(Context, MegaphoneRecord)}
* based on whatever properties you're interested in.
*/
@@ -65,15 +65,9 @@ public final class Megaphones {
.map(Map.Entry::getKey)
.map(records::get)
.map(record -> Megaphones.forRecord(context, record))
+ .sortBy(m -> -m.getPriority().getPriorityValue())
.toList();
- boolean hasOptional = Stream.of(megaphones).anyMatch(m -> !m.isMandatory());
- boolean hasMandatory = Stream.of(megaphones).anyMatch(Megaphone::isMandatory);
-
- if (hasOptional && hasMandatory) {
- megaphones = Stream.of(megaphones).filter(Megaphone::isMandatory).toList();
- }
-
if (megaphones.size() > 0) {
return megaphones.get(0);
} else {
@@ -93,6 +87,7 @@ public final class Megaphones {
put(Event.MESSAGE_REQUESTS, shouldShowMessageRequestsMegaphone() ? ALWAYS : NEVER);
put(Event.MENTIONS, shouldShowMentionsMegaphone() ? ALWAYS : NEVER);
put(Event.LINK_PREVIEWS, shouldShowLinkPreviewsMegaphone(context) ? ALWAYS : NEVER);
+ put(Event.CLIENT_DEPRECATED, SignalStore.misc().isClientDeprecated() ? ALWAYS : NEVER);
}};
}
@@ -110,6 +105,8 @@ public final class Megaphones {
return buildMentionsMegaphone();
case LINK_PREVIEWS:
return buildLinkPreviewsMegaphone();
+ case CLIENT_DEPRECATED:
+ return buildClientDeprecatedMegaphone(context);
default:
throw new IllegalArgumentException("Event not handled!");
}
@@ -117,14 +114,14 @@ public final class Megaphones {
private static @NonNull Megaphone buildReactionsMegaphone() {
return new Megaphone.Builder(Event.REACTIONS, Megaphone.Style.REACTIONS)
- .setMandatory(false)
+ .setPriority(Megaphone.Priority.DEFAULT)
.build();
}
private static @NonNull Megaphone buildPinsForAllMegaphone(@NonNull MegaphoneRecord record) {
if (PinsForAllSchedule.shouldDisplayFullScreen(record.getFirstVisible(), System.currentTimeMillis())) {
return new Megaphone.Builder(Event.PINS_FOR_ALL, Megaphone.Style.FULLSCREEN)
- .setMandatory(true)
+ .setPriority(Megaphone.Priority.HIGH)
.enableSnooze(null)
.setOnVisibleListener((megaphone, listener) -> {
if (new NetworkConstraint.Factory(ApplicationDependencies.getApplication()).create().isMet()) {
@@ -134,7 +131,7 @@ public final class Megaphones {
.build();
} else {
return new Megaphone.Builder(Event.PINS_FOR_ALL, Megaphone.Style.BASIC)
- .setMandatory(true)
+ .setPriority(Megaphone.Priority.HIGH)
.setImage(R.drawable.kbs_pin_megaphone)
.setTitle(R.string.KbsMegaphone__create_a_pin)
.setBody(R.string.KbsMegaphone__pins_keep_information_thats_stored_with_signal_encrytped)
@@ -184,7 +181,7 @@ public final class Megaphones {
private static @NonNull Megaphone buildMessageRequestsMegaphone(@NonNull Context context) {
return new Megaphone.Builder(Event.MESSAGE_REQUESTS, Megaphone.Style.FULLSCREEN)
.disableSnooze()
- .setMandatory(true)
+ .setPriority(Megaphone.Priority.HIGH)
.setOnVisibleListener(((megaphone, listener) -> {
listener.onMegaphoneNavigationRequested(new Intent(context, MessageRequestMegaphoneActivity.class),
ConversationListFragment.MESSAGE_REQUESTS_REQUEST_CODE_CREATE_NAME);
@@ -202,7 +199,17 @@ public final class Megaphones {
private static @NonNull Megaphone buildLinkPreviewsMegaphone() {
return new Megaphone.Builder(Event.LINK_PREVIEWS, Megaphone.Style.LINK_PREVIEWS)
- .setMandatory(true)
+ .setPriority(Megaphone.Priority.HIGH)
+ .build();
+ }
+
+ private static @NonNull Megaphone buildClientDeprecatedMegaphone(@NonNull Context context) {
+ return new Megaphone.Builder(Event.CLIENT_DEPRECATED, Megaphone.Style.FULLSCREEN)
+ .disableSnooze()
+ .setPriority(Megaphone.Priority.HIGH)
+ .setOnVisibleListener((megaphone, listener) -> {
+ listener.onMegaphoneNavigationRequested(new Intent(context, ClientDeprecatedActivity.class));
+ })
.build();
}
@@ -224,7 +231,8 @@ public final class Megaphones {
PIN_REMINDER("pin_reminder"),
MESSAGE_REQUESTS("message_requests"),
MENTIONS("mentions"),
- LINK_PREVIEWS("link_previews");
+ LINK_PREVIEWS("link_previews"),
+ CLIENT_DEPRECATED("client_deprecated");
private final String key;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java
index 47df39184c..5f8ab87036 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java
@@ -75,6 +75,7 @@ public class ApplicationMigrations {
if (!isUpdate(context)) {
Log.d(TAG, "Not an update. Skipping.");
+ VersionTracker.updateLastSeenVersion(context);
return;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/RemoteDeprecationDetectorInterceptor.java b/app/src/main/java/org/thoughtcrime/securesms/net/RemoteDeprecationDetectorInterceptor.java
index 80258eb819..ff5b542ba5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/net/RemoteDeprecationDetectorInterceptor.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/net/RemoteDeprecationDetectorInterceptor.java
@@ -23,7 +23,7 @@ public final class RemoteDeprecationDetectorInterceptor implements Interceptor {
if (response.code() == 499 && !SignalStore.misc().isClientDeprecated()) {
Log.w(TAG, "Received 499. Client version is deprecated.");
- SignalStore.misc().markDeprecated();
+ SignalStore.misc().markClientDeprecated();
}
return response;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/VersionTracker.java b/app/src/main/java/org/thoughtcrime/securesms/util/VersionTracker.java
index 4c9a6ba97a..e94710c021 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/VersionTracker.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/VersionTracker.java
@@ -3,10 +3,15 @@ package org.thoughtcrime.securesms.util;
import android.content.Context;
import androidx.annotation.NonNull;
+import org.thoughtcrime.securesms.keyvalue.SignalStore;
+import org.thoughtcrime.securesms.logging.Log;
+
import java.io.IOException;
public class VersionTracker {
+ private static final String TAG = Log.tag(VersionTracker.class);
+
public static int getLastSeenVersion(@NonNull Context context) {
return TextSecurePreferences.getLastVersionCode(context);
}
@@ -14,7 +19,13 @@ public class VersionTracker {
public static void updateLastSeenVersion(@NonNull Context context) {
try {
int currentVersionCode = Util.getCanonicalVersionCode();
- TextSecurePreferences.setLastVersionCode(context, currentVersionCode);
+ int lastVersionCode = TextSecurePreferences.getLastVersionCode(context);
+
+ if (currentVersionCode != lastVersionCode) {
+ Log.i(TAG, "Upgraded from " + lastVersionCode + " to " + currentVersionCode);
+ SignalStore.misc().clearClientDeprecated();
+ TextSecurePreferences.setLastVersionCode(context, currentVersionCode);
+ }
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
diff --git a/app/src/main/res/drawable/ic_signal_logo_large.xml b/app/src/main/res/drawable/ic_signal_logo_large.xml
new file mode 100644
index 0000000000..cab7595e13
--- /dev/null
+++ b/app/src/main/res/drawable/ic_signal_logo_large.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/reminder_background_terminal.xml b/app/src/main/res/drawable/reminder_background_terminal.xml
new file mode 100644
index 0000000000..795dc3c25c
--- /dev/null
+++ b/app/src/main/res/drawable/reminder_background_terminal.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/client_deprecated_activity.xml b/app/src/main/res/layout/client_deprecated_activity.xml
new file mode 100644
index 0000000000..31dbbba4f0
--- /dev/null
+++ b/app/src/main/res/layout/client_deprecated_activity.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/reminder_action_button.xml b/app/src/main/res/layout/reminder_action_button.xml
index 9b66c0842b..953dd6df7d 100644
--- a/app/src/main/res/layout/reminder_action_button.xml
+++ b/app/src/main/res/layout/reminder_action_button.xml
@@ -5,7 +5,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="@color/white"
- android:textSize="16sp"
+ android:textSize="14sp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginStart="3dp"
diff --git a/app/src/main/res/layout/reminder_header.xml b/app/src/main/res/layout/reminder_header.xml
index cccf1d052d..ee09af735a 100644
--- a/app/src/main/res/layout/reminder_header.xml
+++ b/app/src/main/res/layout/reminder_header.xml
@@ -44,12 +44,12 @@
android:id="@+id/reminder_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="12dp"
- android:layout_marginTop="14dp"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="20dp"
android:layout_marginBottom="6dp"
android:textColor="@color/white"
android:textSize="20sp"
- android:textStyle="bold"
+ android:fontFamily="sans-serif-medium"
app:layout_constraintBottom_toTopOf="@id/reminder_text"
app:layout_constraintStart_toEndOf="@id/reminder_progress"
app:layout_constraintTop_toTopOf="parent"
@@ -62,17 +62,17 @@
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
+ style="@style/Signal.Text.Preview"
android:textColor="@color/white"
- android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@id/reminder_actions"
app:layout_constraintEnd_toStartOf="@id/reminder_space"
app:layout_constraintStart_toEndOf="@id/reminder_progress"
app:layout_constraintTop_toBottomOf="@id/reminder_title"
- app:layout_goneMarginBottom="12dp"
+ app:layout_goneMarginBottom="16dp"
app:layout_goneMarginEnd="16dp"
app:layout_goneMarginStart="16dp"
- app:layout_goneMarginTop="15dp"
- tools:text="Take your conversation with Jules Bonnot to the next level." />
+ app:layout_goneMarginTop="16dp"
+ tools:text="Take your conversation with Otto Octavius to the next level." />
+
+
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index ebcc8de541..41e5186a12 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -6,4 +6,5 @@
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5a3e52e917..7b13706285 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -151,6 +151,14 @@
Remove profile photo?
Remove group photo?
+
+ Update Signal
+ This version of the app is no longer supported. To continue sending and receiving messages, update to the latest version.
+ Update
+ Don\'t Update
+ Warning
+ Your version of Signal has expired. You can view your message history but you won\'t be able to send or receive messages until you update.
+
No web browser found.
No email app found.
@@ -428,6 +436,10 @@
Optimize for missing Play Services
This device does not support Play Services. Tap to disable system battery optimizations that prevent Signal from retrieving messages while inactive.
+
+ This version of Signal has expired. Update now to send and receive messages.
+ Update now
+
Share with
Multiple attachments are only supported for images and videos
@@ -1087,6 +1099,14 @@
Your messages will not expire.
Messages sent and received in this conversation will disappear %s after they have been seen.
+
+ Update now
+
+ - This version of Signal will expire today. Update to the most recent version.
+ - This version of Signal will expire tomorrow. Update to the most recent version.
+ - This version of Signal will expire in %d days. Update to the most recent version.
+
+
Enter passphrase
Signal icon
@@ -2289,14 +2309,6 @@
Compare with clipboard
- Your version of Signal is outdated
-
- - Your version of Signal will expire in %d day. Tap to update to the most recent version.
- - Your version of Signal will expire in %d days. Tap to update to the most recent version.
-
- Your version of Signal will expire today. Tap to update to the most recent version.
- Your version of Signal has expired!
- Messages will no longer send successfully. Tap to update to the most recent version.
Use as default SMS app
Tap to make Signal your default SMS app.
Import system SMS
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 06bb62c5ed..7ecc36a617 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -262,6 +262,10 @@
- ?attr/colorAccent
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 726a938c22..ec7f07019a 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -266,6 +266,8 @@
- @color/transparent_white_90
- @color/core_grey_20
+ - @color/core_grey_70
+
- @color/core_white
- @color/core_grey_05
@@ -648,6 +650,8 @@
- @drawable/scroll_to_bottom_background_dark
- @color/core_white
+ - @color/core_grey_50
+
- @color/core_grey_90
- @color/core_white