Newer
Older
package org.briarproject.android.fragment;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import org.briarproject.android.SettingsActivity;
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.android.widget.PreferenceDividerDecoration;
import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.SettingsUpdatedEvent;
import org.briarproject.api.settings.Settings;
import org.briarproject.util.StringUtils;
import java.util.logging.Logger;
import static android.app.Activity.RESULT_OK;
import static android.media.RingtoneManager.ACTION_RINGTONE_PICKER;
import static android.media.RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_EXISTING_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_PICKED_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT;
import static android.media.RingtoneManager.EXTRA_RINGTONE_TITLE;
import static android.media.RingtoneManager.EXTRA_RINGTONE_TYPE;
import static android.media.RingtoneManager.TYPE_NOTIFICATION;
import static android.provider.Settings.System.DEFAULT_NOTIFICATION_URI;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
public class SettingsFragment extends PreferenceFragmentCompat
implements EventListener, Preference.OnPreferenceChangeListener {
public static final int REQUEST_RINGTONE = 2;
public static final String SETTINGS_NAMESPACE = "android-ui";
private static final Logger LOG =
Logger.getLogger(SettingsFragment.class.getName());
private AndroidExecutor androidExecutor;
private ListPreference enableBluetooth;
private ListPreference torOverMobile;
private CheckBoxPreference notifyPrivateMessages;
private CheckBoxPreference notifyForumPosts;
private CheckBoxPreference notifyVibration;
private Preference notifySound;
// Fields that are accessed from background threads must be volatile
private volatile SettingsManager settingsManager;
private volatile EventBus eventBus;
private volatile Settings settings;
private volatile boolean bluetoothSetting = false, torSetting = false;
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (SettingsActivity) context;
androidExecutor = listener.getAndroidExecutor();
settingsManager = listener.getSettingsManager();
eventBus = listener.getEventBus();
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " is not a SettingsActivity");
}
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
public void onCreatePreferences(Bundle bundle, String s) {
addPreferencesFromResource(R.xml.settings);
enableBluetooth =
(ListPreference) findPreference("pref_key_bluetooth");
torOverMobile =
(ListPreference) findPreference("pref_key_tor_mobile");
notifyPrivateMessages = (CheckBoxPreference) findPreference(
"pref_key_notify_private_messages");
notifyForumPosts = (CheckBoxPreference) findPreference(
"pref_key_notify_forum_posts");
notifyVibration = (CheckBoxPreference) findPreference(
"pref_key_notify_vibration");
notifySound = findPreference("pref_key_notify_sound");
enableBluetooth.setOnPreferenceChangeListener(this);
torOverMobile.setOnPreferenceChangeListener(this);
notifyPrivateMessages.setOnPreferenceChangeListener(this);
notifyForumPosts.setOnPreferenceChangeListener(this);
notifyVibration.setOnPreferenceChangeListener(this);
notifySound.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
String title =
getString(R.string.choose_ringtone_title);
Intent i = new Intent(ACTION_RINGTONE_PICKER);
i.putExtra(EXTRA_RINGTONE_TYPE, TYPE_NOTIFICATION);
i.putExtra(EXTRA_RINGTONE_TITLE, title);
i.putExtra(EXTRA_RINGTONE_DEFAULT_URI,
DEFAULT_NOTIFICATION_URI);
i.putExtra(EXTRA_RINGTONE_SHOW_SILENT, true);
if (settings.getBoolean("notifySound", true)) {
Uri uri;
String ringtoneUri =
settings.get("notifyRingtoneUri");
if (StringUtils.isNullOrEmpty(ringtoneUri))
uri = DEFAULT_NOTIFICATION_URI;
else uri = Uri.parse(ringtoneUri);
i.putExtra(EXTRA_RINGTONE_EXISTING_URI, uri);
}
startActivityForResult(i, REQUEST_RINGTONE);
return true;
}
});
findPreference("pref_key_send_feedback").setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
triggerFeedback();
return true;
}
});
loadSettings();
}
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater,
ViewGroup parent, Bundle savedInstanceState) {
RecyclerView list = super.onCreateRecyclerView(inflater, parent,
savedInstanceState);
list.addItemDecoration(
new PreferenceDividerDecoration(getContext()).drawBottom(true));
return list;
}
@Override
public void onResume() {
super.onResume();
eventBus.addListener(this);
}
@Override
public void onPause() {
super.onPause();
eventBus.removeListener(this);
}
private void loadSettings() {
listener.runOnDbThread(new Runnable() {
public void run() {
try {
settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings btSettings = settingsManager.getSettings("bt");
Settings torSettings = settingsManager.getSettings("tor");
long duration = System.currentTimeMillis() - now;
LOG.info("Loading settings took " + duration + " ms");
bluetoothSetting = btSettings.getBoolean("enable", false);
torSetting = torSettings.getBoolean("torOverMobile", true);
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
listener.runOnUiThread(new Runnable() {
public void run() {
enableBluetooth.setValue(Boolean.toString(bluetoothSetting));
torOverMobile.setValue(Boolean.toString(torSetting));
notifyPrivateMessages.setChecked(settings.getBoolean(
"notifyPrivateMessages", true));
notifyForumPosts.setChecked(settings.getBoolean(
"notifyForumPosts", true));
notifyVibration.setChecked(settings.getBoolean(
"notifyVibration", true));
if (settings.getBoolean("notifySound", true)) {
String ringtoneName = settings.get("notifyRingtoneName");
if (StringUtils.isNullOrEmpty(ringtoneName)) {
text = getString(R.string.notify_sound_setting_default);
} else {
text = ringtoneName;
}
} else {
text = getString(R.string.notify_sound_setting_disabled);
}
}
});
}
androidExecutor.execute(new Runnable() {
ACRA.getErrorReporter().handleException(new UserFeedback(),
false);
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
if (preference == enableBluetooth) {
bluetoothSetting = Boolean.valueOf((String) o);
enableOrDisableBluetooth(bluetoothSetting);
} else if (preference == torOverMobile) {
torSetting = Boolean.valueOf((String) o);
storeTorSettings();
} else if (preference == notifyPrivateMessages) {
s.putBoolean("notifyPrivateMessages", (Boolean) o);
} else if (preference == notifyForumPosts) {
s.putBoolean("notifyForumPosts", (Boolean) o);
} else if (preference == notifyVibration) {
s.putBoolean("notifyVibration", (Boolean) o);
}
private void enableOrDisableBluetooth(final boolean enable) {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
androidExecutor.execute(new Runnable() {
public void run() {
if (enable) adapter.enable();
else adapter.disable();
}
});
}
}
private void storeTorSettings() {
listener.runOnDbThread(new Runnable() {
public void run() {
try {
s.putBoolean("torOverMobile", torSetting);
long now = System.currentTimeMillis();
settingsManager.mergeSettings(s, "tor");
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
listener.runOnDbThread(new Runnable() {
public void run() {
try {
Settings s = new Settings();
s.putBoolean("enable", bluetoothSetting);
settingsManager.mergeSettings(s, "bt");
long duration = System.currentTimeMillis() - now;
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
private void storeSettings(final Settings settings) {
listener.runOnDbThread(new Runnable() {
public void run() {
try {
long now = System.currentTimeMillis();
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
long duration = System.currentTimeMillis() - now;
LOG.info("Merging settings took " + duration + " ms");
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
@Override
public void onActivityResult(int request, int result, Intent data) {
super.onActivityResult(request, result, data);
if (request == REQUEST_RINGTONE && result == RESULT_OK) {
Settings s = new Settings();
Uri uri = data.getParcelableExtra(EXTRA_RINGTONE_PICKED_URI);
// The user chose silence
s.putBoolean("notifySound", false);
s.put("notifyRingtoneName", "");
s.put("notifyRingtoneUri", "");
} else if (RingtoneManager.isDefault(uri)) {
// The user chose the default
s.putBoolean("notifySound", true);
s.put("notifyRingtoneName", "");
s.put("notifyRingtoneUri", "");
} else {
// The user chose a ringtone other than the default
Ringtone r = RingtoneManager.getRingtone(getContext(), uri);
String name = r.getTitle(getContext());
s.putBoolean("notifySound", true);
s.put("notifyRingtoneName", name);
s.put("notifyRingtoneUri", uri.toString());
}
storeSettings(s);
}
}
if (e instanceof SettingsUpdatedEvent) {
String namespace = ((SettingsUpdatedEvent) e).getNamespace();
if (namespace.equals("bt") || namespace.equals("tor")
|| namespace.equals(SETTINGS_NAMESPACE)) {
LOG.info("Settings updated");
loadSettings();
}