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