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