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.crypto.PgpEngine;
  8import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException;
  9import eu.siacs.conversations.entities.Account;
 10import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
 11import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
 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.content.IntentSender.SendIntentException;
 19import android.os.Bundle;
 20import android.util.Log;
 21import android.view.ActionMode;
 22import android.view.LayoutInflater;
 23import android.view.Menu;
 24import android.view.MenuInflater;
 25import android.view.MenuItem;
 26import android.view.View;
 27import android.view.ViewGroup;
 28import android.widget.AdapterView;
 29import android.widget.AdapterView.OnItemClickListener;
 30import android.widget.AdapterView.OnItemLongClickListener;
 31import android.widget.ArrayAdapter;
 32import android.widget.ListView;
 33import android.widget.TextView;
 34
 35public class ManageAccountActivity extends XmppActivity {
 36
 37	public static final int REQUEST_ANNOUNCE_PGP = 0x73731;
 38	
 39	protected boolean isActionMode = false;
 40	protected ActionMode actionMode;
 41	protected Account selectedAccountForActionMode = null;
 42	protected ManageAccountActivity activity = this;
 43	
 44	protected List<Account> accountList = new ArrayList<Account>();
 45	protected ListView accountListView;
 46	protected ArrayAdapter<Account> accountListViewAdapter;
 47	protected OnAccountListChangedListener accountChanged = new OnAccountListChangedListener() {
 48
 49		@Override
 50		public void onAccountListChangedListener() {
 51			accountList.clear();
 52			accountList.addAll(xmppConnectionService.getAccounts());
 53			runOnUiThread(new Runnable() {
 54
 55				@Override
 56				public void run() {
 57					accountListViewAdapter.notifyDataSetChanged();
 58				}
 59			});
 60		}
 61	};
 62	
 63	protected OnTLSExceptionReceived tlsExceptionReceived = new OnTLSExceptionReceived() {
 64		
 65		@Override
 66		public void onTLSExceptionReceived(final String fingerprint, final Account account) {
 67			activity.runOnUiThread(new Runnable() {
 68				
 69				@Override
 70				public void run() {
 71					AlertDialog.Builder builder = new AlertDialog.Builder(activity);
 72					builder.setTitle("Untrusted Certificate");
 73					builder.setIconAttribute(android.R.attr.alertDialogIcon);
 74					View view = (View) getLayoutInflater().inflate(R.layout.cert_warning, null);
 75					TextView sha = (TextView) view.findViewById(R.id.sha);
 76					TextView hint = (TextView) view.findViewById(R.id.hint);
 77					StringBuilder humanReadableSha = new StringBuilder();
 78					humanReadableSha.append(fingerprint);
 79					for(int i = 2; i < 59; i += 3) {
 80						Log.d("gultsch","insert into "+i);
 81						if ((i==14)||(i==29)||(i==44)) {
 82							humanReadableSha.insert(i, "\n");
 83						} else {
 84							humanReadableSha.insert(i, ":");
 85						}
 86						
 87					}
 88					hint.setText(getString(R.string.untrusted_cert_hint,account.getServer()));
 89					sha.setText(humanReadableSha.toString());
 90					builder.setView(view);
 91					builder.setNegativeButton("Don't connect", null);
 92					builder.setPositiveButton("Trust certificate", new OnClickListener() {
 93						
 94						@Override
 95						public void onClick(DialogInterface dialog, int which) {
 96							account.setSSLCertFingerprint(fingerprint);
 97							activity.xmppConnectionService.updateAccount(account);
 98						}
 99					});
100					builder.create().show();
101				}
102			});
103			
104		}
105	};
106
107	@Override
108	protected void onCreate(Bundle savedInstanceState) {
109
110		super.onCreate(savedInstanceState);
111
112		setContentView(R.layout.manage_accounts);
113
114		accountListView = (ListView) findViewById(R.id.account_list);
115		accountListViewAdapter = new ArrayAdapter<Account>(
116				getApplicationContext(), R.layout.account_row, this.accountList) {
117			@Override
118			public View getView(int position, View view, ViewGroup parent) {
119				Account account = getItem(position);
120				if (view == null) {
121					LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
122					view = (View) inflater.inflate(R.layout.account_row, null);
123				}
124				((TextView) view.findViewById(R.id.account_jid))
125						.setText(account.getJid());
126				TextView statusView = (TextView) view
127						.findViewById(R.id.account_status);
128				switch (account.getStatus()) {
129				case Account.STATUS_DISABLED:
130					statusView.setText("temporarily disabled");
131					statusView.setTextColor(0xFF1da9da);
132					break;
133				case Account.STATUS_ONLINE:
134					statusView.setText("online");
135					statusView.setTextColor(0xFF83b600);
136					break;
137				case Account.STATUS_CONNECTING:
138					statusView.setText("connecting\u2026");
139					statusView.setTextColor(0xFF1da9da);
140					break;
141				case Account.STATUS_OFFLINE:
142					statusView.setText("offline");
143					statusView.setTextColor(0xFFe92727);
144					break;
145				case Account.STATUS_UNAUTHORIZED:
146					statusView.setText("unauthorized");
147					statusView.setTextColor(0xFFe92727);
148					break;
149				case Account.STATUS_SERVER_NOT_FOUND:
150					statusView.setText("server not found");
151					statusView.setTextColor(0xFFe92727);
152					break;
153				case Account.STATUS_NO_INTERNET:
154					statusView.setText("no internet");
155					statusView.setTextColor(0xFFe92727);
156					break;
157				case Account.STATUS_SERVER_REQUIRES_TLS:
158					statusView.setText("server requires TLS");
159					statusView.setTextColor(0xFFe92727);
160					break;
161				case Account.STATUS_TLS_ERROR:
162					statusView.setText("untrusted cerficate");
163					statusView.setTextColor(0xFFe92727);
164					break;
165				default:
166					break;
167				}
168
169				return view;
170			}
171		};
172		final XmppActivity activity = this;
173		accountListView.setAdapter(this.accountListViewAdapter);
174		accountListView.setOnItemClickListener(new OnItemClickListener() {
175
176			@Override
177			public void onItemClick(AdapterView<?> arg0, View view,
178					int position, long arg3) {
179				if (!isActionMode) {
180					Account account = accountList.get(position);
181					if ((account.getStatus() != Account.STATUS_ONLINE)&&(account.getStatus() != Account.STATUS_CONNECTING)&&(!account.isOptionSet(Account.OPTION_DISABLED))) {
182						activity.xmppConnectionService.reconnectAccount(accountList.get(position));
183					} else if (account.getStatus() == Account.STATUS_ONLINE) {
184						activity.startActivity(new Intent(activity.getApplicationContext(),NewConversationActivity.class));
185					}
186					
187					Log.d("gultsch","clicked on account "+accountList.get(position).getJid());
188				} else {
189					selectedAccountForActionMode = accountList.get(position);
190					actionMode.invalidate();
191				}
192			}
193		});
194		accountListView.setOnItemLongClickListener(new OnItemLongClickListener() {
195
196			@Override
197			public boolean onItemLongClick(AdapterView<?> arg0, View view,
198					int position, long arg3) {
199				if (!isActionMode) {
200					accountListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
201					accountListView.setItemChecked(position,true);
202					selectedAccountForActionMode = accountList.get(position);
203					actionMode = activity.startActionMode((new ActionMode.Callback() {
204						
205						@Override
206						public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
207							if (selectedAccountForActionMode.isOptionSet(Account.OPTION_DISABLED)) {
208					        	menu.findItem(R.id.mgmt_account_enable).setVisible(true);
209					        	menu.findItem(R.id.mgmt_account_disable).setVisible(false);
210					        } else {
211					        	menu.findItem(R.id.mgmt_account_disable).setVisible(true);
212					        	menu.findItem(R.id.mgmt_account_enable).setVisible(false);
213					        }
214							return true;
215						}
216						
217						@Override
218						public void onDestroyActionMode(ActionMode mode) {
219							// TODO Auto-generated method stub
220							
221						}
222						
223						@Override
224						public boolean onCreateActionMode(ActionMode mode, Menu menu) {
225							MenuInflater inflater = mode.getMenuInflater();
226					        inflater.inflate(R.menu.manageaccounts_context, menu);
227							return true;
228						}
229						
230						@Override
231						public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
232							if (item.getItemId()==R.id.mgmt_account_edit) {
233								EditAccount dialog = new EditAccount();
234								dialog.setAccount(selectedAccountForActionMode);
235								dialog.setEditAccountListener(new EditAccountListener() {
236				
237									@Override
238									public void onAccountEdited(Account account) {
239										xmppConnectionService.updateAccount(account);
240										actionMode.finish();
241									}
242								});
243								dialog.show(getFragmentManager(), "edit_account");
244							} else if (item.getItemId()==R.id.mgmt_account_disable) {
245								selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, true);
246								xmppConnectionService.updateAccount(selectedAccountForActionMode);
247								mode.finish();
248							} else if (item.getItemId()==R.id.mgmt_account_enable) {
249								selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, false);
250								xmppConnectionService.updateAccount(selectedAccountForActionMode);
251								mode.finish();
252							} else if (item.getItemId()==R.id.mgmt_account_delete) {
253								AlertDialog.Builder builder = new AlertDialog.Builder(activity);
254								builder.setTitle("Are you sure?");
255								builder.setIconAttribute(android.R.attr.alertDialogIcon);
256								builder.setMessage("If you delete your account your entire conversation history will be lost");
257								builder.setPositiveButton("Delete", new OnClickListener() {
258									
259									@Override
260									public void onClick(DialogInterface dialog, int which) {
261										xmppConnectionService.deleteAccount(selectedAccountForActionMode);
262										selectedAccountForActionMode = null;
263										mode.finish();
264									}
265								});
266								builder.setNegativeButton("Cancel",null);
267								builder.create().show();
268							} else if (item.getItemId()==R.id.mgmt_account_announce_pgp) {
269								if (activity.hasPgp()) {
270									mode.finish();
271									try {
272										xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
273									} catch (PgpEngine.UserInputRequiredException e) {
274										try {
275											startIntentSenderForResult(e.getPendingIntent().getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
276										} catch (SendIntentException e1) {
277											Log.d("gultsch","sending intent failed");
278										}
279									}
280								}
281							}
282							return true;
283						}
284					}));
285					return true;
286				} else {
287					return false;
288				}
289			}
290		});
291	}
292
293	@Override
294	protected void onStop() {
295		if (xmppConnectionServiceBound) {
296			xmppConnectionService.removeOnAccountListChangedListener();
297			xmppConnectionService.removeOnTLSExceptionReceivedListener();
298		}
299		super.onStop();
300	}
301
302	@Override
303	void onBackendConnected() {
304		xmppConnectionService.setOnAccountListChangedListener(accountChanged);
305		xmppConnectionService.setOnTLSExceptionReceivedListener(tlsExceptionReceived);
306		this.accountList.clear();
307		this.accountList.addAll(xmppConnectionService.getAccounts());
308		accountListViewAdapter.notifyDataSetChanged();
309		if (this.accountList.size() == 0) {
310			getActionBar().setDisplayHomeAsUpEnabled(false);
311			addAccount();
312		}
313	}
314
315	@Override
316	public boolean onCreateOptionsMenu(Menu menu) {
317		getMenuInflater().inflate(R.menu.manageaccounts, menu);
318		return true;
319	}
320
321	@Override
322	public boolean onOptionsItemSelected(MenuItem item) {
323		switch (item.getItemId()) {
324		case R.id.action_settings:
325			startActivity(new Intent(this, SettingsActivity.class));
326			break;
327		case R.id.action_add_account:
328			addAccount();
329			break;
330		default:
331			break;
332		}
333		return super.onOptionsItemSelected(item);
334	}
335
336	protected void addAccount() {
337		final Activity activity = this;
338		EditAccount dialog = new EditAccount();
339		dialog.setEditAccountListener(new EditAccountListener() {
340
341			@Override
342			public void onAccountEdited(Account account) {
343				xmppConnectionService.createAccount(account);
344				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
345			}
346		});
347		dialog.show(getFragmentManager(), "add_account");
348	}
349
350	
351	@Override
352	public void onActionModeStarted(ActionMode mode) {
353		super.onActionModeStarted(mode);
354		this.isActionMode = true;
355	}
356	
357	@Override
358	public void onActionModeFinished(ActionMode mode) {
359		super.onActionModeFinished(mode);
360		this.isActionMode = false;
361		accountListView.clearChoices();
362		accountListView.requestLayout();
363		accountListView.post(new Runnable() {
364            @Override
365            public void run() {
366                accountListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
367            }
368        });
369	}
370	
371	 @Override
372	 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
373		 super.onActivityResult(requestCode, resultCode, data);
374		 if (resultCode == RESULT_OK) {
375			if (requestCode == REQUEST_ANNOUNCE_PGP) {
376				 try {
377					xmppConnectionService.generatePgpAnnouncement(selectedAccountForActionMode);
378				} catch (UserInputRequiredException e) {
379					Log.d("gultsch","already came back. ignoring");
380				}
381			 }
382		 }
383	 }
384}