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}