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				hasStoragePermission(REQUEST_WRITE_LOGS);
153				return true;
154			}
155		});
156
157		final Preference deleteOmemoPreference = mSettingsFragment.findPreference("delete_omemo_identities");
158		deleteOmemoPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
159			@Override
160			public boolean onPreferenceClick(Preference preference) {
161				deleteOmemoIdentities();
162				return true;
163			}
164		});
165	}
166
167	private void deleteOmemoIdentities() {
168		AlertDialog.Builder builder = new AlertDialog.Builder(this);
169		builder.setTitle(R.string.pref_delete_omemo_identities);
170		final List<CharSequence> accounts = new ArrayList<>();
171		for(Account account : xmppConnectionService.getAccounts()) {
172			if (!account.isOptionSet(Account.OPTION_DISABLED)) {
173				accounts.add(account.getJid().toBareJid().toString());
174			}
175		}
176		final boolean[] checkedItems = new boolean[accounts.size()];
177		builder.setMultiChoiceItems(accounts.toArray(new CharSequence[accounts.size()]), checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
178			@Override
179			public void onClick(DialogInterface dialog, int which, boolean isChecked) {
180				checkedItems[which] = isChecked;
181				final AlertDialog alertDialog = (AlertDialog) dialog;
182				for(boolean item : checkedItems) {
183					if (item) {
184						alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
185						return;
186					}
187				}
188				alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
189			}
190		});
191		builder.setNegativeButton(R.string.cancel,null);
192		builder.setPositiveButton(R.string.delete_selected_keys, new DialogInterface.OnClickListener() {
193			@Override
194			public void onClick(DialogInterface dialog, int which) {
195				for(int i = 0; i < checkedItems.length; ++i) {
196					if (checkedItems[i]) {
197						try {
198							Jid jid = Jid.fromString(accounts.get(i).toString());
199							Account account = xmppConnectionService.findAccountByJid(jid);
200							if (account != null) {
201								account.getAxolotlService().regenerateKeys(true);
202							}
203						} catch (InvalidJidException e) {
204							//
205						}
206
207					}
208				}
209			}
210		});
211		AlertDialog dialog = builder.create();
212		dialog.show();
213		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
214	}
215
216	@Override
217	public void onStop() {
218		super.onStop();
219		PreferenceManager.getDefaultSharedPreferences(this)
220				.unregisterOnSharedPreferenceChangeListener(this);
221	}
222
223	@Override
224	public void onSharedPreferenceChanged(SharedPreferences preferences, String name) {
225		final List<String> resendPresence = Arrays.asList(
226				"confirm_messages",
227				"xa_on_silent_mode",
228				"away_when_screen_off",
229				"allow_message_correction",
230				"treat_vibrate_as_silent",
231				"manually_change_presence",
232				"last_activity");
233		if (name.equals("resource")) {
234			String resource = preferences.getString("resource", "mobile")
235					.toLowerCase(Locale.US);
236			if (xmppConnectionServiceBound) {
237				for (Account account : xmppConnectionService.getAccounts()) {
238					if (account.setResource(resource)) {
239						if (!account.isOptionSet(Account.OPTION_DISABLED)) {
240							XmppConnection connection = account.getXmppConnection();
241							if (connection != null) {
242								connection.resetStreamId();
243							}
244							xmppConnectionService.reconnectAccountInBackground(account);
245						}
246					}
247				}
248			}
249		} else if (name.equals("keep_foreground_service")) {
250			xmppConnectionService.toggleForegroundService();
251		} else if (resendPresence.contains(name)) {
252			if (xmppConnectionServiceBound) {
253				if (name.equals("away_when_screen_off")
254						|| name.equals("manually_change_presence")) {
255					xmppConnectionService.toggleScreenEventReceiver();
256				}
257				if (name.equals("manually_change_presence") && !noAccountUsesPgp()) {
258					Toast.makeText(this, R.string.republish_pgp_keys, Toast.LENGTH_LONG).show();
259				}
260				xmppConnectionService.refreshAllPresences();
261			}
262		} else if (name.equals("dont_trust_system_cas")) {
263			xmppConnectionService.updateMemorizingTrustmanager();
264			reconnectAccounts();
265		} else if (name.equals("use_tor")) {
266			reconnectAccounts();
267		}
268
269	}
270
271	@Override
272	public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
273		if (grantResults.length > 0)
274			if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
275				if (requestCode == REQUEST_WRITE_LOGS) {
276					getApplicationContext().startService(new Intent(getApplicationContext(), ExportLogsService.class));
277				}
278			} else {
279				Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
280			}
281	}
282
283	private void displayToast(final String msg) {
284		runOnUiThread(new Runnable() {
285			@Override
286			public void run() {
287				Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show();
288			}
289		});
290	}
291
292	private void reconnectAccounts() {
293		for (Account account : xmppConnectionService.getAccounts()) {
294			if (!account.isOptionSet(Account.OPTION_DISABLED)) {
295				xmppConnectionService.reconnectAccountInBackground(account);
296			}
297		}
298	}
299
300	public void refreshUiReal() {
301		//nothing to do. This Activity doesn't implement any listeners
302	}
303
304}