Move all files to natural position.

This commit is contained in:
Alan Evans
2020-01-06 10:52:48 -05:00
parent 0df36047e7
commit 9ebe920195
3016 changed files with 6 additions and 36 deletions

View File

@@ -0,0 +1,231 @@
package org.thoughtcrime.securesms.preferences;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.LogSubmitActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import java.io.IOException;
public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment {
private static final String TAG = AdvancedPreferenceFragment.class.getSimpleName();
private static final String PUSH_MESSAGING_PREF = "pref_toggle_push_messaging";
private static final String SUBMIT_DEBUG_LOG_PREF = "pref_submit_debug_logs";
private static final int PICK_IDENTITY_CONTACT = 1;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
initializeIdentitySelection();
Preference submitDebugLog = this.findPreference(SUBMIT_DEBUG_LOG_PREF);
submitDebugLog.setOnPreferenceClickListener(new SubmitDebugLogListener());
submitDebugLog.setSummary(getVersion(getActivity()));
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_advanced);
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__advanced);
initializePushMessagingToggle();
}
@Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
Log.i(TAG, "Got result: " + resultCode + " for req: " + reqCode);
if (resultCode == Activity.RESULT_OK && reqCode == PICK_IDENTITY_CONTACT) {
handleIdentitySelection(data);
}
}
private void initializePushMessagingToggle() {
CheckBoxPreference preference = (CheckBoxPreference)this.findPreference(PUSH_MESSAGING_PREF);
if (TextSecurePreferences.isPushRegistered(getActivity())) {
preference.setChecked(true);
preference.setSummary(TextSecurePreferences.getLocalNumber(getActivity()));
} else {
preference.setChecked(false);
preference.setSummary(R.string.preferences__free_private_messages_and_calls);
}
preference.setOnPreferenceChangeListener(new PushMessagingClickListener());
}
private void initializeIdentitySelection() {
ContactIdentityManager identity = ContactIdentityManager.getInstance(getActivity());
Preference preference = this.findPreference(TextSecurePreferences.IDENTITY_PREF);
if (identity.isSelfIdentityAutoDetected()) {
this.getPreferenceScreen().removePreference(preference);
} else {
Uri contactUri = identity.getSelfIdentityUri();
if (contactUri != null) {
String contactName = ContactAccessor.getInstance().getNameFromContact(getActivity(), contactUri);
preference.setSummary(String.format(getString(R.string.ApplicationPreferencesActivity_currently_s),
contactName));
}
preference.setOnPreferenceClickListener(new IdentityPreferenceClickListener());
}
}
private @NonNull String getVersion(@Nullable Context context) {
try {
if (context == null) return "";
String app = context.getString(R.string.app_name);
String version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
return String.format("%s %s", app, version);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, e);
return context.getString(R.string.app_name);
}
}
private class IdentityPreferenceClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
startActivityForResult(intent, PICK_IDENTITY_CONTACT);
return true;
}
}
private void handleIdentitySelection(Intent data) {
Uri contactUri = data.getData();
if (contactUri != null) {
TextSecurePreferences.setIdentityContactUri(getActivity(), contactUri.toString());
initializeIdentitySelection();
}
}
private class SubmitDebugLogListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
final Intent intent = new Intent(getActivity(), LogSubmitActivity.class);
startActivity(intent);
return true;
}
}
private class PushMessagingClickListener implements Preference.OnPreferenceChangeListener {
private static final int SUCCESS = 0;
private static final int NETWORK_ERROR = 1;
private class DisablePushMessagesTask extends ProgressDialogAsyncTask<Void, Void, Integer> {
private final CheckBoxPreference checkBoxPreference;
public DisablePushMessagesTask(final CheckBoxPreference checkBoxPreference) {
super(getActivity(), R.string.ApplicationPreferencesActivity_unregistering, R.string.ApplicationPreferencesActivity_unregistering_from_signal_messages_and_calls);
this.checkBoxPreference = checkBoxPreference;
}
@Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
switch (result) {
case NETWORK_ERROR:
Toast.makeText(getActivity(),
R.string.ApplicationPreferencesActivity_error_connecting_to_server,
Toast.LENGTH_LONG).show();
break;
case SUCCESS:
TextSecurePreferences.setPushRegistered(getActivity(), false);
initializePushMessagingToggle();
break;
}
}
@Override
protected Integer doInBackground(Void... params) {
try {
Context context = getActivity();
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
try {
accountManager.setGcmId(Optional.<String>absent());
} catch (AuthorizationFailedException e) {
Log.w(TAG, e);
}
if (!TextSecurePreferences.isFcmDisabled(context)) {
FirebaseInstanceId.getInstance().deleteInstanceId();
}
return SUCCESS;
} catch (IOException ioe) {
Log.w(TAG, ioe);
return NETWORK_ERROR;
}
}
}
@Override
public boolean onPreferenceChange(final Preference preference, Object newValue) {
if (((CheckBoxPreference)preference).isChecked()) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setIconAttribute(R.attr.dialog_info_icon);
builder.setTitle(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls);
builder.setMessage(R.string.ApplicationPreferencesActivity_disable_signal_messages_and_calls_by_unregistering);
builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new DisablePushMessagesTask((CheckBoxPreference)preference).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
builder.show();
} else {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
}
return false;
}
}
}

View File

@@ -0,0 +1,329 @@
package org.thoughtcrime.securesms.preferences;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.BlockedContactsActivity;
import org.thoughtcrime.securesms.PassphraseChangeActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import mobi.upod.timedurationpicker.TimeDurationPickerDialog;
public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment {
private static final String PREFERENCE_CATEGORY_BLOCKED = "preference_category_blocked";
private static final String PREFERENCE_UNIDENTIFIED_LEARN_MORE = "pref_unidentified_learn_more";
private CheckBoxPreference disablePassphrase;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
disablePassphrase = (CheckBoxPreference) this.findPreference("pref_enable_passphrase_temporary");
this.findPreference(TextSecurePreferences.REGISTRATION_LOCK_PREF).setOnPreferenceClickListener(new AccountLockClickListener());
this.findPreference(TextSecurePreferences.SCREEN_LOCK).setOnPreferenceChangeListener(new ScreenLockListener());
this.findPreference(TextSecurePreferences.SCREEN_LOCK_TIMEOUT).setOnPreferenceClickListener(new ScreenLockTimeoutListener());
this.findPreference(TextSecurePreferences.CHANGE_PASSPHRASE_PREF).setOnPreferenceClickListener(new ChangePassphraseClickListener());
this.findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF).setOnPreferenceClickListener(new PassphraseIntervalClickListener());
this.findPreference(TextSecurePreferences.READ_RECEIPTS_PREF).setOnPreferenceChangeListener(new ReadReceiptToggleListener());
this.findPreference(TextSecurePreferences.TYPING_INDICATORS).setOnPreferenceChangeListener(new TypingIndicatorsToggleListener());
this.findPreference(TextSecurePreferences.LINK_PREVIEWS).setOnPreferenceChangeListener(new LinkPreviewToggleListener());
this.findPreference(PREFERENCE_CATEGORY_BLOCKED).setOnPreferenceClickListener(new BlockedContactsClickListener());
this.findPreference(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS).setOnPreferenceChangeListener(new ShowUnidentifiedDeliveryIndicatorsChangedListener());
this.findPreference(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS).setOnPreferenceChangeListener(new UniversalUnidentifiedAccessChangedListener());
this.findPreference(PREFERENCE_UNIDENTIFIED_LEARN_MORE).setOnPreferenceClickListener(new UnidentifiedLearnMoreClickListener());
disablePassphrase.setOnPreferenceChangeListener(new DisablePassphraseClickListener());
initializeVisibility();
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_app_protection);
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__privacy);
if (!TextSecurePreferences.isPasswordDisabled(getContext())) initializePassphraseTimeoutSummary();
else initializeScreenLockTimeoutSummary();
disablePassphrase.setChecked(!TextSecurePreferences.isPasswordDisabled(getActivity()));
}
private void initializePassphraseTimeoutSummary() {
int timeoutMinutes = TextSecurePreferences.getPassphraseTimeoutInterval(getActivity());
this.findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF)
.setSummary(getResources().getQuantityString(R.plurals.AppProtectionPreferenceFragment_minutes, timeoutMinutes, timeoutMinutes));
}
private void initializeScreenLockTimeoutSummary() {
long timeoutSeconds = TextSecurePreferences.getScreenLockTimeout(getContext());
long hours = TimeUnit.SECONDS.toHours(timeoutSeconds);
long minutes = TimeUnit.SECONDS.toMinutes(timeoutSeconds) - (TimeUnit.SECONDS.toHours(timeoutSeconds) * 60 );
long seconds = TimeUnit.SECONDS.toSeconds(timeoutSeconds) - (TimeUnit.SECONDS.toMinutes(timeoutSeconds) * 60);
findPreference(TextSecurePreferences.SCREEN_LOCK_TIMEOUT)
.setSummary(timeoutSeconds <= 0 ? getString(R.string.AppProtectionPreferenceFragment_none) :
String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds));
}
private void initializeVisibility() {
if (TextSecurePreferences.isPasswordDisabled(getContext())) {
findPreference("pref_enable_passphrase_temporary").setVisible(false);
findPreference(TextSecurePreferences.CHANGE_PASSPHRASE_PREF).setVisible(false);
findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF).setVisible(false);
findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_PREF).setVisible(false);
KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService(Context.KEYGUARD_SERVICE);
if (!keyguardManager.isKeyguardSecure()) {
((SwitchPreferenceCompat)findPreference(TextSecurePreferences.SCREEN_LOCK)).setChecked(false);
findPreference(TextSecurePreferences.SCREEN_LOCK).setEnabled(false);
}
} else {
findPreference(TextSecurePreferences.SCREEN_LOCK).setVisible(false);
findPreference(TextSecurePreferences.SCREEN_LOCK_TIMEOUT).setVisible(false);
}
}
private class ScreenLockListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enabled = (Boolean)newValue;
TextSecurePreferences.setScreenLockEnabled(getContext(), enabled);
Intent intent = new Intent(getContext(), KeyCachingService.class);
intent.setAction(KeyCachingService.LOCK_TOGGLED_EVENT);
getContext().startService(intent);
return true;
}
}
private class ScreenLockTimeoutListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
new TimeDurationPickerDialog(getContext(), (view, duration) -> {
if (duration == 0) {
TextSecurePreferences.setScreenLockTimeout(getContext(), 0);
} else {
long timeoutSeconds = Math.max(TimeUnit.MILLISECONDS.toSeconds(duration), 60);
TextSecurePreferences.setScreenLockTimeout(getContext(), timeoutSeconds);
}
initializeScreenLockTimeoutSummary();
}, 0).show();
return true;
}
}
private class AccountLockClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (((SwitchPreferenceCompat)preference).isChecked()) {
RegistrationLockDialog.showRegistrationUnlockPrompt(requireContext(), (SwitchPreferenceCompat)preference);
} else {
RegistrationLockDialog.showRegistrationLockPrompt(requireContext(), (SwitchPreferenceCompat)preference);
}
return true;
}
}
private class BlockedContactsClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(getActivity(), BlockedContactsActivity.class);
startActivity(intent);
return true;
}
}
private class ReadReceiptToggleListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enabled = (boolean)newValue;
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(enabled,
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
return true;
}
}
private class TypingIndicatorsToggleListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enabled = (boolean)newValue;
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
enabled,
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
if (!enabled) {
ApplicationContext.getInstance(requireContext()).getTypingStatusRepository().clear();
}
return true;
}
}
private class LinkPreviewToggleListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enabled = (boolean)newValue;
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(requireContext()),
enabled));
return true;
}
}
public static CharSequence getSummary(Context context) {
final int privacySummaryResId = R.string.ApplicationPreferencesActivity_privacy_summary;
final String onRes = context.getString(R.string.ApplicationPreferencesActivity_on);
final String offRes = context.getString(R.string.ApplicationPreferencesActivity_off);
if (TextSecurePreferences.isPasswordDisabled(context) && !TextSecurePreferences.isScreenLockEnabled(context)) {
if (TextSecurePreferences.isRegistrationLockEnabled(context)) {
return context.getString(privacySummaryResId, offRes, onRes);
} else {
return context.getString(privacySummaryResId, offRes, offRes);
}
} else {
if (TextSecurePreferences.isRegistrationLockEnabled(context)) {
return context.getString(privacySummaryResId, onRes, onRes);
} else {
return context.getString(privacySummaryResId, onRes, offRes);
}
}
}
// Derecated
private class ChangePassphraseClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (MasterSecretUtil.isPassphraseInitialized(getActivity())) {
startActivity(new Intent(getActivity(), PassphraseChangeActivity.class));
} else {
Toast.makeText(getActivity(),
R.string.ApplicationPreferenceActivity_you_havent_set_a_passphrase_yet,
Toast.LENGTH_LONG).show();
}
return true;
}
}
private class PassphraseIntervalClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
new TimeDurationPickerDialog(getContext(), (view, duration) -> {
int timeoutMinutes = Math.max((int)TimeUnit.MILLISECONDS.toMinutes(duration), 1);
TextSecurePreferences.setPassphraseTimeoutInterval(getActivity(), timeoutMinutes);
initializePassphraseTimeoutSummary();
}, 0).show();
return true;
}
}
private class DisablePassphraseClickListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(final Preference preference, Object newValue) {
if (((CheckBoxPreference)preference).isChecked()) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.ApplicationPreferencesActivity_disable_passphrase);
builder.setMessage(R.string.ApplicationPreferencesActivity_this_will_permanently_unlock_signal_and_message_notifications);
builder.setIconAttribute(R.attr.dialog_alert_icon);
builder.setPositiveButton(R.string.ApplicationPreferencesActivity_disable, (dialog, which) -> {
MasterSecretUtil.changeMasterSecretPassphrase(getActivity(),
KeyCachingService.getMasterSecret(getContext()),
MasterSecretUtil.UNENCRYPTED_PASSPHRASE);
TextSecurePreferences.setPasswordDisabled(getActivity(), true);
((CheckBoxPreference)preference).setChecked(false);
Intent intent = new Intent(getActivity(), KeyCachingService.class);
intent.setAction(KeyCachingService.DISABLE_ACTION);
getActivity().startService(intent);
initializeVisibility();
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
} else {
Intent intent = new Intent(getActivity(), PassphraseChangeActivity.class);
startActivity(intent);
}
return false;
}
}
private class ShowUnidentifiedDeliveryIndicatorsChangedListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enabled = (boolean) newValue;
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(getContext()),
TextSecurePreferences.isTypingIndicatorsEnabled(getContext()),
enabled,
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
return true;
}
}
private class UniversalUnidentifiedAccessChangedListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
ApplicationDependencies.getJobManager().add(new RefreshAttributesJob());
return true;
}
}
private class UnidentifiedLearnMoreClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
CommunicationActions.openBrowserLink(preference.getContext(), "https://signal.org/blog/sealed-sender/");
return true;
}
}
}

View File

@@ -0,0 +1,65 @@
package org.thoughtcrime.securesms.preferences;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.preference.ListPreference;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Arrays;
public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment {
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
this.findPreference(TextSecurePreferences.THEME_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.LANGUAGE_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
initializeListSummary((ListPreference)findPreference(TextSecurePreferences.THEME_PREF));
initializeListSummary((ListPreference)findPreference(TextSecurePreferences.LANGUAGE_PREF));
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_appearance);
}
@Override
public void onStart() {
super.onStart();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener((ApplicationPreferencesActivity)getActivity());
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__appearance);
}
@Override
public void onStop() {
super.onStop();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener((ApplicationPreferencesActivity) getActivity());
}
public static CharSequence getSummary(Context context) {
String[] languageEntries = context.getResources().getStringArray(R.array.language_entries);
String[] languageEntryValues = context.getResources().getStringArray(R.array.language_values);
String[] themeEntries = context.getResources().getStringArray(R.array.pref_theme_entries);
String[] themeEntryValues = context.getResources().getStringArray(R.array.pref_theme_values);
int langIndex = Arrays.asList(languageEntryValues).indexOf(TextSecurePreferences.getLanguage(context));
int themeIndex = Arrays.asList(themeEntryValues).indexOf(TextSecurePreferences.getTheme(context));
if (langIndex == -1) langIndex = 0;
if (themeIndex == -1) themeIndex = 0;
return context.getString(R.string.ApplicationPreferencesActivity_appearance_summary,
themeEntries[themeIndex],
languageEntries[langIndex]);
}
}

View File

@@ -0,0 +1,48 @@
package org.thoughtcrime.securesms.preferences;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.preferences.widgets.StorageGraphView;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import java.util.Arrays;
public class ApplicationPreferencesViewModel extends ViewModel {
private final MutableLiveData<StorageGraphView.StorageBreakdown> storageBreakdown = new MutableLiveData<>();
LiveData<StorageGraphView.StorageBreakdown> getStorageBreakdown() {
return storageBreakdown;
}
static ApplicationPreferencesViewModel getApplicationPreferencesViewModel(@NonNull FragmentActivity activity) {
return ViewModelProviders.of(activity).get(ApplicationPreferencesViewModel.class);
}
void refreshStorageBreakdown(@NonNull Context context) {
SignalExecutors.BOUNDED.execute(() -> {
MediaDatabase.StorageBreakdown breakdown = DatabaseFactory.getMediaDatabase(context)
.getStorageBreakdown();
StorageGraphView.StorageBreakdown latestStorageBreakdown = new StorageGraphView.StorageBreakdown(Arrays.asList(
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_photos), breakdown.getPhotoSize()),
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_videos), breakdown.getVideoSize()),
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_files), breakdown.getDocumentSize()),
new StorageGraphView.Entry(ContextCompat.getColor(context, R.color.storage_color_audio), breakdown.getAudioSize())
));
storageBreakdown.postValue(latestStorageBreakdown);
});
}
}

View File

@@ -0,0 +1,72 @@
package org.thoughtcrime.securesms.preferences;
import android.content.Context;
import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
import org.thoughtcrime.securesms.util.Util;
public class BlockedContactListItem extends RelativeLayout implements RecipientForeverObserver {
private AvatarImageView contactPhotoImage;
private TextView nameView;
private GlideRequests glideRequests;
private LiveRecipient recipient;
public BlockedContactListItem(Context context) {
super(context);
}
public BlockedContactListItem(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BlockedContactListItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void onFinishInflate() {
super.onFinishInflate();
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.nameView = findViewById(R.id.name);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (this.recipient != null) {
recipient.removeForeverObserver(this);
}
}
public void set(@NonNull GlideRequests glideRequests, @NonNull LiveRecipient recipient) {
this.glideRequests = glideRequests;
this.recipient = recipient;
onRecipientChanged(recipient.get());
this.recipient.observeForever(this);
}
@Override
public void onRecipientChanged(@NonNull Recipient recipient) {
final AvatarImageView contactPhotoImage = this.contactPhotoImage;
final TextView nameView = this.nameView;
contactPhotoImage.setAvatar(glideRequests, recipient, false);
nameView.setText(recipient.toShortString(getContext()));
}
public Recipient getRecipient() {
return recipient.get();
}
}

View File

@@ -0,0 +1,177 @@
package org.thoughtcrime.securesms.preferences;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.backup.BackupDialog;
import org.thoughtcrime.securesms.backup.FullBackupBase.BackupEvent;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.preferences.widgets.ProgressPreference;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
private static final String TAG = ChatsPreferenceFragment.class.getSimpleName();
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF)
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF)
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF)
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
findPreference(TextSecurePreferences.MESSAGE_BODY_TEXT_SIZE_PREF)
.setOnPreferenceChangeListener(new ListSummaryListener());
findPreference(TextSecurePreferences.BACKUP_ENABLED)
.setOnPreferenceClickListener(new BackupClickListener());
findPreference(TextSecurePreferences.BACKUP_NOW)
.setOnPreferenceClickListener(new BackupCreateListener());
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.MESSAGE_BODY_TEXT_SIZE_PREF));
EventBus.getDefault().register(this);
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_chats);
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.preferences__chats);
setMediaDownloadSummaries();
setBackupSummary();
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(BackupEvent event) {
ProgressPreference preference = (ProgressPreference)findPreference(TextSecurePreferences.BACKUP_NOW);
if (event.getType() == BackupEvent.Type.PROGRESS) {
preference.setEnabled(false);
preference.setSummary(getString(R.string.ChatsPreferenceFragment_in_progress));
preference.setProgress(event.getCount());
} else if (event.getType() == BackupEvent.Type.FINISHED) {
preference.setEnabled(true);
preference.setProgressVisible(false);
setBackupSummary();
}
}
private void setBackupSummary() {
findPreference(TextSecurePreferences.BACKUP_NOW)
.setSummary(String.format(getString(R.string.ChatsPreferenceFragment_last_backup_s), BackupUtil.getLastBackupTime(getContext(), Locale.US)));
}
private void setMediaDownloadSummaries() {
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF)
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getMobileMediaDownloadAllowed(getActivity())));
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF)
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getWifiMediaDownloadAllowed(getActivity())));
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF)
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getRoamingMediaDownloadAllowed(getActivity())));
}
private CharSequence getSummaryForMediaPreference(Set<String> allowedNetworks) {
String[] keys = getResources().getStringArray(R.array.pref_media_download_entries);
String[] values = getResources().getStringArray(R.array.pref_media_download_values);
List<String> outValues = new ArrayList<>(allowedNetworks.size());
for (int i=0; i < keys.length; i++) {
if (allowedNetworks.contains(keys[i])) outValues.add(values[i]);
}
return outValues.isEmpty() ? getResources().getString(R.string.preferences__none)
: TextUtils.join(", ", outValues);
}
private class BackupClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Permissions.with(ChatsPreferenceFragment.this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.ifNecessary()
.onAllGranted(() -> {
if (!((SwitchPreferenceCompat)preference).isChecked()) {
BackupDialog.showEnableBackupDialog(getActivity(), (SwitchPreferenceCompat)preference);
} else {
BackupDialog.showDisableBackupDialog(getActivity(), (SwitchPreferenceCompat)preference);
}
})
.withPermanentDenialDialog(getString(R.string.ChatsPreferenceFragment_signal_requires_external_storage_permission_in_order_to_create_backups))
.execute();
return true;
}
}
private class BackupCreateListener implements Preference.OnPreferenceClickListener {
@SuppressLint("StaticFieldLeak")
@Override
public boolean onPreferenceClick(Preference preference) {
Permissions.with(ChatsPreferenceFragment.this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.ifNecessary()
.onAllGranted(() -> {
Log.i(TAG, "Queing backup...");
ApplicationDependencies.getJobManager().add(new LocalBackupJob());
})
.withPermanentDenialDialog(getString(R.string.ChatsPreferenceFragment_signal_requires_external_storage_permission_in_order_to_create_backups))
.execute();
return true;
}
}
private class MediaDownloadChangeListener implements Preference.OnPreferenceChangeListener {
@SuppressWarnings("unchecked")
@Override public boolean onPreferenceChange(Preference preference, Object newValue) {
Log.i(TAG, "onPreferenceChange");
preference.setSummary(getSummaryForMediaPreference((Set<String>)newValue));
return true;
}
}
public static CharSequence getSummary(Context context) {
return null;
}
}

View File

@@ -0,0 +1,85 @@
package org.thoughtcrime.securesms.preferences;
import android.annotation.SuppressLint;
import android.os.Bundle;
import androidx.fragment.app.DialogFragment;
import androidx.core.view.ViewCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroupAdapter;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.CustomDefaultPreference;
import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference;
import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreferenceDialogFragmentCompat;
public abstract class CorrectedPreferenceFragment extends PreferenceFragmentCompat {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View lv = getView().findViewById(android.R.id.list);
if (lv != null) lv.setPadding(0, 0, 0, 0);
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
DialogFragment dialogFragment = null;
if (preference instanceof ColorPickerPreference) {
dialogFragment = ColorPickerPreferenceDialogFragmentCompat.newInstance(preference.getKey());
} else if (preference instanceof CustomDefaultPreference) {
dialogFragment = CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.newInstance(preference.getKey());
}
if (dialogFragment != null) {
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG");
} else {
super.onDisplayPreferenceDialog(preference);
}
}
@Override
@SuppressLint("RestrictedApi")
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen) {
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
Preference preference = getItem(position);
if (preference instanceof PreferenceCategory) {
setZeroPaddingToLayoutChildren(holder.itemView);
} else {
View iconFrame = holder.itemView.findViewById(R.id.icon_frame);
if (iconFrame != null) {
iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
}
}
}
};
}
private void setZeroPaddingToLayoutChildren(View view) {
if (!(view instanceof ViewGroup)) return;
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
ViewCompat.setPaddingRelative(viewGroup, 0, viewGroup.getPaddingTop(), ViewCompat.getPaddingEnd(viewGroup), viewGroup.getPaddingBottom());
}
}
}

View File

@@ -0,0 +1,29 @@
package org.thoughtcrime.securesms.preferences;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.R;
import java.util.Arrays;
public abstract class ListSummaryPreferenceFragment extends CorrectedPreferenceFragment {
protected class ListSummaryListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
ListPreference listPref = (ListPreference) preference;
int entryIndex = Arrays.asList(listPref.getEntryValues()).indexOf(value);
listPref.setSummary(entryIndex >= 0 && entryIndex < listPref.getEntries().length
? listPref.getEntries()[entryIndex]
: getString(R.string.preferences__led_color_unknown));
return true;
}
}
protected void initializeListSummary(ListPreference pref) {
pref.setSummary(pref.getEntry());
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2011 Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.preferences;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.view.MenuItem;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
public class MmsPreferencesActivity extends PassphraseRequiredActionBarActivity {
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
protected void onCreate(Bundle icicle, boolean ready) {
assert getSupportActionBar() != null;
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Fragment fragment = new MmsPreferencesFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return false;
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
}

View File

@@ -0,0 +1,103 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.preferences;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.CustomDefaultPreference;
import org.thoughtcrime.securesms.database.ApnDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.LegacyMmsConnection;
import org.thoughtcrime.securesms.util.TelephonyUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.io.IOException;
public class MmsPreferencesFragment extends CorrectedPreferenceFragment {
private static final String TAG = MmsPreferencesFragment.class.getSimpleName();
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
((PassphraseRequiredActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(R.string.preferences__advanced_mms_access_point_names);
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_manual_mms);
}
@Override
public void onResume() {
super.onResume();
new LoadApnDefaultsTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private class LoadApnDefaultsTask extends AsyncTask<Void, Void, LegacyMmsConnection.Apn> {
@Override
protected LegacyMmsConnection.Apn doInBackground(Void... params) {
try {
Context context = getActivity();
if (context != null) {
return ApnDatabase.getInstance(context)
.getDefaultApnParameters(TelephonyUtil.getMccMnc(context),
TelephonyUtil.getApn(context));
}
} catch (IOException e) {
Log.w(TAG, e);
}
return null;
}
@Override
protected void onPostExecute(LegacyMmsConnection.Apn apnDefaults) {
((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_HOST_PREF))
.setValidator(new CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.UriValidator())
.setDefaultValue(apnDefaults.getMmsc());
((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_PROXY_HOST_PREF))
.setValidator(new CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.HostnameValidator())
.setDefaultValue(apnDefaults.getProxy());
((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_PROXY_PORT_PREF))
.setValidator(new CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.PortValidator())
.setDefaultValue(apnDefaults.getPort());
((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_USERNAME_PREF))
.setDefaultValue(apnDefaults.getPort());
((CustomDefaultPreference)findPreference(TextSecurePreferences.MMSC_PASSWORD_PREF))
.setDefaultValue(apnDefaults.getPassword());
((CustomDefaultPreference)findPreference(TextSecurePreferences.MMS_USER_AGENT))
.setDefaultValue(LegacyMmsConnection.USER_AGENT);
}
}
}

View File

@@ -0,0 +1,239 @@
package org.thoughtcrime.securesms.preferences;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import androidx.annotation.Nullable;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import android.text.TextUtils;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import static android.app.Activity.RESULT_OK;
public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragment {
@SuppressWarnings("unused")
private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName();
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
Preference ledBlinkPref = this.findPreference(TextSecurePreferences.LED_BLINK_PREF);
if (NotificationChannels.supported()) {
ledBlinkPref.setVisible(false);
TextSecurePreferences.setNotificationRingtone(getContext(), NotificationChannels.getMessageRingtone(getContext()).toString());
TextSecurePreferences.setNotificationVibrateEnabled(getContext(), NotificationChannels.getMessageVibrate(getContext()));
} else {
ledBlinkPref.setOnPreferenceChangeListener(new ListSummaryListener());
initializeListSummary((ListPreference) ledBlinkPref);
}
this.findPreference(TextSecurePreferences.LED_COLOR_PREF)
.setOnPreferenceChangeListener(new LedColorChangeListener());
this.findPreference(TextSecurePreferences.RINGTONE_PREF)
.setOnPreferenceChangeListener(new RingtoneSummaryListener());
this.findPreference(TextSecurePreferences.REPEAT_ALERTS_PREF)
.setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)
.setOnPreferenceChangeListener(new NotificationPrivacyListener());
this.findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF)
.setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.CALL_RINGTONE_PREF)
.setOnPreferenceChangeListener(new RingtoneSummaryListener());
this.findPreference(TextSecurePreferences.VIBRATE_PREF)
.setOnPreferenceChangeListener((preference, newValue) -> {
NotificationChannels.updateMessageVibrate(getContext(), (boolean) newValue);
return true;
});
this.findPreference(TextSecurePreferences.RINGTONE_PREF)
.setOnPreferenceClickListener(preference -> {
Uri current = TextSecurePreferences.getNotificationRingtone(getContext());
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current);
startActivityForResult(intent, 1);
return true;
});
this.findPreference(TextSecurePreferences.CALL_RINGTONE_PREF)
.setOnPreferenceClickListener(preference -> {
Uri current = TextSecurePreferences.getCallNotificationRingtone(getContext());
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_RINGTONE_URI);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current);
startActivityForResult(intent, 2);
return true;
});
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.LED_COLOR_PREF));
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.REPEAT_ALERTS_PREF));
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF));
if (NotificationChannels.supported()) {
this.findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF)
.setOnPreferenceClickListener(preference -> {
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationChannels.getMessagesChannel(getContext()));
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName());
startActivity(intent);
return true;
});
} else {
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF));
}
initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF));
initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF));
initializeMessageVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.VIBRATE_PREF));
initializeCallVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.CALL_VIBRATE_PREF));
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_notifications);
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__notifications);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1 && resultCode == RESULT_OK && data != null) {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)) {
NotificationChannels.updateMessageRingtone(getContext(), uri);
TextSecurePreferences.removeNotificationRingtone(getContext());
} else {
uri = uri == null ? Uri.EMPTY : uri;
NotificationChannels.updateMessageRingtone(getContext(), uri );
TextSecurePreferences.setNotificationRingtone(getContext(), uri.toString());
}
initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF));
} else if (requestCode == 2 && resultCode == RESULT_OK && data != null) {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (Settings.System.DEFAULT_RINGTONE_URI.equals(uri)) {
TextSecurePreferences.removeCallNotificationRingtone(getContext());
} else {
TextSecurePreferences.setCallNotificationRingtone(getContext(), uri != null ? uri.toString() : Uri.EMPTY.toString());
}
initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF));
}
}
private class RingtoneSummaryListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Uri value = (Uri) newValue;
if (value == null || TextUtils.isEmpty(value.toString())) {
preference.setSummary(R.string.preferences__silent);
} else {
Ringtone tone = RingtoneManager.getRingtone(getActivity(), value);
if (tone != null) {
preference.setSummary(tone.getTitle(getActivity()));
}
}
return true;
}
}
private void initializeRingtoneSummary(Preference pref) {
RingtoneSummaryListener listener = (RingtoneSummaryListener) pref.getOnPreferenceChangeListener();
Uri uri = TextSecurePreferences.getNotificationRingtone(getContext());
listener.onPreferenceChange(pref, uri);
}
private void initializeCallRingtoneSummary(Preference pref) {
RingtoneSummaryListener listener = (RingtoneSummaryListener) pref.getOnPreferenceChangeListener();
Uri uri = TextSecurePreferences.getCallNotificationRingtone(getContext());
listener.onPreferenceChange(pref, uri);
}
private void initializeMessageVibrateSummary(SwitchPreferenceCompat pref) {
pref.setChecked(TextSecurePreferences.isNotificationVibrateEnabled(getContext()));
}
private void initializeCallVibrateSummary(SwitchPreferenceCompat pref) {
pref.setChecked(TextSecurePreferences.isCallNotificationVibrateEnabled(getContext()));
}
public static CharSequence getSummary(Context context) {
final int onCapsResId = R.string.ApplicationPreferencesActivity_On;
final int offCapsResId = R.string.ApplicationPreferencesActivity_Off;
return context.getString(TextSecurePreferences.isNotificationsEnabled(context) ? onCapsResId : offCapsResId);
}
private class NotificationPrivacyListener extends ListSummaryListener {
@SuppressLint("StaticFieldLeak")
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
MessageNotifier.updateNotification(getActivity());
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
return super.onPreferenceChange(preference, value);
}
}
@SuppressLint("StaticFieldLeak")
private class LedColorChangeListener extends ListSummaryListener {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
if (NotificationChannels.supported()) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
NotificationChannels.updateMessagesLedColor(getActivity(), (String) value);
return null;
}
}.execute();
}
return super.onPreferenceChange(preference, value);
}
}
}

View File

@@ -0,0 +1,118 @@
package org.thoughtcrime.securesms.preferences;
import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.provider.Settings;
import android.provider.Telephony;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
public class SmsMmsPreferenceFragment extends CorrectedPreferenceFragment {
private static final String KITKAT_DEFAULT_PREF = "pref_set_default";
private static final String MMS_PREF = "pref_mms_preferences";
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
this.findPreference(MMS_PREF)
.setOnPreferenceClickListener(new ApnPreferencesClickListener());
initializePlatformSpecificOptions();
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_sms_mms);
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__sms_mms);
initializeDefaultPreference();
}
private void initializePlatformSpecificOptions() {
PreferenceScreen preferenceScreen = getPreferenceScreen();
Preference defaultPreference = findPreference(KITKAT_DEFAULT_PREF);
Preference allSmsPreference = findPreference(TextSecurePreferences.ALL_SMS_PREF);
Preference allMmsPreference = findPreference(TextSecurePreferences.ALL_MMS_PREF);
Preference manualMmsPreference = findPreference(MMS_PREF);
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
if (allSmsPreference != null) preferenceScreen.removePreference(allSmsPreference);
if (allMmsPreference != null) preferenceScreen.removePreference(allMmsPreference);
} else if (defaultPreference != null) {
preferenceScreen.removePreference(defaultPreference);
}
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && manualMmsPreference != null) {
preferenceScreen.removePreference(manualMmsPreference);
}
}
private void initializeDefaultPreference() {
if (VERSION.SDK_INT < VERSION_CODES.KITKAT) return;
Preference defaultPreference = findPreference(KITKAT_DEFAULT_PREF);
if (Util.isDefaultSmsProvider(getActivity())) {
if (VERSION.SDK_INT < VERSION_CODES.M) defaultPreference.setIntent(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
if (VERSION.SDK_INT < VERSION_CODES.N) defaultPreference.setIntent(new Intent(Settings.ACTION_SETTINGS));
else defaultPreference.setIntent(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS));
defaultPreference.setTitle(getString(R.string.ApplicationPreferencesActivity_sms_enabled));
defaultPreference.setSummary(getString(R.string.ApplicationPreferencesActivity_touch_to_change_your_default_sms_app));
} else {
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getActivity().getPackageName());
defaultPreference.setIntent(intent);
defaultPreference.setTitle(getString(R.string.ApplicationPreferencesActivity_sms_disabled));
defaultPreference.setSummary(getString(R.string.ApplicationPreferencesActivity_touch_to_make_signal_your_default_sms_app));
}
}
private class ApnPreferencesClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Fragment fragment = new MmsPreferencesFragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
return true;
}
}
public static CharSequence getSummary(Context context) {
final String on = context.getString(R.string.ApplicationPreferencesActivity_on);
final String onCaps = context.getString(R.string.ApplicationPreferencesActivity_On);
final String off = context.getString(R.string.ApplicationPreferencesActivity_off);
final String offCaps = context.getString(R.string.ApplicationPreferencesActivity_Off);
final int smsMmsSummaryResId = R.string.ApplicationPreferencesActivity_sms_mms_summary;
boolean postKitkatSMS = Util.isDefaultSmsProvider(context);
boolean preKitkatSMS = TextSecurePreferences.isInterceptAllSmsEnabled(context);
boolean preKitkatMMS = TextSecurePreferences.isInterceptAllMmsEnabled(context);
if (postKitkatSMS) return onCaps;
else return offCaps;
}
}

View File

@@ -0,0 +1,109 @@
package org.thoughtcrime.securesms.preferences;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.preferences.widgets.StoragePreferenceCategory;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Trimmer;
public class StoragePreferenceFragment extends ListSummaryPreferenceFragment {
private static final String TAG = Log.tag(StoragePreferenceFragment.class);
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
findPreference(TextSecurePreferences.THREAD_TRIM_NOW)
.setOnPreferenceClickListener(new TrimNowClickListener());
findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH)
.setOnPreferenceChangeListener(new TrimLengthValidationListener());
StoragePreferenceCategory storageCategory = (StoragePreferenceCategory) findPreference("pref_storage_category");
FragmentActivity activity = requireActivity();
ApplicationPreferencesViewModel viewModel = ApplicationPreferencesViewModel.getApplicationPreferencesViewModel(activity);
storageCategory.setOnFreeUpSpace(() -> activity.startActivity(MediaOverviewActivity.forAll(activity)));
viewModel.getStorageBreakdown().observe(activity, storageCategory::setStorage);
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences_storage);
}
@Override
public void onResume() {
super.onResume();
((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.preferences__storage);
FragmentActivity activity = requireActivity();
ApplicationPreferencesViewModel viewModel = ApplicationPreferencesViewModel.getApplicationPreferencesViewModel(activity);
viewModel.refreshStorageBreakdown(activity.getApplicationContext());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
private class TrimNowClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
final int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(getActivity());
new AlertDialog.Builder(requireActivity())
.setTitle(R.string.ApplicationPreferencesActivity_delete_all_old_messages_now)
.setMessage(getResources().getQuantityString(R.plurals.ApplicationPreferencesActivity_this_will_immediately_trim_all_conversations_to_the_d_most_recent_messages,
threadLengthLimit, threadLengthLimit))
.setPositiveButton(R.string.ApplicationPreferencesActivity_delete, (dialog, which) -> Trimmer.trimAllThreads(getActivity(), threadLengthLimit))
.setNegativeButton(android.R.string.cancel, null)
.show();
return true;
}
}
private class TrimLengthValidationListener implements Preference.OnPreferenceChangeListener {
TrimLengthValidationListener() {
EditTextPreference preference = (EditTextPreference)findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH);
onPreferenceChange(preference, preference.getText());
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue == null || ((String)newValue).trim().length() == 0) {
return false;
}
int value;
try {
value = Integer.parseInt((String)newValue);
} catch (NumberFormatException nfe) {
Log.w(TAG, nfe);
return false;
}
if (value < 1) {
return false;
}
preference.setSummary(getResources().getQuantityString(R.plurals.ApplicationPreferencesActivity_messages_per_conversation, value, value));
return true;
}
}
}

View File

@@ -0,0 +1,251 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceViewHolder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.takisoft.colorpicker.ColorPickerDialog;
import com.takisoft.colorpicker.ColorPickerDialog.Size;
import com.takisoft.colorpicker.ColorStateDrawable;
import org.thoughtcrime.securesms.R;
public class ColorPickerPreference extends DialogPreference {
private static final String TAG = ColorPickerPreference.class.getSimpleName();
private int[] colors;
private CharSequence[] colorDescriptions;
private int color;
private int columns;
private int size;
private boolean sortColors;
private ImageView colorWidget;
private OnPreferenceChangeListener listener;
public ColorPickerPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorPickerPreference, defStyleAttr, 0);
int colorsId = a.getResourceId(R.styleable.ColorPickerPreference_colors, R.array.color_picker_default_colors);
if (colorsId != 0) {
colors = context.getResources().getIntArray(colorsId);
}
colorDescriptions = a.getTextArray(R.styleable.ColorPickerPreference_colorDescriptions);
color = a.getColor(R.styleable.ColorPickerPreference_currentColor, 0);
columns = a.getInt(R.styleable.ColorPickerPreference_columns, 3);
size = a.getInt(R.styleable.ColorPickerPreference_colorSize, 2);
sortColors = a.getBoolean(R.styleable.ColorPickerPreference_sortColors, false);
a.recycle();
setWidgetLayoutResource(R.layout.preference_widget_color_swatch);
}
public ColorPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@SuppressLint("RestrictedApi")
public ColorPickerPreference(Context context, AttributeSet attrs) {
this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.dialogPreferenceStyle,
android.R.attr.dialogPreferenceStyle));
}
public ColorPickerPreference(Context context) {
this(context, null);
}
@Override
public void setOnPreferenceChangeListener(OnPreferenceChangeListener listener) {
super.setOnPreferenceChangeListener(listener);
this.listener = listener;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
colorWidget = (ImageView) holder.findViewById(R.id.color_picker_widget);
setColorOnWidget(color);
}
private void setColorOnWidget(int color) {
if (colorWidget == null) {
return;
}
Drawable[] colorDrawable = new Drawable[]
{ContextCompat.getDrawable(getContext(), R.drawable.colorpickerpreference_pref_swatch)};
colorWidget.setImageDrawable(new ColorStateDrawable(colorDrawable, color));
}
/**
* Returns the current color.
*
* @return The current color.
*/
public int getColor() {
return color;
}
/**
* Sets the current color.
*
* @param color The current color.
*/
public void setColor(int color) {
setInternalColor(color, false);
}
/**
* Returns all of the available colors.
*
* @return The available colors.
*/
public int[] getColors() {
return colors;
}
/**
* Sets the available colors.
*
* @param colors The available colors.
*/
public void setColors(int[] colors) {
this.colors = colors;
}
/**
* Returns whether the available colors should be sorted automatically based on their HSV
* values.
*
* @return Whether the available colors should be sorted automatically based on their HSV
* values.
*/
public boolean isSortColors() {
return sortColors;
}
/**
* Sets whether the available colors should be sorted automatically based on their HSV
* values. The sorting does not modify the order of the original colors supplied via
* {@link #setColors(int[])} or the XML attribute {@code app:colors}.
*
* @param sortColors Whether the available colors should be sorted automatically based on their
* HSV values.
*/
public void setSortColors(boolean sortColors) {
this.sortColors = sortColors;
}
/**
* Returns the available colors' descriptions that can be used by accessibility services.
*
* @return The available colors' descriptions.
*/
public CharSequence[] getColorDescriptions() {
return colorDescriptions;
}
/**
* Sets the available colors' descriptions that can be used by accessibility services.
*
* @param colorDescriptions The available colors' descriptions.
*/
public void setColorDescriptions(CharSequence[] colorDescriptions) {
this.colorDescriptions = colorDescriptions;
}
/**
* Returns the number of columns to be used in the picker dialog for displaying the available
* colors. If the value is less than or equals to 0, the number of columns will be determined
* automatically by the system using FlexboxLayoutManager.
*
* @return The number of columns to be used in the picker dialog.
* @see com.google.android.flexbox.FlexboxLayoutManager
*/
public int getColumns() {
return columns;
}
/**
* Sets the number of columns to be used in the picker dialog for displaying the available
* colors. If the value is less than or equals to 0, the number of columns will be determined
* automatically by the system using FlexboxLayoutManager.
*
* @param columns The number of columns to be used in the picker dialog. Use 0 to set it to
* 'auto' mode.
* @see com.google.android.flexbox.FlexboxLayoutManager
*/
public void setColumns(int columns) {
this.columns = columns;
}
/**
* Returns the size of the color swatches in the dialog. It can be either
* {@link ColorPickerDialog#SIZE_SMALL} or {@link ColorPickerDialog#SIZE_LARGE}.
*
* @return The size of the color swatches in the dialog.
* @see ColorPickerDialog#SIZE_SMALL
* @see ColorPickerDialog#SIZE_LARGE
*/
@Size
public int getSize() {
return size;
}
/**
* Sets the size of the color swatches in the dialog. It can be either
* {@link ColorPickerDialog#SIZE_SMALL} or {@link ColorPickerDialog#SIZE_LARGE}.
*
* @param size The size of the color swatches in the dialog. It can be either
* {@link ColorPickerDialog#SIZE_SMALL} or {@link ColorPickerDialog#SIZE_LARGE}.
* @see ColorPickerDialog#SIZE_SMALL
* @see ColorPickerDialog#SIZE_LARGE
*/
public void setSize(@Size int size) {
this.size = size;
}
private void setInternalColor(int color, boolean force) {
int oldColor = getPersistedInt(0);
boolean changed = oldColor != color;
if (changed || force) {
this.color = color;
persistInt(color);
setColorOnWidget(color);
if (listener != null) listener.onPreferenceChange(this, color);
notifyChanged();
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValueObj) {
final String defaultValue = (String) defaultValueObj;
setInternalColor(restoreValue ? getPersistedInt(0) : (!TextUtils.isEmpty(defaultValue) ? Color.parseColor(defaultValue) : 0), true);
}
}

View File

@@ -0,0 +1,64 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceDialogFragmentCompat;
import com.takisoft.colorpicker.ColorPickerDialog;
import com.takisoft.colorpicker.OnColorSelectedListener;
public class ColorPickerPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat implements OnColorSelectedListener {
private int pickedColor;
public static ColorPickerPreferenceDialogFragmentCompat newInstance(String key) {
ColorPickerPreferenceDialogFragmentCompat fragment = new ColorPickerPreferenceDialogFragmentCompat();
Bundle b = new Bundle(1);
b.putString(PreferenceDialogFragmentCompat.ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ColorPickerPreference pref = getColorPickerPreference();
ColorPickerDialog.Params params = new ColorPickerDialog.Params.Builder(getContext())
.setSelectedColor(pref.getColor())
.setColors(pref.getColors())
.setColorContentDescriptions(pref.getColorDescriptions())
.setSize(pref.getSize())
.setSortColors(pref.isSortColors())
.setColumns(pref.getColumns())
.build();
ColorPickerDialog dialog = new ColorPickerDialog(getActivity(), this, params);
dialog.setTitle(pref.getDialogTitle());
return dialog;
}
@Override
public void onDialogClosed(boolean positiveResult) {
ColorPickerPreference preference = getColorPickerPreference();
if (positiveResult) {
preference.setColor(pickedColor);
}
}
@Override
public void onColorSelected(int color) {
this.pickedColor = color;
super.onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
}
ColorPickerPreference getColorPickerPreference() {
return (ColorPickerPreference) getPreference();
}
}

View File

@@ -0,0 +1,98 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import android.graphics.PorterDuff;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import org.thoughtcrime.securesms.R;
public class ContactPreference extends Preference {
private ImageView messageButton;
private ImageView callButton;
private ImageView secureCallButton;
private ImageView secureVideoButton;
private Listener listener;
private boolean secure;
public ContactPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
public ContactPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public ContactPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public ContactPreference(Context context) {
super(context);
initialize();
}
private void initialize() {
setWidgetLayoutResource(R.layout.recipient_preference_contact_widget);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
this.messageButton = (ImageView) view.findViewById(R.id.message);
this.callButton = (ImageView) view.findViewById(R.id.call);
this.secureCallButton = (ImageView) view.findViewById(R.id.secure_call);
this.secureVideoButton = (ImageView) view.findViewById(R.id.secure_video);
if (listener != null) setListener(listener);
setSecure(secure);
}
public void setSecure(boolean secure) {
this.secure = secure;
if (secureCallButton != null) secureCallButton.setVisibility(secure ? View.VISIBLE : View.GONE);
if (secureVideoButton != null) secureVideoButton.setVisibility(secure ? View.VISIBLE : View.GONE);
if (callButton != null) callButton.setVisibility(secure ? View.GONE : View.VISIBLE);
int color;
if (secure) {
color = getContext().getResources().getColor(R.color.textsecure_primary);
} else {
color = getContext().getResources().getColor(R.color.grey_600);
}
if (messageButton != null) messageButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
if (secureCallButton != null) secureCallButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
if (secureVideoButton != null) secureVideoButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
if (callButton != null) callButton.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
public void setListener(Listener listener) {
this.listener = listener;
if (this.messageButton != null) this.messageButton.setOnClickListener(v -> listener.onMessageClicked());
if (this.secureCallButton != null) this.secureCallButton.setOnClickListener(v -> listener.onSecureCallClicked());
if (this.secureVideoButton != null) this.secureVideoButton.setOnClickListener(v -> listener.onSecureVideoClicked());
if (this.callButton != null) this.callButton.setOnClickListener(v -> listener.onInSecureCallClicked());
}
public interface Listener {
public void onMessageClicked();
public void onSecureCallClicked();
public void onSecureVideoClicked();
public void onInSecureCallClicked();
}
}

View File

@@ -0,0 +1,107 @@
/**
* Copyright (C) 2017 Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import androidx.annotation.NonNull;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.widget.ImageView;
import org.thoughtcrime.securesms.R;
/**
* List preference that disables dependents when set to "none", similar to a CheckBoxPreference.
*
* @author Taylor Kline
*/
public class LEDColorListPreference extends ListPreference {
private static final String TAG = LEDColorListPreference.class.getSimpleName();
private ImageView colorImageView;
public LEDColorListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setWidgetLayoutResource(R.layout.led_color_preference_widget);
}
public LEDColorListPreference(Context context) {
super(context);
setWidgetLayoutResource(R.layout.led_color_preference_widget);
}
@Override
public void setValue(String value) {
CharSequence oldEntry = getEntry();
super.setValue(value);
CharSequence newEntry = getEntry();
if (oldEntry != newEntry) {
notifyDependencyChange(shouldDisableDependents());
}
if (value != null) setPreviewColor(value);
}
@Override
public boolean shouldDisableDependents() {
CharSequence newEntry = getValue();
boolean shouldDisable = newEntry.equals("none");
return shouldDisable || super.shouldDisableDependents();
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
this.colorImageView = (ImageView)view.findViewById(R.id.color_view);
setPreviewColor(getValue());
}
@Override
public void setSummary(CharSequence summary) {
super.setSummary(null);
}
private void setPreviewColor(@NonNull String value) {
int color;
switch (value) {
case "green": color = getContext().getResources().getColor(R.color.green_500); break;
case "red": color = getContext().getResources().getColor(R.color.red_500); break;
case "blue": color = getContext().getResources().getColor(R.color.blue_500); break;
case "yellow": color = getContext().getResources().getColor(R.color.yellow_500); break;
case "cyan": color = getContext().getResources().getColor(R.color.cyan_500); break;
case "magenta": color = getContext().getResources().getColor(R.color.pink_500); break;
case "white": color = getContext().getResources().getColor(R.color.white); break;
default: color = getContext().getResources().getColor(R.color.transparent); break;
}
if (colorImageView != null) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.OVAL);
drawable.setColor(color);
colorImageView.setImageDrawable(drawable);
}
}
}

View File

@@ -0,0 +1,19 @@
package org.thoughtcrime.securesms.preferences.widgets;
public class NotificationPrivacyPreference {
private final String preference;
public NotificationPrivacyPreference(String preference) {
this.preference = preference;
}
public boolean isDisplayContact() {
return "all".equals(preference) || "contact".equals(preference);
}
public boolean isDisplayMessage() {
return "all".equals(preference);
}
}

View File

@@ -0,0 +1,84 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
public class ProfilePreference extends Preference {
private ImageView avatarView;
private TextView profileNameView;
private TextView profileSubtextView;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public ProfilePreference(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public ProfilePreference(Context context) {
super(context);
initialize();
}
private void initialize() {
setLayoutResource(R.layout.profile_preference_view);
}
@Override
public void onBindViewHolder(PreferenceViewHolder viewHolder) {
super.onBindViewHolder(viewHolder);
avatarView = (ImageView)viewHolder.findViewById(R.id.avatar);
profileNameView = (TextView)viewHolder.findViewById(R.id.profile_name);
profileSubtextView = (TextView)viewHolder.findViewById(R.id.number);
refresh();
}
public void refresh() {
if (profileSubtextView == null) return;
final Recipient self = Recipient.self();
final String profileName = TextSecurePreferences.getProfileName(getContext());
GlideApp.with(getContext().getApplicationContext())
.load(new ProfileContactPhoto(self.getId(), String.valueOf(TextSecurePreferences.getProfileAvatarId(getContext()))))
.error(new ResourceContactPhoto(R.drawable.ic_camera_solid_white_24).asDrawable(getContext(), getContext().getResources().getColor(R.color.grey_400)))
.circleCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(avatarView);
if (!TextUtils.isEmpty(profileName)) {
profileNameView.setText(profileName);
}
profileSubtextView.setText(self.getUsername().or(self.getE164()).orNull());
}
}

View File

@@ -0,0 +1,61 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
public class ProgressPreference extends Preference {
private View container;
private TextView progressText;
public ProgressPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
public ProgressPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public ProgressPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public ProgressPreference(Context context) {
super(context);
initialize();
}
private void initialize() {
setWidgetLayoutResource(R.layout.preference_widget_progress);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
this.container = view.findViewById(R.id.container);
this.progressText = (TextView) view.findViewById(R.id.progress_text);
this.container.setVisibility(View.GONE);
}
public void setProgress(int count) {
container.setVisibility(View.VISIBLE);
progressText.setText(getContext().getString(R.string.ProgressPreference_d_messages_so_far, count));
}
public void setProgressVisible(boolean visible) {
container.setVisibility(visible ? View.VISIBLE : View.GONE);
}
}

View File

@@ -0,0 +1,77 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
public class SignalListPreference extends ListPreference {
private TextView rightSummary;
private CharSequence summary;
private OnPreferenceClickListener clickListener;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public SignalListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public SignalListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public SignalListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public SignalListPreference(Context context) {
super(context);
initialize();
}
private void initialize() {
setWidgetLayoutResource(R.layout.preference_right_summary_widget);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
this.rightSummary = (TextView)view.findViewById(R.id.right_summary);
setSummary(this.summary);
}
@Override
public void setSummary(CharSequence summary) {
super.setSummary(null);
this.summary = summary;
if (this.rightSummary != null) {
this.rightSummary.setText(summary);
}
}
@Override
public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
this.clickListener = onPreferenceClickListener;
}
@Override
protected void onClick() {
if (clickListener == null || !clickListener.onPreferenceClick(this)) {
super.onClick();
}
}
}

View File

@@ -0,0 +1,60 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
public class SignalPreference extends Preference {
private TextView rightSummary;
private CharSequence summary;
public SignalPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
public SignalPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public SignalPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public SignalPreference(Context context) {
super(context);
initialize();
}
private void initialize() {
setWidgetLayoutResource(R.layout.preference_right_summary_widget);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
this.rightSummary = (TextView)view.findViewById(R.id.right_summary);
setSummary(this.summary);
}
@Override
public void setSummary(CharSequence summary) {
super.setSummary(null);
this.summary = summary;
if (this.rightSummary != null) {
this.rightSummary.setText(summary);
}
}
}

View File

@@ -0,0 +1,125 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import org.thoughtcrime.securesms.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class StorageGraphView extends View {
private final RectF rect = new RectF();
private final Path path = new Path();
private final Paint paint = new Paint();
@NonNull private StorageBreakdown storageBreakdown;
private StorageBreakdown emptyBreakdown;
public StorageGraphView(Context context) {
super(context);
initialize();
}
public StorageGraphView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initialize();
}
public StorageGraphView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
private void initialize() {
setWillNotDraw(false);
paint.setStyle(Paint.Style.FILL);
Entry emptyEntry = new Entry(ContextCompat.getColor(getContext(), R.color.storage_color_empty), 1);
emptyBreakdown = new StorageBreakdown(Collections.singletonList(emptyEntry));
setStorageBreakdown(emptyBreakdown);
}
public void setStorageBreakdown(@NonNull StorageBreakdown storageBreakdown) {
if (storageBreakdown.totalSize == 0) {
storageBreakdown = emptyBreakdown;
}
this.storageBreakdown = storageBreakdown;
invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int radius = getHeight() / 2;
rect.set(0, 0, w, h);
path.reset();
path.addRoundRect(rect, radius, radius, Path.Direction.CW);
}
@Override
protected void onDraw(Canvas canvas) {
if (storageBreakdown.totalSize == 0) return;
canvas.clipPath(path);
int startX = 0;
int entryCount = storageBreakdown.entries.size();
int width = getWidth();
for (int i = 0; i < entryCount; i++) {
Entry entry = storageBreakdown.entries.get(i);
int endX = i < entryCount - 1 ? startX + (int) (width * entry.size / storageBreakdown.totalSize)
: width;
rect.left = startX;
rect.right = endX;
paint.setColor(entry.color);
canvas.drawRect(rect, paint);
startX = endX;
}
}
public static class StorageBreakdown {
private final List<Entry> entries;
private final long totalSize;
public StorageBreakdown(@NonNull List<Entry> entries) {
this.entries = new ArrayList<>(entries);
long total = 0;
for (Entry entry : entries) {
total += entry.size;
}
this.totalSize = total;
}
long getTotalSize() {
return totalSize;
}
}
public static class Entry {
@ColorInt private final int color;
private final long size;
public Entry(@ColorInt int color, long size) {
this.color = color;
this.size = size;
}
}
}

View File

@@ -0,0 +1,73 @@
package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceViewHolder;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.Util;
public final class StoragePreferenceCategory extends PreferenceCategory {
private Runnable onFreeUpSpace;
private TextView totalSize;
private StorageGraphView storageGraphView;
private StorageGraphView.StorageBreakdown storage;
public StoragePreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public StoragePreferenceCategory(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public StoragePreferenceCategory(Context context) {
super(context);
initialize();
}
private void initialize() {
setLayoutResource(R.layout.preference_storage_category);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
totalSize = (TextView) view.findViewById(R.id.total_size);
storageGraphView = (StorageGraphView) view.findViewById(R.id.storageGraphView);
view.findViewById(R.id.free_up_space)
.setOnClickListener(v -> {
if (onFreeUpSpace != null) {
onFreeUpSpace.run();
}
});
totalSize.setText(Util.getPrettyFileSize(0));
if (storage != null) {
setStorage(storage);
}
}
public void setOnFreeUpSpace(Runnable onFreeUpSpace) {
this.onFreeUpSpace = onFreeUpSpace;
}
public void setStorage(StorageGraphView.StorageBreakdown storage) {
this.storage = storage;
if (totalSize != null) {
totalSize.setText(Util.getPrettyFileSize(storage.getTotalSize()));
}
if (storageGraphView != null) {
storageGraphView.setStorageBreakdown(storage);
}
}
}