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