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