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