diff --git a/res/drawable-hdpi/ic_push_registration_reminder.png b/res/drawable-hdpi/ic_push_registration_reminder.png new file mode 100644 index 0000000000..6fb00a4e51 Binary files /dev/null and b/res/drawable-hdpi/ic_push_registration_reminder.png differ diff --git a/res/drawable-mdpi/ic_push_registration_reminder.png b/res/drawable-mdpi/ic_push_registration_reminder.png new file mode 100644 index 0000000000..7b98c77b45 Binary files /dev/null and b/res/drawable-mdpi/ic_push_registration_reminder.png differ diff --git a/res/drawable-xhdpi/ic_push_registration_reminder.png b/res/drawable-xhdpi/ic_push_registration_reminder.png new file mode 100644 index 0000000000..4efc673cf6 Binary files /dev/null and b/res/drawable-xhdpi/ic_push_registration_reminder.png differ diff --git a/res/drawable-xxhdpi/ic_push_registration_reminder.png b/res/drawable-xxhdpi/ic_push_registration_reminder.png new file mode 100644 index 0000000000..7d85e0c15d Binary files /dev/null and b/res/drawable-xxhdpi/ic_push_registration_reminder.png differ diff --git a/res/values/strings.xml b/res/values/strings.xml index cced6800e6..20e3c48a18 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -861,6 +861,8 @@ TextSecure is not currently your default SMS app. Import system SMS? TextSecure can copy your phone\'s SMS messages into its encrypted database. + Enable TextSecure messages? + Instant delivery, stronger privacy, and no SMS fees. diff --git a/src/org/thoughtcrime/securesms/ConversationListFragment.java b/src/org/thoughtcrime/securesms/ConversationListFragment.java index 887f174333..20a15c77ba 100644 --- a/src/org/thoughtcrime/securesms/ConversationListFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationListFragment.java @@ -21,28 +21,19 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; -import android.content.Intent; import android.database.Cursor; import android.os.AsyncTask; -import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Bundle; -import android.provider.Telephony; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.Button; import android.widget.CursorAdapter; -import android.widget.ImageButton; -import android.widget.ImageView; import android.widget.ListView; -import android.widget.TextView; import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.view.ActionMode; @@ -51,15 +42,17 @@ import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.widget.SearchView; +import org.thoughtcrime.securesms.components.DefaultSmsReminder; +import org.thoughtcrime.securesms.components.PushRegistrationReminder; +import org.thoughtcrime.securesms.components.ReminderView; +import org.thoughtcrime.securesms.components.SystemSmsImportReminder; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.loaders.ConversationListLoader; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.service.ApplicationMigrationService; import org.thoughtcrime.securesms.util.Dialogs; -import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.textsecure.crypto.MasterSecret; -import org.thoughtcrime.securesms.util.Util; import java.util.Set; @@ -71,13 +64,13 @@ public class ConversationListFragment extends SherlockListFragment private ConversationSelectedListener listener; private MasterSecret masterSecret; private ActionMode actionMode; - private View reminderView; - private String queryFilter = ""; + private ReminderView reminderView; + private String queryFilter = ""; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { final View view = inflater.inflate(R.layout.conversation_list_fragment, container, false); - reminderView = LayoutInflater.from(getActivity()).inflate(R.layout.reminder_header, null); + reminderView = new ReminderView(getActivity()); return view; } @@ -203,17 +196,14 @@ public class ConversationListFragment extends SherlockListFragment } private void initializeReminders() { - final boolean isDefault = Util.isDefaultSmsProvider(getActivity()); - if (isDefault) { - TextSecurePreferences.setPromptedDefaultSmsProvider(getActivity(), false); - } - - if (!isDefault && !TextSecurePreferences.hasPromptedDefaultSmsProvider(getActivity())) { - showDefaultSmsReminder(); - } else if (isDefault && !ApplicationMigrationService.isDatabaseImported(getActivity())) { - showSystemSmsImportReminder(); + if (DefaultSmsReminder.isEligible(getActivity())) { + reminderView.showReminder(new DefaultSmsReminder(getActivity())); + } else if (SystemSmsImportReminder.isEligible(getActivity())) { + reminderView.showReminder(new SystemSmsImportReminder(getActivity(), masterSecret)); + } else if (PushRegistrationReminder.isEligible(getActivity())) { + reminderView.showReminder(new PushRegistrationReminder(getActivity(), masterSecret)); } else { - reminderView.findViewById(R.id.container).setVisibility(View.GONE); + reminderView.hide(); } } @@ -339,79 +329,6 @@ public class ConversationListFragment extends SherlockListFragment actionMode = null; } - @TargetApi(VERSION_CODES.KITKAT) - private void showDefaultSmsReminder() { - final ViewGroup container = (ViewGroup) reminderView.findViewById(R.id.container); - - setReminderData(R.drawable.sms_selection_icon, - R.string.reminder_header_sms_default_title, - R.string.reminder_header_sms_default_text, - new OnClickListener() { - @Override - public void onClick(View v) { - TextSecurePreferences.setPromptedDefaultSmsProvider(getActivity(), true); - Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT); - intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getActivity().getPackageName()); - startActivity(intent); - } - }, - new OnClickListener() { - @Override - public void onClick(View v) { - TextSecurePreferences.setPromptedDefaultSmsProvider(getActivity(), true); - container.setVisibility(View.GONE); - } - }); - container.setVisibility(View.VISIBLE); - } - - private void showSystemSmsImportReminder() { - final ViewGroup container = (ViewGroup) reminderView.findViewById(R.id.container); - - setReminderData(R.drawable.sms_system_import_icon, - R.string.reminder_header_sms_import_title, - R.string.reminder_header_sms_import_text, - new OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), ApplicationMigrationService.class); - intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE); - intent.putExtra("master_secret", masterSecret); - getActivity().startService(intent); - - Intent nextIntent = new Intent(getActivity(), ConversationListActivity.class); - intent.putExtra("master_secret", masterSecret); - - Intent activityIntent = new Intent(getActivity(), DatabaseMigrationActivity.class); - activityIntent.putExtra("master_secret", masterSecret); - activityIntent.putExtra("next_intent", nextIntent); - getActivity().startActivity(activityIntent); - } - }, - new OnClickListener() { - @Override - public void onClick(View v) { - ApplicationMigrationService.setDatabaseImported(getActivity()); - container.setVisibility(View.GONE); - } - }); - container.setVisibility(View.VISIBLE); - } - - private void setReminderData(int iconResId, int titleResId, int textResId, OnClickListener okListener, OnClickListener cancelListener) { - final ImageButton cancel = (ImageButton) reminderView.findViewById(R.id.cancel); - final Button ok = (Button ) reminderView.findViewById(R.id.ok); - final TextView title = (TextView ) reminderView.findViewById(R.id.reminder_title); - final TextView text = (TextView ) reminderView.findViewById(R.id.reminder_text); - final ImageView icon = (ImageView ) reminderView.findViewById(R.id.icon); - - icon.setImageResource(iconResId); - title.setText(titleResId); - text.setText(textResId); - ok.setOnClickListener(okListener); - cancel.setOnClickListener(cancelListener); - } - } diff --git a/src/org/thoughtcrime/securesms/components/DefaultSmsReminder.java b/src/org/thoughtcrime/securesms/components/DefaultSmsReminder.java new file mode 100644 index 0000000000..6a2a0ea8ba --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/DefaultSmsReminder.java @@ -0,0 +1,51 @@ +package org.thoughtcrime.securesms.components; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.provider.Telephony; +import android.view.View; +import android.view.View.OnClickListener; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.thoughtcrime.securesms.util.Util; + +public class DefaultSmsReminder extends Reminder { + + @TargetApi(VERSION_CODES.KITKAT) + public DefaultSmsReminder(final Context context) { + super(R.drawable.sms_selection_icon, + R.string.reminder_header_sms_default_title, + R.string.reminder_header_sms_default_text); + + final OnClickListener okListener = new OnClickListener() { + @Override + public void onClick(View v) { + TextSecurePreferences.setPromptedDefaultSmsProvider(context, true); + Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT); + intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, context.getPackageName()); + context.startActivity(intent); + } + }; + final OnClickListener cancelListener = new OnClickListener() { + @Override + public void onClick(View v) { + TextSecurePreferences.setPromptedDefaultSmsProvider(context, true); + } + }; + setOkListener(okListener); + setCancelListener(cancelListener); + } + + public static boolean isEligible(Context context) { + final boolean isDefault = Util.isDefaultSmsProvider(context); + if (isDefault) { + TextSecurePreferences.setPromptedDefaultSmsProvider(context, false); + } + + return !isDefault && !TextSecurePreferences.hasPromptedDefaultSmsProvider(context); + } +} diff --git a/src/org/thoughtcrime/securesms/components/PushRegistrationReminder.java b/src/org/thoughtcrime/securesms/components/PushRegistrationReminder.java new file mode 100644 index 0000000000..910e545b27 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/PushRegistrationReminder.java @@ -0,0 +1,43 @@ +package org.thoughtcrime.securesms.components; + +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.view.View.OnClickListener; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.RegistrationActivity; +import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.textsecure.crypto.MasterSecret; + +public class PushRegistrationReminder extends Reminder { + public static final long REMINDER_INTERVAL_MS = 3 * 24 * 60 * 60 * 1000; + + public PushRegistrationReminder(final Context context, final MasterSecret masterSecret) { + super(R.drawable.ic_push_registration_reminder, + R.string.reminder_header_push_title, + R.string.reminder_header_push_text); + + final OnClickListener okListener = new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(context, RegistrationActivity.class); + intent.putExtra("master_secret", masterSecret); + context.startActivity(intent); + } + }; + final OnClickListener cancelListener = new OnClickListener() { + @Override + public void onClick(View v) { + TextSecurePreferences.setLastPushReminderTime(context, System.currentTimeMillis()); + } + }; + setOkListener(okListener); + setCancelListener(cancelListener); + } + + public static boolean isEligible(Context context) { + return !TextSecurePreferences.isPushRegistered(context) && + (TextSecurePreferences.getLastPushReminderTime(context) + REMINDER_INTERVAL_MS < System.currentTimeMillis()); + } +} diff --git a/src/org/thoughtcrime/securesms/components/Reminder.java b/src/org/thoughtcrime/securesms/components/Reminder.java new file mode 100644 index 0000000000..6334675546 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/Reminder.java @@ -0,0 +1,49 @@ +package org.thoughtcrime.securesms.components; + +import android.content.Context; +import android.view.View.OnClickListener; +import android.view.ViewGroup; + +import org.thoughtcrime.securesms.R; + +public abstract class Reminder { + private int iconResId; + private int titleResId; + private int textResId; + private OnClickListener okListener; + private OnClickListener cancelListener; + + public Reminder(int iconResId, int titleResId, int textResId) { + this.iconResId = iconResId; + this.titleResId = titleResId; + this.textResId = textResId; + } + + public int getIconResId() { + return iconResId; + } + + public int getTitleResId() { + return titleResId; + } + + public int getTextResId() { + return textResId; + } + + public OnClickListener getOkListener() { + return okListener; + } + + public OnClickListener getCancelListener() { + return cancelListener; + } + + public void setOkListener(OnClickListener okListener) { + this.okListener = okListener; + } + + public void setCancelListener(OnClickListener cancelListener) { + this.cancelListener = cancelListener; + } +} diff --git a/src/org/thoughtcrime/securesms/components/ReminderView.java b/src/org/thoughtcrime/securesms/components/ReminderView.java new file mode 100644 index 0000000000..b684814eb4 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/ReminderView.java @@ -0,0 +1,73 @@ +package org.thoughtcrime.securesms.components; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build.VERSION_CODES; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.thoughtcrime.securesms.R; + +/** + * View to display actionable reminders to the user + */ +public class ReminderView extends LinearLayout { + private ViewGroup container; + private ImageButton cancel; + private Button ok; + private TextView title; + private TextView text; + private ImageView icon; + + public ReminderView(Context context) { + super(context); + initialize(); + } + + public ReminderView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(); + } + + @TargetApi(VERSION_CODES.HONEYCOMB) + public ReminderView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(); + } + + private void initialize() { + LayoutInflater.from(getContext()).inflate(R.layout.reminder_header, this, true); + container = (ViewGroup ) findViewById(R.id.container); + cancel = (ImageButton) findViewById(R.id.cancel); + ok = (Button ) findViewById(R.id.ok); + title = (TextView ) findViewById(R.id.reminder_title); + text = (TextView ) findViewById(R.id.reminder_text); + icon = (ImageView ) findViewById(R.id.icon); + } + + public void showReminder(final Reminder reminder) { + icon.setImageResource(reminder.getIconResId()); + title.setText(reminder.getTitleResId()); + text.setText(reminder.getTextResId()); + ok.setOnClickListener(reminder.getOkListener()); + cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + hide(); + if (reminder.getCancelListener() != null) reminder.getCancelListener().onClick(v); + } + }); + container.setVisibility(View.VISIBLE); + } + + public void hide() { + container.setVisibility(View.GONE); + } +} diff --git a/src/org/thoughtcrime/securesms/components/SystemSmsImportReminder.java b/src/org/thoughtcrime/securesms/components/SystemSmsImportReminder.java new file mode 100644 index 0000000000..6badeabec4 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/SystemSmsImportReminder.java @@ -0,0 +1,51 @@ +package org.thoughtcrime.securesms.components; + +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.view.View.OnClickListener; + +import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.DatabaseMigrationActivity; +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.service.ApplicationMigrationService; +import org.whispersystems.textsecure.crypto.MasterSecret; + +public class SystemSmsImportReminder extends Reminder { + + public SystemSmsImportReminder(final Context context, final MasterSecret masterSecret) { + super(R.drawable.sms_system_import_icon, + R.string.reminder_header_sms_import_title, + R.string.reminder_header_sms_import_text); + + final OnClickListener okListener = new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(context, ApplicationMigrationService.class); + intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE); + intent.putExtra("master_secret", masterSecret); + context.startService(intent); + + Intent nextIntent = new Intent(context, ConversationListActivity.class); + intent.putExtra("master_secret", masterSecret); + + Intent activityIntent = new Intent(context, DatabaseMigrationActivity.class); + activityIntent.putExtra("master_secret", masterSecret); + activityIntent.putExtra("next_intent", nextIntent); + context.startActivity(activityIntent); + } + }; + final OnClickListener cancelListener = new OnClickListener() { + @Override + public void onClick(View v) { + ApplicationMigrationService.setDatabaseImported(context); + } + }; + setOkListener(okListener); + setCancelListener(cancelListener); + } + + public static boolean isEligible(Context context) { + return !ApplicationMigrationService.isDatabaseImported(context); + } +} diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 65d08e2bba..b67874ee36 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -55,6 +55,8 @@ 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 PUSH_REGISTRATION_REMINDER_PREF = "pref_push_registration_reminder"; + public static void setGcmRegistrationId(Context context, String registrationId) { setStringPreference(context, GCM_REGISTRATION_ID_PREF, registrationId); setIntegerPrefrence(context, GCM_REGISTRATION_ID_VERSION_PREF, Util.getCurrentApkReleaseVersion(context)); @@ -305,6 +307,14 @@ public class TextSecurePreferences { return Integer.parseInt(getStringPreference(context, THREAD_TRIM_LENGTH, "500")); } + public static long getLastPushReminderTime(Context context) { + return getLongPreference(context, PUSH_REGISTRATION_REMINDER_PREF, 0L); + } + + public static void setLastPushReminderTime(Context context, long time) { + setLongPreference(context, PUSH_REGISTRATION_REMINDER_PREF, System.currentTimeMillis()); + } + private static void setBooleanPreference(Context context, String key, boolean value) { PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(key, value).apply(); }