ManageAccountActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.ArrayList;
  4import java.util.List;
  5
  6import eu.siacs.conversations.R;
  7import eu.siacs.conversations.entities.Account;
  8import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
  9import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
 10import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
 11import eu.siacs.conversations.xmpp.XmppConnection;
 12import android.app.Activity;
 13import android.app.AlertDialog;
 14import android.content.Context;
 15import android.content.DialogInterface;
 16import android.content.DialogInterface.OnClickListener;
 17import android.content.Intent;
 18import android.os.Bundle;
 19import android.os.SystemClock;
 20import android.view.ActionMode;
 21import android.view.LayoutInflater;
 22import android.view.Menu;
 23import android.view.MenuInflater;
 24import android.view.MenuItem;
 25import android.view.View;
 26import android.view.ViewGroup;
 27import android.widget.AdapterView;
 28import android.widget.AdapterView.OnItemClickListener;
 29import android.widget.AdapterView.OnItemLongClickListener;
 30import android.widget.ArrayAdapter;
 31import android.widget.ListView;
 32import android.widget.TextView;
 33
 34public class ManageAccountActivity extends XmppActivity {
 35
 36	protected boolean isActionMode = false;
 37	protected ActionMode actionMode;
 38	protected Account selectedAccountForActionMode = null;
 39	protected ManageAccountActivity activity = this;
 40
 41	protected boolean firstrun = true;
 42
 43	protected List<Account> accountList = new ArrayList<Account>();
 44	protected ListView accountListView;
 45	protected ArrayAdapter<Account> accountListViewAdapter;
 46	protected OnAccountUpdate accountChanged = new OnAccountUpdate() {
 47
 48		@Override
 49		public void onAccountUpdate() {
 50			accountList.clear();
 51			accountList.addAll(xmppConnectionService.getAccounts());
 52			runOnUiThread(new Runnable() {
 53
 54				@Override
 55				public void run() {
 56					accountListViewAdapter.notifyDataSetChanged();
 57				}
 58			});
 59		}
 60	};
 61
 62	protected OnTLSExceptionReceived tlsExceptionReceived = new OnTLSExceptionReceived() {
 63
 64		@Override
 65		public void onTLSExceptionReceived(final String fingerprint,
 66				final Account account) {
 67			activity.runOnUiThread(new Runnable() {
 68
 69				@Override
 70				public void run() {
 71					AlertDialog.Builder builder = new AlertDialog.Builder(
 72							activity);
 73					builder.setTitle(getString(R.string.account_status_error));
 74					builder.setIconAttribute(android.R.attr.alertDialogIcon);
 75					View view = (View) getLayoutInflater().inflate(
 76							R.layout.cert_warning, null);
 77					TextView sha = (TextView) view.findViewById(R.id.sha);
 78					TextView hint = (TextView) view.findViewById(R.id.hint);
 79					StringBuilder humanReadableSha = new StringBuilder();
 80					humanReadableSha.append(fingerprint);
 81					for (int i = 2; i < 59; i += 3) {
 82						if ((i == 14) || (i == 29) || (i == 44)) {
 83							humanReadableSha.insert(i, "\n");
 84						} else {
 85							humanReadableSha.insert(i, ":");
 86						}
 87
 88					}
 89					hint.setText(getString(R.string.untrusted_cert_hint,
 90							account.getServer()));
 91					sha.setText(humanReadableSha.toString());
 92					builder.setView(view);
 93					builder.setNegativeButton(
 94							getString(R.string.certif_no_trust), null);
 95					builder.setPositiveButton(getString(R.string.certif_trust),
 96							new OnClickListener() {
 97
 98								@Override
 99								public void onClick(DialogInterface dialog,
100										int which) {
101									account.setSSLCertFingerprint(fingerprint);
102									activity.xmppConnectionService
103											.updateAccount(account);
104								}
105							});
106					builder.create().show();
107				}
108			});
109
110		}
111	};
112
113	@Override
114	protected void onCreate(Bundle savedInstanceState) {
115
116		super.onCreate(savedInstanceState);
117
118		setContentView(R.layout.manage_accounts);
119
120		accountListView = (ListView) findViewById(R.id.account_list);
121		accountListViewAdapter = new ArrayAdapter<Account>(
122				getApplicationContext(), R.layout.account_row, this.accountList) {
123			@Override
124			public View getView(int position, View view, ViewGroup parent) {
125				Account account = getItem(position);
126				if (view == null) {
127					LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
128					view = (View) inflater.inflate(R.layout.account_row, null);
129				}
130				((TextView) view.findViewById(R.id.account_jid))
131						.setText(account.getJid());
132				TextView statusView = (TextView) view
133						.findViewById(R.id.account_status);
134				switch (account.getStatus()) {
135				case Account.STATUS_DISABLED:
136					statusView
137							.setText(getString(R.string.account_status_disabled));
138					statusView.setTextColor(0xFF1da9da);
139					break;
140				case Account.STATUS_ONLINE:
141					statusView
142							.setText(getString(R.string.account_status_online));
143					statusView.setTextColor(0xFF83b600);
144					break;
145				case Account.STATUS_CONNECTING:
146					statusView
147							.setText(getString(R.string.account_status_connecting));
148					statusView.setTextColor(0xFF1da9da);
149					break;
150				case Account.STATUS_OFFLINE:
151					statusView
152							.setText(getString(R.string.account_status_offline));
153					statusView.setTextColor(0xFFe92727);
154					break;
155				case Account.STATUS_UNAUTHORIZED:
156					statusView
157							.setText(getString(R.string.account_status_unauthorized));
158					statusView.setTextColor(0xFFe92727);
159					break;
160				case Account.STATUS_SERVER_NOT_FOUND:
161					statusView
162							.setText(getString(R.string.account_status_not_found));
163					statusView.setTextColor(0xFFe92727);
164					break;
165				case Account.STATUS_NO_INTERNET:
166					statusView
167							.setText(getString(R.string.account_status_no_internet));
168					statusView.setTextColor(0xFFe92727);
169					break;
170				case Account.STATUS_SERVER_REQUIRES_TLS:
171					statusView
172							.setText(getString(R.string.account_status_requires_tls));
173					statusView.setTextColor(0xFFe92727);
174					break;
175				case Account.STATUS_TLS_ERROR:
176					statusView
177							.setText(getString(R.string.account_status_error));
178					statusView.setTextColor(0xFFe92727);
179					break;
180				case Account.STATUS_REGISTRATION_FAILED:
181					statusView
182							.setText(getString(R.string.account_status_regis_fail));
183					statusView.setTextColor(0xFFe92727);
184					break;
185				case Account.STATUS_REGISTRATION_CONFLICT:
186					statusView
187							.setText(getString(R.string.account_status_regis_conflict));
188					statusView.setTextColor(0xFFe92727);
189					break;
190				case Account.STATUS_REGISTRATION_SUCCESSFULL:
191					statusView
192							.setText(getString(R.string.account_status_regis_success));
193					statusView.setTextColor(0xFF83b600);
194					break;
195				case Account.STATUS_REGISTRATION_NOT_SUPPORTED:
196					statusView
197							.setText(getString(R.string.account_status_regis_not_sup));
198					statusView.setTextColor(0xFFe92727);
199					break;
200				default:
201					statusView.setText("");
202					break;
203				}
204
205				return view;
206			}
207		};
208		final XmppActivity activity = this;
209		accountListView.setAdapter(this.accountListViewAdapter);
210		accountListView.setOnItemClickListener(new OnItemClickListener() {
211
212			@Override
213			public void onItemClick(AdapterView<?> arg0, View view,
214					int position, long arg3) {
215				if (!isActionMode) {
216					Account account = accountList.get(position);
217					if ((account.getStatus() == Account.STATUS_OFFLINE)
218							|| (account.getStatus() == Account.STATUS_TLS_ERROR)) {
219						activity.xmppConnectionService.reconnectAccount(
220								accountList.get(position), true);
221					} else if (account.getStatus() == Account.STATUS_ONLINE) {
222						activity.startActivity(new Intent(activity
223								.getApplicationContext(),
224								StartConversation.class));
225					} else if (account.getStatus() != Account.STATUS_DISABLED) {
226						editAccount(account);
227					}
228				} else {
229					selectedAccountForActionMode = accountList.get(position);
230					actionMode.invalidate();
231				}
232			}
233		});
234		accountListView
235				.setOnItemLongClickListener(new OnItemLongClickListener() {
236
237					@Override
238					public boolean onItemLongClick(AdapterView<?> arg0,
239							View view, int position, long arg3) {
240						if (!isActionMode) {
241							accountListView
242									.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
243							accountListView.setItemChecked(position, true);
244							selectedAccountForActionMode = accountList
245									.get(position);
246							actionMode = activity
247									.startActionMode((new ActionMode.Callback() {
248
249										@Override
250										public boolean onPrepareActionMode(
251												ActionMode mode, Menu menu) {
252											if (selectedAccountForActionMode
253													.isOptionSet(Account.OPTION_DISABLED)) {
254												menu.findItem(
255														R.id.mgmt_account_enable)
256														.setVisible(true);
257												menu.findItem(
258														R.id.mgmt_account_disable)
259														.setVisible(false);
260											} else {
261												menu.findItem(
262														R.id.mgmt_account_disable)
263														.setVisible(true);
264												menu.findItem(
265														R.id.mgmt_account_enable)
266														.setVisible(false);
267											}
268											return true;
269										}
270
271										@Override
272										public void onDestroyActionMode(
273												ActionMode mode) {
274											// TODO Auto-generated method stub
275
276										}
277
278										@Override
279										public boolean onCreateActionMode(
280												ActionMode mode, Menu menu) {
281											MenuInflater inflater = mode
282													.getMenuInflater();
283											inflater.inflate(
284													R.menu.manageaccounts_context,
285													menu);
286											return true;
287										}
288
289										@Override
290										public boolean onActionItemClicked(
291												final ActionMode mode,
292												MenuItem item) {
293											if (item.getItemId() == R.id.mgmt_account_edit) {
294												editAccount(selectedAccountForActionMode);
295											} else if (item.getItemId() == R.id.mgmt_account_disable) {
296												selectedAccountForActionMode
297														.setOption(
298																Account.OPTION_DISABLED,
299																true);
300												xmppConnectionService
301														.updateAccount(selectedAccountForActionMode);
302												mode.finish();
303											} else if (item.getItemId() == R.id.mgmt_account_enable) {
304												selectedAccountForActionMode
305														.setOption(
306																Account.OPTION_DISABLED,
307																false);
308												xmppConnectionService
309														.updateAccount(selectedAccountForActionMode);
310												mode.finish();
311											} else if (item.getItemId() == R.id.mgmt_account_delete) {
312												AlertDialog.Builder builder = new AlertDialog.Builder(
313														activity);
314												builder.setTitle(getString(R.string.mgmt_account_are_you_sure));
315												builder.setIconAttribute(android.R.attr.alertDialogIcon);
316												builder.setMessage(getString(R.string.mgmt_account_delete_confirm_text));
317												builder.setPositiveButton(
318														getString(R.string.delete),
319														new OnClickListener() {
320
321															@Override
322															public void onClick(
323																	DialogInterface dialog,
324																	int which) {
325																xmppConnectionService
326																		.deleteAccount(selectedAccountForActionMode);
327																selectedAccountForActionMode = null;
328																mode.finish();
329															}
330														});
331												builder.setNegativeButton(
332														getString(R.string.cancel),
333														null);
334												builder.create().show();
335											} else if (item.getItemId() == R.id.mgmt_account_announce_pgp) {
336												if (activity.hasPgp()) {
337													mode.finish();
338													announcePgp(
339															selectedAccountForActionMode,
340															null);
341												} else {
342													activity.showInstallPgpDialog();
343												}
344											} else if (item.getItemId() == R.id.mgmt_otr_key) {
345												AlertDialog.Builder builder = new AlertDialog.Builder(
346														activity);
347												builder.setTitle("OTR Fingerprint");
348												String fingerprintTxt = selectedAccountForActionMode
349														.getOtrFingerprint(getApplicationContext());
350												View view = (View) getLayoutInflater()
351														.inflate(
352																R.layout.otr_fingerprint,
353																null);
354												if (fingerprintTxt != null) {
355													TextView fingerprint = (TextView) view
356															.findViewById(R.id.otr_fingerprint);
357													TextView noFingerprintView = (TextView) view
358															.findViewById(R.id.otr_no_fingerprint);
359													fingerprint
360															.setText(fingerprintTxt);
361													fingerprint
362															.setVisibility(View.VISIBLE);
363													noFingerprintView
364															.setVisibility(View.GONE);
365												}
366												builder.setView(view);
367												builder.setPositiveButton(
368														getString(R.string.done),
369														null);
370												builder.create().show();
371											} else if (item.getItemId() == R.id.mgmt_account_info) {
372												AlertDialog.Builder builder = new AlertDialog.Builder(
373														activity);
374												builder.setTitle(getString(R.string.account_info));
375												if (selectedAccountForActionMode
376														.getStatus() == Account.STATUS_ONLINE) {
377													XmppConnection xmpp = selectedAccountForActionMode
378															.getXmppConnection();
379													long connectionAge = (SystemClock
380															.elapsedRealtime() - xmpp.lastConnect) / 60000;
381													long sessionAge = (SystemClock
382															.elapsedRealtime() - xmpp.lastSessionStarted) / 60000;
383													long connectionAgeHours = connectionAge / 60;
384													long sessionAgeHours = sessionAge / 60;
385													View view = (View) getLayoutInflater()
386															.inflate(
387																	R.layout.server_info,
388																	null);
389													TextView connection = (TextView) view
390															.findViewById(R.id.connection);
391													TextView session = (TextView) view
392															.findViewById(R.id.session);
393													TextView pcks_sent = (TextView) view
394															.findViewById(R.id.pcks_sent);
395													TextView pcks_received = (TextView) view
396															.findViewById(R.id.pcks_received);
397													TextView carbon = (TextView) view
398															.findViewById(R.id.carbon);
399													TextView stream = (TextView) view
400															.findViewById(R.id.stream);
401													TextView roster = (TextView) view
402															.findViewById(R.id.roster);
403													TextView presences = (TextView) view
404															.findViewById(R.id.number_presences);
405													presences.setText(selectedAccountForActionMode
406															.countPresences()
407															+ "");
408													pcks_received.setText(""
409															+ xmpp.getReceivedStanzas());
410													pcks_sent.setText(""
411															+ xmpp.getSentStanzas());
412													if (connectionAgeHours >= 2) {
413														connection
414																.setText(connectionAgeHours
415																		+ " "
416																		+ getString(R.string.hours));
417													} else {
418														connection
419																.setText(connectionAge
420																		+ " "
421																		+ getString(R.string.mins));
422													}
423													if (xmpp.hasFeatureStreamManagment()) {
424														if (sessionAgeHours >= 2) {
425															session.setText(sessionAgeHours
426																	+ " "
427																	+ getString(R.string.hours));
428														} else {
429															session.setText(sessionAge
430																	+ " "
431																	+ getString(R.string.mins));
432														}
433														stream.setText(getString(R.string.yes));
434													} else {
435														stream.setText(getString(R.string.no));
436														session.setText(connection
437																.getText());
438													}
439													if (xmpp.hasFeaturesCarbon()) {
440														carbon.setText(getString(R.string.yes));
441													} else {
442														carbon.setText(getString(R.string.no));
443													}
444													if (xmpp.hasFeatureRosterManagment()) {
445														roster.setText(getString(R.string.yes));
446													} else {
447														roster.setText(getString(R.string.no));
448													}
449													builder.setView(view);
450												} else {
451													builder.setMessage(getString(R.string.mgmt_account_account_offline));
452												}
453												builder.setPositiveButton(
454														getString(R.string.hide),
455														null);
456												builder.create().show();
457											}
458											return true;
459										}
460
461									}));
462							return true;
463						} else {
464							return false;
465						}
466					}
467				});
468	}
469
470	@Override
471	protected void onStop() {
472		if (xmppConnectionServiceBound) {
473			xmppConnectionService.removeOnAccountListChangedListener();
474			xmppConnectionService.removeOnTLSExceptionReceivedListener();
475		}
476		super.onStop();
477	}
478
479	@Override
480	void onBackendConnected() {
481		xmppConnectionService.setOnAccountListChangedListener(accountChanged);
482		xmppConnectionService
483				.setOnTLSExceptionReceivedListener(tlsExceptionReceived);
484		this.accountList.clear();
485		this.accountList.addAll(xmppConnectionService.getAccounts());
486		accountListViewAdapter.notifyDataSetChanged();
487		if ((this.accountList.size() == 0) && (this.firstrun)) {
488			getActionBar().setDisplayHomeAsUpEnabled(false);
489			getActionBar().setHomeButtonEnabled(false);
490			addAccount();
491			this.firstrun = false;
492		}
493	}
494
495	@Override
496	public boolean onCreateOptionsMenu(Menu menu) {
497		getMenuInflater().inflate(R.menu.manageaccounts, menu);
498		return true;
499	}
500
501	@Override
502	public boolean onOptionsItemSelected(MenuItem item) {
503		switch (item.getItemId()) {
504		case R.id.action_add_account:
505			addAccount();
506			break;
507		default:
508			break;
509		}
510		return super.onOptionsItemSelected(item);
511	}
512
513	@Override
514	public boolean onNavigateUp() {
515		if (xmppConnectionService.getConversations().size() == 0) {
516			Intent contactsIntent = new Intent(this, StartConversation.class);
517			contactsIntent.setFlags(
518			// if activity exists in stack, pop the stack and go back to it
519					Intent.FLAG_ACTIVITY_CLEAR_TOP |
520					// otherwise, make a new task for it
521							Intent.FLAG_ACTIVITY_NEW_TASK |
522							// don't use the new activity animation; finish
523							// animation runs instead
524							Intent.FLAG_ACTIVITY_NO_ANIMATION);
525			startActivity(contactsIntent);
526			finish();
527			return true;
528		} else {
529			return super.onNavigateUp();
530		}
531	}
532
533	private void editAccount(Account account) {
534		EditAccount dialog = new EditAccount();
535		dialog.setAccount(account);
536		dialog.setEditAccountListener(new EditAccountListener() {
537
538			@Override
539			public void onAccountEdited(Account account) {
540				xmppConnectionService.updateAccount(account);
541				if (actionMode != null) {
542					actionMode.finish();
543				}
544			}
545		});
546		dialog.show(getFragmentManager(), "edit_account");
547		dialog.setKnownHosts(xmppConnectionService.getKnownHosts(), this);
548
549	}
550
551	protected void addAccount() {
552		final Activity activity = this;
553		EditAccount dialog = new EditAccount();
554		dialog.setEditAccountListener(new EditAccountListener() {
555
556			@Override
557			public void onAccountEdited(Account account) {
558				xmppConnectionService.createAccount(account);
559				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
560				activity.getActionBar().setHomeButtonEnabled(true);
561			}
562		});
563		dialog.show(getFragmentManager(), "add_account");
564		dialog.setKnownHosts(xmppConnectionService.getKnownHosts(), this);
565	}
566
567	@Override
568	public void onActionModeStarted(ActionMode mode) {
569		super.onActionModeStarted(mode);
570		this.isActionMode = true;
571	}
572
573	@Override
574	public void onActionModeFinished(ActionMode mode) {
575		super.onActionModeFinished(mode);
576		this.isActionMode = false;
577		accountListView.clearChoices();
578		accountListView.requestLayout();
579		accountListView.post(new Runnable() {
580			@Override
581			public void run() {
582				accountListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
583			}
584		});
585	}
586
587	@Override
588	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
589		super.onActivityResult(requestCode, resultCode, data);
590		if (resultCode == RESULT_OK) {
591			if (requestCode == REQUEST_ANNOUNCE_PGP) {
592				announcePgp(selectedAccountForActionMode, null);
593			}
594		}
595	}
596}