mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Move all files to natural position.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user