session-android/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java
2017-08-28 10:30:50 -07:00

540 lines
21 KiB
Java

package org.thoughtcrime.securesms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.color.MaterialColors;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.preferences.AdvancedRingtonePreference;
import org.thoughtcrime.securesms.preferences.ColorPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.concurrent.ExecutionException;
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener
{
private static final String TAG = RecipientPreferenceActivity.class.getSimpleName();
public static final String ADDRESS_EXTRA = "recipient_address";
public static final String CAN_HAVE_SAFETY_NUMBER_EXTRA = "can_have_safety_number";
private static final String PREFERENCE_MUTED = "pref_key_recipient_mute";
private static final String PREFERENCE_TONE = "pref_key_recipient_ringtone";
private static final String PREFERENCE_VIBRATE = "pref_key_recipient_vibrate";
private static final String PREFERENCE_BLOCK = "pref_key_recipient_block";
private static final String PREFERENCE_COLOR = "pref_key_recipient_color";
private static final String PREFERENCE_IDENTITY = "pref_key_recipient_identity";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private AvatarImageView avatar;
private Toolbar toolbar;
private TextView title;
private TextView blockedIndicator;
private BroadcastReceiver staleReceiver;
@Override
public void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) {
setContentView(R.layout.recipient_preference_activity);
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
Recipient recipient = RecipientFactory.getRecipientFor(this, address, true);
initializeToolbar();
initializeReceivers();
setHeader(recipient);
recipient.addListener(this);
Bundle bundle = new Bundle();
bundle.putParcelable(ADDRESS_EXTRA, address);
initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), masterSecret, null, bundle);
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(staleReceiver);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.preference_fragment);
fragment.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
return true;
}
return false;
}
private void initializeToolbar() {
this.toolbar = (Toolbar) findViewById(R.id.toolbar);
this.toolbar.setLogo(null);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
this.avatar = (AvatarImageView) toolbar.findViewById(R.id.avatar);
this.title = (TextView) toolbar.findViewById(R.id.name);
this.blockedIndicator = (TextView) toolbar.findViewById(R.id.blocked_indicator);
}
private void initializeReceivers() {
this.staleReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Recipient recipient = RecipientFactory.getRecipientFor(context, (Address)getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
recipient.addListener(RecipientPreferenceActivity.this);
onModified(recipient);
}
};
IntentFilter staleFilter = new IntentFilter();
staleFilter.addAction(GroupDatabase.DATABASE_UPDATE_ACTION);
staleFilter.addAction(RecipientFactory.RECIPIENT_CLEAR_ACTION);
registerReceiver(staleReceiver, staleFilter);
}
private void setHeader(Recipient recipient) {
this.avatar.setAvatar(recipient, true);
this.title.setText(recipient.toShortString());
this.toolbar.setBackgroundColor(recipient.getColor().toActionBarColor(this));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(recipient.getColor().toStatusBarColor(this));
}
if (recipient.isBlocked()) this.blockedIndicator.setVisibility(View.VISIBLE);
else this.blockedIndicator.setVisibility(View.GONE);
}
@Override
public void onModified(final Recipient recipient) {
title.post(new Runnable() {
@Override
public void run() {
setHeader(recipient);
}
});
}
public static class RecipientPreferenceFragment
extends PreferenceFragment
implements RecipientModifiedListener
{
private final Handler handler = new Handler();
private Recipient recipient;
private BroadcastReceiver staleReceiver;
private MasterSecret masterSecret;
private boolean canHaveSafetyNumber;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.recipient_preferences);
initializeRecipients();
this.masterSecret = getArguments().getParcelable("master_secret");
this.canHaveSafetyNumber = getActivity().getIntent()
.getBooleanExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA, false);
this.findPreference(PREFERENCE_TONE)
.setOnPreferenceChangeListener(new RingtoneChangeListener());
this.findPreference(PREFERENCE_VIBRATE)
.setOnPreferenceChangeListener(new VibrateChangeListener());
this.findPreference(PREFERENCE_MUTED)
.setOnPreferenceClickListener(new MuteClickedListener());
this.findPreference(PREFERENCE_BLOCK)
.setOnPreferenceClickListener(new BlockClickedListener());
this.findPreference(PREFERENCE_COLOR)
.setOnPreferenceChangeListener(new ColorChangeListener());
}
@Override
public void onResume() {
super.onResume();
setSummaries(recipient);
}
@Override
public void onDestroy() {
super.onDestroy();
this.recipient.removeListener(this);
getActivity().unregisterReceiver(staleReceiver);
}
private void initializeRecipients() {
this.recipient = RecipientFactory.getRecipientFor(getActivity(),
(Address)getArguments().getParcelable(ADDRESS_EXTRA),
true);
this.recipient.addListener(this);
this.staleReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
recipient.removeListener(RecipientPreferenceFragment.this);
recipient = RecipientFactory.getRecipientFor(getActivity(), (Address)getArguments().getParcelable(ADDRESS_EXTRA), true);
onModified(recipient);
}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(GroupDatabase.DATABASE_UPDATE_ACTION);
intentFilter.addAction(RecipientFactory.RECIPIENT_CLEAR_ACTION);
getActivity().registerReceiver(staleReceiver, intentFilter);
}
private void setSummaries(Recipient recipient) {
CheckBoxPreference mutePreference = (CheckBoxPreference) this.findPreference(PREFERENCE_MUTED);
AdvancedRingtonePreference ringtonePreference = (AdvancedRingtonePreference) this.findPreference(PREFERENCE_TONE);
ListPreference vibratePreference = (ListPreference) this.findPreference(PREFERENCE_VIBRATE);
ColorPreference colorPreference = (ColorPreference) this.findPreference(PREFERENCE_COLOR);
Preference blockPreference = this.findPreference(PREFERENCE_BLOCK);
final Preference identityPreference = this.findPreference(PREFERENCE_IDENTITY);
mutePreference.setChecked(recipient.isMuted());
final Uri toneUri = recipient.getRingtone();
if (toneUri == null) {
ringtonePreference.setSummary(R.string.preferences__default);
ringtonePreference.setCurrentRingtone(Settings.System.DEFAULT_NOTIFICATION_URI);
} else if (toneUri.toString().isEmpty()) {
ringtonePreference.setSummary(R.string.preferences__silent);
ringtonePreference.setCurrentRingtone(null);
} else {
Ringtone tone = RingtoneManager.getRingtone(getActivity(), toneUri);
if (tone != null) {
ringtonePreference.setSummary(tone.getTitle(getActivity()));
ringtonePreference.setCurrentRingtone(toneUri);
}
}
if (recipient.getVibrate() == VibrateState.DEFAULT) {
vibratePreference.setSummary(R.string.preferences__default);
vibratePreference.setValueIndex(0);
} else if (recipient.getVibrate() == VibrateState.ENABLED) {
vibratePreference.setSummary(R.string.RecipientPreferenceActivity_enabled);
vibratePreference.setValueIndex(1);
} else {
vibratePreference.setSummary(R.string.RecipientPreferenceActivity_disabled);
vibratePreference.setValueIndex(2);
}
if (recipient.isGroupRecipient()) {
if (colorPreference != null) getPreferenceScreen().removePreference(colorPreference);
if (blockPreference != null) getPreferenceScreen().removePreference(blockPreference);
if (identityPreference != null) getPreferenceScreen().removePreference(identityPreference);
} else {
colorPreference.setChoices(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(getActivity()));
colorPreference.setValue(recipient.getColor().toActionBarColor(getActivity()));
if (recipient.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block);
IdentityUtil.getRemoteIdentityKey(getActivity(), recipient).addListener(new ListenableFuture.Listener<Optional<IdentityRecord>>() {
@Override
public void onSuccess(Optional<IdentityRecord> result) {
if (result.isPresent()) {
if (identityPreference != null) identityPreference.setOnPreferenceClickListener(new IdentityClickedListener(result.get()));
if (identityPreference != null) identityPreference.setEnabled(true);
} else if (canHaveSafetyNumber) {
if (identityPreference != null) identityPreference.setSummary(R.string.RecipientPreferenceActivity_available_once_a_message_has_been_sent_or_received);
if (identityPreference != null) identityPreference.setEnabled(false);
} else {
if (identityPreference != null) getPreferenceScreen().removePreference(identityPreference);
}
}
@Override
public void onFailure(ExecutionException e) {
if (identityPreference != null) getPreferenceScreen().removePreference(identityPreference);
}
});
}
}
@Override
public void onModified(final Recipient recipient) {
handler.post(new Runnable() {
@Override
public void run() {
setSummaries(recipient);
}
});
}
private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String value = (String)newValue;
final Uri uri;
if (Settings.System.DEFAULT_NOTIFICATION_URI.toString().equals(value)) {
uri = null;
} else {
uri = Uri.parse(value);
}
recipient.setRingtone(uri);
new AsyncTask<Uri, Void, Void>() {
@Override
protected Void doInBackground(Uri... params) {
DatabaseFactory.getRecipientPreferenceDatabase(getActivity())
.setRingtone(recipient, params[0]);
return null;
}
}.execute(uri);
return false;
}
}
private class VibrateChangeListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
int value = Integer.parseInt((String) newValue);
final VibrateState vibrateState = VibrateState.fromId(value);
recipient.setVibrate(vibrateState);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(getActivity())
.setVibrate(recipient, vibrateState);
return null;
}
}.execute();
return false;
}
}
private class ColorChangeListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final int value = (Integer) newValue;
final MaterialColor selectedColor = MaterialColors.CONVERSATION_PALETTE.getByColor(getActivity(), value);
final MaterialColor currentColor = recipient.getColor();
if (selectedColor == null) return true;
if (preference.isEnabled() && !currentColor.equals(selectedColor)) {
recipient.setColor(selectedColor);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Context context = getActivity();
DatabaseFactory.getRecipientPreferenceDatabase(context)
.setColor(recipient, selectedColor);
if (DirectoryHelper.getUserCapabilities(context, recipient) == DirectoryHelper.Capability.SUPPORTED) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceContactUpdateJob(context, recipient.getAddress()));
}
return null;
}
}.execute();
}
return true;
}
}
private class MuteClickedListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (recipient.isMuted()) handleUnmute();
else handleMute();
return true;
}
private void handleMute() {
MuteDialog.show(getActivity(), new MuteDialog.MuteSelectionListener() {
@Override
public void onMuted(long until) {
setMuted(recipient, until);
}
});
setSummaries(recipient);
}
private void handleUnmute() {
setMuted(recipient, 0);
}
private void setMuted(final Recipient recipient, final long until) {
recipient.setMuted(until);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientPreferenceDatabase(getActivity())
.setMuted(recipient, until);
return null;
}
}.execute();
}
}
private class IdentityClickedListener implements Preference.OnPreferenceClickListener {
private final IdentityRecord identityKey;
private IdentityClickedListener(IdentityRecord identityKey) {
Log.w(TAG, "Identity record: " + identityKey);
this.identityKey = identityKey;
}
@Override
public boolean onPreferenceClick(Preference preference) {
Intent verifyIdentityIntent = new Intent(getActivity(), VerifyIdentityActivity.class);
verifyIdentityIntent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, recipient.getAddress());
verifyIdentityIntent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey.getIdentityKey()));
verifyIdentityIntent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, identityKey.getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
startActivity(verifyIdentityIntent);
return true;
}
}
private class BlockClickedListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (recipient.isBlocked()) handleUnblock();
else handleBlock();
return true;
}
private void handleBlock() {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.RecipientPreferenceActivity_block_this_contact_question)
.setMessage(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact)
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_block, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setBlocked(recipient, true);
}
}).show();
}
private void handleUnblock() {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.RecipientPreferenceActivity_unblock_this_contact_question)
.setMessage(R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact)
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setBlocked(recipient, false);
}
}).show();
}
private void setBlocked(final Recipient recipient, final boolean blocked) {
recipient.setBlocked(blocked);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Context context = getActivity();
DatabaseFactory.getRecipientPreferenceDatabase(context)
.setBlocked(recipient, blocked);
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceBlockedUpdateJob(context));
return null;
}
}.execute();
}
}
}
}