diff --git a/res/values/strings.xml b/res/values/strings.xml
index 223afe0f62..9834706517 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -279,6 +279,13 @@
Submit passphrase
Invalid passphrase!
+
+ Rate this app
+ If you enjoy using this app, please take a moment to help us by rating it.
+ Rate now!
+ No thanks
+ Later
+
The
signature on this key exchange is different than what you\'ve previously received from this
diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java
index 44f23dcca9..861cc7c4ff 100644
--- a/src/org/thoughtcrime/securesms/ConversationListActivity.java
+++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java
@@ -30,6 +30,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import org.thoughtcrime.securesms.components.RatingManager;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
@@ -69,6 +70,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
initializeContactUpdatesReceiver();
DirectoryRefreshListener.schedule(this);
+ RatingManager.showRatingDialogIfNecessary(this);
}
@Override
diff --git a/src/org/thoughtcrime/securesms/components/RatingManager.java b/src/org/thoughtcrime/securesms/components/RatingManager.java
new file mode 100644
index 0000000000..e359ef2dbc
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/components/RatingManager.java
@@ -0,0 +1,85 @@
+package org.thoughtcrime.securesms.components;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.util.Log;
+
+import com.afollestad.materialdialogs.MaterialDialog;
+
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
+
+import java.util.concurrent.TimeUnit;
+
+public class RatingManager {
+
+ private static final int DAYS_SINCE_INSTALL_THRESHOLD = 7;
+ private static final int DAYS_UNTIL_REPROMPT_THRESHOLD = 4;
+
+ private static final String TAG = RatingManager.class.getSimpleName();
+
+ public static void showRatingDialogIfNecessary(Context context) {
+ if (!TextSecurePreferences.isRatingEnabled(context)) return;
+
+ long daysSinceInstall = getDaysSinceInstalled(context);
+ long laterTimestamp = TextSecurePreferences.getRatingLaterTimestamp(context);
+
+ if (daysSinceInstall >= DAYS_SINCE_INSTALL_THRESHOLD &&
+ System.currentTimeMillis() >= laterTimestamp)
+ {
+ showRatingDialog(context);
+ }
+ }
+
+ private static void showRatingDialog(final Context context) {
+ new MaterialDialog.Builder(context)
+ .title(context.getString(R.string.RatingManager_rate_this_app))
+ .content(context.getString(R.string.RatingManager_if_you_enjoy_using_this_app_please_take_a_moment))
+ .positiveText(context.getString(R.string.RatingManager_rate_now))
+ .negativeText(context.getString(R.string.RatingManager_no_thanks))
+ .neutralText(context.getString(R.string.RatingManager_later))
+ .callback(new MaterialDialog.ButtonCallback() {
+ @Override
+ public void onPositive(MaterialDialog dialog) {
+ TextSecurePreferences.setRatingEnabled(context, false);
+ startPlayStore(context);
+ super.onPositive(dialog);
+ }
+
+ @Override
+ public void onNegative(MaterialDialog dialog) {
+ TextSecurePreferences.setRatingEnabled(context, false);
+ super.onNegative(dialog);
+ }
+
+ @Override
+ public void onNeutral(MaterialDialog dialog) {
+ long waitUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(DAYS_UNTIL_REPROMPT_THRESHOLD);
+ TextSecurePreferences.setRatingLaterTimestamp(context, waitUntil);
+ super.onNeutral(dialog);
+ }
+ })
+ .show();
+ }
+
+ private static void startPlayStore(Context context) {
+ Uri uri = Uri.parse("market://details?id=" + context.getPackageName());
+ context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ }
+
+ private static long getDaysSinceInstalled(Context context) {
+ try {
+ long installTimestamp = context.getPackageManager()
+ .getPackageInfo(context.getPackageName(), 0)
+ .firstInstallTime;
+
+ return TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - installTimestamp);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, e);
+ return 0;
+ }
+ }
+
+}
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index 1ae209bf6b..31cf71475a 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -66,9 +66,27 @@ public class TextSecurePreferences {
private static final String GCM_REGISTRATION_ID_PREF = "pref_gcm_registration_id";
private static final String GCM_REGISTRATION_ID_VERSION_PREF = "pref_gcm_registration_id_version";
private static final String WEBSOCKET_REGISTERED_PREF = "pref_websocket_registered";
+ private static final String RATING_LATER_PREF = "pref_rating_later";
+ private static final String RATING_ENABLED_PREF = "pref_rating_enabled";
public static final String REPEAT_ALERTS_PREF = "pref_repeat_alerts";
+ public static long getRatingLaterTimestamp(Context context) {
+ return getLongPreference(context, RATING_LATER_PREF, 0);
+ }
+
+ public static void setRatingLaterTimestamp(Context context, long timestamp) {
+ setLongPreference(context, RATING_LATER_PREF, timestamp);
+ }
+
+ public static boolean isRatingEnabled(Context context) {
+ return getBooleanPreference(context, RATING_ENABLED_PREF, true);
+ }
+
+ public static void setRatingEnabled(Context context, boolean enabled) {
+ setBooleanPreference(context, RATING_ENABLED_PREF, enabled);
+ }
+
public static boolean isWebsocketRegistered(Context context) {
return getBooleanPreference(context, WEBSOCKET_REGISTERED_PREF, false);
}