SettingsActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.app.AlertDialog;
  4import android.app.FragmentManager;
  5import android.content.DialogInterface;
  6import android.content.Intent;
  7import android.content.SharedPreferences;
  8import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
  9import android.content.pm.PackageManager;
 10import android.os.Build;
 11import android.os.Bundle;
 12import android.preference.ListPreference;
 13import android.preference.Preference;
 14import android.preference.PreferenceCategory;
 15import android.preference.PreferenceManager;
 16import android.preference.PreferenceScreen;
 17import android.widget.Toast;
 18
 19import java.security.KeyStoreException;
 20import java.util.ArrayList;
 21import java.util.Arrays;
 22import java.util.Collections;
 23import java.util.List;
 24import java.util.Locale;
 25
 26import de.duenndns.ssl.MemorizingTrustManager;
 27import eu.siacs.conversations.Config;
 28import eu.siacs.conversations.R;
 29import eu.siacs.conversations.entities.Account;
 30import eu.siacs.conversations.services.ExportLogsService;
 31import eu.siacs.conversations.xmpp.XmppConnection;
 32import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 33import eu.siacs.conversations.xmpp.jid.Jid;
 34
 35public class SettingsActivity extends XmppActivity implements
 36		OnSharedPreferenceChangeListener {
 37
 38	public static final String KEEP_FOREGROUND_SERVICE = "keep_foreground_service";
 39	public static final String AWAY_WHEN_SCREEN_IS_OFF = "away_when_screen_off";
 40	public static final String TREAT_VIBRATE_AS_SILENT = "treat_vibrate_as_silent";
 41	public static final String MANUALLY_CHANGE_PRESENCE = "manually_change_presence";
 42
 43	public static final int REQUEST_WRITE_LOGS = 0xbf8701;
 44	private SettingsFragment mSettingsFragment;
 45
 46	@Override
 47	protected void onCreate(Bundle savedInstanceState) {
 48		super.onCreate(savedInstanceState);
 49		FragmentManager fm = getFragmentManager();
 50		mSettingsFragment = (SettingsFragment) fm.findFragmentById(android.R.id.content);
 51		if (mSettingsFragment == null || !mSettingsFragment.getClass().equals(SettingsFragment.class)) {
 52			mSettingsFragment = new SettingsFragment();
 53			fm.beginTransaction().replace(android.R.id.content, mSettingsFragment).commit();
 54		}
 55
 56		this.mTheme = findTheme();
 57		setTheme(this.mTheme);
 58
 59		int bgcolor = getPrimaryBackgroundColor();
 60		getWindow().getDecorView().setBackgroundColor(bgcolor);
 61
 62	}
 63
 64	@Override
 65	void onBackendConnected() {
 66
 67	}
 68
 69	@Override
 70	public void onStart() {
 71		super.onStart();
 72		PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
 73		ListPreference resources = (ListPreference) mSettingsFragment.findPreference("resource");
 74		if (resources != null) {
 75			ArrayList<CharSequence> entries = new ArrayList<>(Arrays.asList(resources.getEntries()));
 76			if (!entries.contains(Build.MODEL)) {
 77				entries.add(0, Build.MODEL);
 78				resources.setEntries(entries.toArray(new CharSequence[entries.size()]));
 79				resources.setEntryValues(entries.toArray(new CharSequence[entries.size()]));
 80			}
 81		}
 82
 83		if (Config.FORCE_ORBOT) {
 84			PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options");
 85			PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert");
 86			if (connectionOptions != null) {
 87				expert.removePreference(connectionOptions);
 88			}
 89		}
 90
 91		final Preference removeCertsPreference = mSettingsFragment.findPreference("remove_trusted_certificates");
 92		removeCertsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
 93			@Override
 94			public boolean onPreferenceClick(Preference preference) {
 95				final MemorizingTrustManager mtm = xmppConnectionService.getMemorizingTrustManager();
 96				final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
 97				if (aliases.size() == 0) {
 98					displayToast(getString(R.string.toast_no_trusted_certs));
 99					return true;
100				}
101				final ArrayList selectedItems = new ArrayList<>();
102				final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(SettingsActivity.this);
103				dialogBuilder.setTitle(getResources().getString(R.string.dialog_manage_certs_title));
104				dialogBuilder.setMultiChoiceItems(aliases.toArray(new CharSequence[aliases.size()]), null,
105						new DialogInterface.OnMultiChoiceClickListener() {
106							@Override
107							public void onClick(DialogInterface dialog, int indexSelected,
108												boolean isChecked) {
109								if (isChecked) {
110									selectedItems.add(indexSelected);
111								} else if (selectedItems.contains(indexSelected)) {
112									selectedItems.remove(Integer.valueOf(indexSelected));
113								}
114								if (selectedItems.size() > 0)
115									((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
116								else {
117									((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
118								}
119							}
120						});
121
122				dialogBuilder.setPositiveButton(
123						getResources().getString(R.string.dialog_manage_certs_positivebutton), new DialogInterface.OnClickListener() {
124							@Override
125							public void onClick(DialogInterface dialog, int which) {
126								int count = selectedItems.size();
127								if (count > 0) {
128									for (int i = 0; i < count; i++) {
129										try {
130											Integer item = Integer.valueOf(selectedItems.get(i).toString());
131											String alias = aliases.get(item);
132											mtm.deleteCertificate(alias);
133										} catch (KeyStoreException e) {
134											e.printStackTrace();
135											displayToast("Error: " + e.getLocalizedMessage());
136										}
137									}
138									if (xmppConnectionServiceBound) {
139										reconnectAccounts();
140									}
141									displayToast(getResources().getQuantityString(R.plurals.toast_delete_certificates, count, count));
142								}
143							}
144						});
145				dialogBuilder.setNegativeButton(getResources().getString(R.string.dialog_manage_certs_negativebutton), null);
146				AlertDialog removeCertsDialog = dialogBuilder.create();
147				removeCertsDialog.show();
148				removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
149				return true;
150			}
151		});
152
153		final Preference exportLogsPreference = mSettingsFragment.findPreference("export_logs");
154		exportLogsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
155			@Override
156			public boolean onPreferenceClick(Preference preference) {
157				if (hasStoragePermission(REQUEST_WRITE_LOGS)) {
158					startExport();
159				}
160				return true;
161			}
162		});
163
164		final Preference deleteOmemoPreference = mSettingsFragment.findPreference("delete_omemo_identities");
165		deleteOmemoPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
166			@Override
167			public boolean onPreferenceClick(Preference preference) {
168				deleteOmemoIdentities();
169				return true;
170			}
171		});
172	}
173
174	private void deleteOmemoIdentities() {
175		AlertDialog.Builder builder = new AlertDialog.Builder(this);
176		builder.setTitle(R.string.pref_delete_omemo_identities);
177		final List<CharSequence> accounts = new ArrayList<>();
178		for(Account account : xmppConnectionService.getAccounts()) {
179			if (!account.isOptionSet(Account.OPTION_DISABLED)) {
180				accounts.add(account.getJid().toBareJid().toString());
181			}
182		}
183		final boolean[] checkedItems = new boolean[accounts.size()];
184		builder.setMultiChoiceItems(accounts.toArray(new CharSequence[accounts.size()]), checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
185			@Override
186			public void onClick(DialogInterface dialog, int which, boolean isChecked) {
187				checkedItems[which] = isChecked;
188				final AlertDialog alertDialog = (AlertDialog) dialog;
189				for(boolean item : checkedItems) {
190					if (item) {
191						alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
192						return;
193					}
194				}
195				alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
196			}
197		});
198		builder.setNegativeButton(R.string.cancel,null);
199		builder.setPositiveButton(R.string.delete_selected_keys, new DialogInterface.OnClickListener() {
200			@Override
201			public void onClick(DialogInterface dialog, int which) {
202				for(int i = 0; i < checkedItems.length; ++i) {
203					if (checkedItems[i]) {
204						try {
205							Jid jid = Jid.fromString(accounts.get(i).toString());
206							Account account = xmppConnectionService.findAccountByJid(jid);
207							if (account != null) {
208								account.getAxolotlService().regenerateKeys(true);
209							}
210						} catch (InvalidJidException e) {
211							//
212						}
213
214					}
215				}
216			}
217		});
218		AlertDialog dialog = builder.create();
219		dialog.show();
220		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
221	}
222
223	@Override
224	public void onStop() {
225		super.onStop();
226		PreferenceManager.getDefaultSharedPreferences(this)
227				.unregisterOnSharedPreferenceChangeListener(this);
228	}
229
230	@Override
231	public void onSharedPreferenceChanged(SharedPreferences preferences, String name) {
232		final List<String> resendPresence = Arrays.asList(
233				"confirm_messages",
234				"xa_on_silent_mode",
235				AWAY_WHEN_SCREEN_IS_OFF,
236				"allow_message_correction",
237				TREAT_VIBRATE_AS_SILENT,
238				MANUALLY_CHANGE_PRESENCE,
239				"last_activity");
240		if (name.equals("resource")) {
241			String resource = preferences.getString("resource", "mobile")
242					.toLowerCase(Locale.US);
243			if (xmppConnectionServiceBound) {
244				for (Account account : xmppConnectionService.getAccounts()) {
245					if (account.setResource(resource)) {
246						if (!account.isOptionSet(Account.OPTION_DISABLED)) {
247							XmppConnection connection = account.getXmppConnection();
248							if (connection != null) {
249								connection.resetStreamId();
250							}
251							xmppConnectionService.reconnectAccountInBackground(account);
252						}
253					}
254				}
255			}
256		} else if (name.equals(KEEP_FOREGROUND_SERVICE)) {
257			boolean foreground_service = preferences.getBoolean(KEEP_FOREGROUND_SERVICE,false);
258			if (!foreground_service) {
259				xmppConnectionService.clearStartTimeCounter();
260			}
261			xmppConnectionService.toggleForegroundService();
262		} else if (resendPresence.contains(name)) {
263			if (xmppConnectionServiceBound) {
264				if (name.equals(AWAY_WHEN_SCREEN_IS_OFF) || name.equals(MANUALLY_CHANGE_PRESENCE)) {
265					xmppConnectionService.toggleScreenEventReceiver();
266				}
267				if (name.equals(MANUALLY_CHANGE_PRESENCE) && !noAccountUsesPgp()) {
268					Toast.makeText(this, R.string.republish_pgp_keys, Toast.LENGTH_LONG).show();
269				}
270				xmppConnectionService.refreshAllPresences();
271			}
272		} else if (name.equals("dont_trust_system_cas")) {
273			xmppConnectionService.updateMemorizingTrustmanager();
274			reconnectAccounts();
275		} else if (name.equals("use_tor")) {
276			reconnectAccounts();
277		}
278
279	}
280
281	@Override
282	public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
283		if (grantResults.length > 0)
284			if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
285				if (requestCode == REQUEST_WRITE_LOGS) {
286					startExport();
287				}
288			} else {
289				Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
290			}
291	}
292
293	private void startExport() {
294		startService(new Intent(getApplicationContext(), ExportLogsService.class));
295	}
296
297	private void displayToast(final String msg) {
298		runOnUiThread(new Runnable() {
299			@Override
300			public void run() {
301				Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show();
302			}
303		});
304	}
305
306	private void reconnectAccounts() {
307		for (Account account : xmppConnectionService.getAccounts()) {
308			if (!account.isOptionSet(Account.OPTION_DISABLED)) {
309				xmppConnectionService.reconnectAccountInBackground(account);
310			}
311		}
312	}
313
314	public void refreshUiReal() {
315		//nothing to do. This Activity doesn't implement any listeners
316	}
317
318}