Prompt user to rate app

Closes #2841

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2015-03-31 12:34:49 -07:00
parent 0c7dba6d43
commit 0efdada928
4 changed files with 112 additions and 0 deletions

View File

@ -279,6 +279,13 @@
<string name="PassphrasePromptActivity_ok_button_content_description">Submit passphrase</string>
<string name="PassphrasePromptActivity_invalid_passphrase_exclamation">Invalid passphrase!</string>
<!-- RatingManager -->
<string name="RatingManager_rate_this_app">Rate this app</string>
<string name="RatingManager_if_you_enjoy_using_this_app_please_take_a_moment">If you enjoy using this app, please take a moment to help us by rating it.</string>
<string name="RatingManager_rate_now">Rate now!</string>
<string name="RatingManager_no_thanks">No thanks</string>
<string name="RatingManager_later">Later</string>
<!-- ReceiveKeyActivity -->
<string name="ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different">The
signature on this key exchange is different than what you\'ve previously received from this

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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);
}