Files
briar/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java

363 lines
12 KiB
Java

package org.briarproject.android.fragment;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
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.acra.ACRA;
import org.briarproject.R;
import org.briarproject.android.SettingsActivity;
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.android.util.UserFeedback;
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.api.settings.SettingsManager;
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 SettingsActivity listener;
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");
}
}
@Override
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 {
long now = System.currentTimeMillis();
settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings btSettings = settingsManager.getSettings("bt");
Settings torSettings = settingsManager.getSettings("tor");
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading settings took " + duration + " ms");
bluetoothSetting = btSettings.getBoolean("enable", false);
torSetting = torSettings.getBoolean("torOverMobile", true);
displaySettings();
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
private void displaySettings() {
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));
String text;
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);
}
notifySound.setSummary(text);
}
});
}
private void triggerFeedback() {
androidExecutor.execute(new Runnable() {
public void run() {
ACRA.getErrorReporter().handleException(new UserFeedback(),
false);
}
});
}
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
if (preference == enableBluetooth) {
bluetoothSetting = Boolean.valueOf((String) o);
enableOrDisableBluetooth(bluetoothSetting);
storeBluetoothSettings();
} else if (preference == torOverMobile) {
torSetting = Boolean.valueOf((String) o);
storeTorSettings();
} else if (preference == notifyPrivateMessages) {
Settings s = new Settings();
s.putBoolean("notifyPrivateMessages", (Boolean) o);
storeSettings(s);
} else if (preference == notifyForumPosts) {
Settings s = new Settings();
s.putBoolean("notifyForumPosts", (Boolean) o);
storeSettings(s);
} else if (preference == notifyVibration) {
Settings s = new Settings();
s.putBoolean("notifyVibration", (Boolean) o);
storeSettings(s);
}
return true;
}
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 {
Settings s = new Settings();
s.putBoolean("torOverMobile", torSetting);
long now = System.currentTimeMillis();
settingsManager.mergeSettings(s, "tor");
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Merging settings took " + duration + " ms");
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
private void storeBluetoothSettings() {
listener.runOnDbThread(new Runnable() {
public void run() {
try {
Settings s = new Settings();
s.putBoolean("enable", bluetoothSetting);
long now = System.currentTimeMillis();
settingsManager.mergeSettings(s, "bt");
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Merging settings took " + duration + " ms");
} 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;
if (LOG.isLoggable(INFO))
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);
if (uri == null) {
// 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);
}
}
@Override
public void eventOccurred(Event e) {
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();
}
}
}
}