ContactDetailsActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.Iterator;
  4
  5import org.openintents.openpgp.util.OpenPgpUtils;
  6
  7import android.app.AlertDialog;
  8import android.app.PendingIntent;
  9import android.content.Context;
 10import android.content.DialogInterface;
 11import android.content.Intent;
 12import android.content.IntentSender.SendIntentException;
 13import android.net.Uri;
 14import android.os.Bundle;
 15import android.provider.ContactsContract.CommonDataKinds;
 16import android.provider.ContactsContract.Contacts;
 17import android.provider.ContactsContract.Intents;
 18import android.view.LayoutInflater;
 19import android.view.Menu;
 20import android.view.MenuItem;
 21import android.view.View;
 22import android.view.View.OnClickListener;
 23import android.widget.CheckBox;
 24import android.widget.CompoundButton.OnCheckedChangeListener;
 25import android.widget.CompoundButton;
 26import android.widget.ImageButton;
 27import android.widget.LinearLayout;
 28import android.widget.QuickContactBadge;
 29import android.widget.TextView;
 30import eu.siacs.conversations.R;
 31import eu.siacs.conversations.crypto.PgpEngine;
 32import eu.siacs.conversations.entities.Account;
 33import eu.siacs.conversations.entities.Contact;
 34import eu.siacs.conversations.entities.Presences;
 35import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 36import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 37import eu.siacs.conversations.utils.UIHelper;
 38
 39public class ContactDetailsActivity extends XmppActivity {
 40	public static final String ACTION_VIEW_CONTACT = "view_contact";
 41
 42	private Contact contact;
 43
 44	private String accountJid;
 45	private String contactJid;
 46
 47	private TextView contactJidTv;
 48	private TextView accountJidTv;
 49	private TextView status;
 50	private TextView lastseen;
 51	private CheckBox send;
 52	private CheckBox receive;
 53	private QuickContactBadge badge;
 54
 55	private DialogInterface.OnClickListener removeFromRoster = new DialogInterface.OnClickListener() {
 56
 57		@Override
 58		public void onClick(DialogInterface dialog, int which) {
 59			ContactDetailsActivity.this.xmppConnectionService
 60					.deleteContactOnServer(contact);
 61			ContactDetailsActivity.this.finish();
 62		}
 63	};
 64
 65	private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() {
 66
 67		@Override
 68		public void onClick(DialogInterface dialog, int which) {
 69			Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
 70			intent.setType(Contacts.CONTENT_ITEM_TYPE);
 71			intent.putExtra(Intents.Insert.IM_HANDLE, contact.getJid());
 72			intent.putExtra(Intents.Insert.IM_PROTOCOL,
 73					CommonDataKinds.Im.PROTOCOL_JABBER);
 74			intent.putExtra("finishActivityOnSaveCompleted", true);
 75			ContactDetailsActivity.this.startActivityForResult(intent, 0);
 76		}
 77	};
 78	private OnClickListener onBadgeClick = new OnClickListener() {
 79
 80		@Override
 81		public void onClick(View v) {
 82			AlertDialog.Builder builder = new AlertDialog.Builder(
 83					ContactDetailsActivity.this);
 84			builder.setTitle(getString(R.string.action_add_phone_book));
 85			builder.setMessage(getString(R.string.add_phone_book_text,
 86					contact.getJid()));
 87			builder.setNegativeButton(getString(R.string.cancel), null);
 88			builder.setPositiveButton(getString(R.string.add), addToPhonebook);
 89			builder.create().show();
 90		}
 91	};
 92
 93	private LinearLayout keys;
 94
 95	private OnRosterUpdate rosterUpdate = new OnRosterUpdate() {
 96
 97		@Override
 98		public void onRosterUpdate() {
 99			runOnUiThread(new Runnable() {
100
101				@Override
102				public void run() {
103					populateView();
104				}
105			});
106		}
107	};
108
109	private OnCheckedChangeListener mOnSendCheckedChange = new OnCheckedChangeListener() {
110
111		@Override
112		public void onCheckedChanged(CompoundButton buttonView,
113				boolean isChecked) {
114			if (isChecked) {
115				if (contact
116						.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
117					xmppConnectionService.sendPresencePacket(contact
118							.getAccount(),
119							xmppConnectionService.getPresenceGenerator()
120									.sendPresenceUpdatesTo(contact));
121				} else {
122					contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
123				}
124			} else {
125				contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
126				xmppConnectionService.sendPresencePacket(contact.getAccount(),
127						xmppConnectionService.getPresenceGenerator()
128								.stopPresenceUpdatesTo(contact));
129			}
130		}
131	};
132
133	private OnCheckedChangeListener mOnReceiveCheckedChange = new OnCheckedChangeListener() {
134
135		@Override
136		public void onCheckedChanged(CompoundButton buttonView,
137				boolean isChecked) {
138			if (isChecked) {
139				xmppConnectionService.sendPresencePacket(contact.getAccount(),
140						xmppConnectionService.getPresenceGenerator()
141								.requestPresenceUpdatesFrom(contact));
142			} else {
143				xmppConnectionService.sendPresencePacket(contact.getAccount(),
144						xmppConnectionService.getPresenceGenerator()
145								.stopPresenceUpdatesFrom(contact));
146			}
147		}
148	};
149
150	private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
151
152		@Override
153		public void onAccountUpdate() {
154			runOnUiThread(new Runnable() {
155
156				@Override
157				public void run() {
158					populateView();
159				}
160			});
161		}
162	};
163
164	@Override
165	protected String getShareableUri() {
166		if (contact!=null) {
167			return "xmpp:"+contact.getJid();
168		} else {
169			return "";
170		}
171	}
172
173	@Override
174	protected void onCreate(Bundle savedInstanceState) {
175		super.onCreate(savedInstanceState);
176		if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
177			this.accountJid = getIntent().getExtras().getString("account");
178			this.contactJid = getIntent().getExtras().getString("contact");
179		}
180		setContentView(R.layout.activity_contact_details);
181
182		contactJidTv = (TextView) findViewById(R.id.details_contactjid);
183		accountJidTv = (TextView) findViewById(R.id.details_account);
184		status = (TextView) findViewById(R.id.details_contactstatus);
185		lastseen = (TextView) findViewById(R.id.details_lastseen);
186		send = (CheckBox) findViewById(R.id.details_send_presence);
187		receive = (CheckBox) findViewById(R.id.details_receive_presence);
188		badge = (QuickContactBadge) findViewById(R.id.details_contact_badge);
189		keys = (LinearLayout) findViewById(R.id.details_contact_keys);
190		getActionBar().setHomeButtonEnabled(true);
191		getActionBar().setDisplayHomeAsUpEnabled(true);
192
193	}
194
195	@Override
196	public boolean onOptionsItemSelected(MenuItem menuItem) {
197		AlertDialog.Builder builder = new AlertDialog.Builder(this);
198		builder.setNegativeButton(getString(R.string.cancel), null);
199		switch (menuItem.getItemId()) {
200		case android.R.id.home:
201			finish();
202			break;
203		case R.id.action_delete_contact:
204			builder.setTitle(getString(R.string.action_delete_contact))
205					.setMessage(
206							getString(R.string.remove_contact_text,
207									contact.getJid()))
208					.setPositiveButton(getString(R.string.delete),
209							removeFromRoster).create().show();
210			break;
211		case R.id.action_edit_contact:
212			if (contact.getSystemAccount() == null) {
213				quickEdit(contact.getDisplayName(), new OnValueEdited() {
214
215					@Override
216					public void onValueEdited(String value) {
217						contact.setServerName(value);
218						ContactDetailsActivity.this.xmppConnectionService
219								.pushContactToServer(contact);
220						populateView();
221					}
222				});
223			} else {
224				Intent intent = new Intent(Intent.ACTION_EDIT);
225				String[] systemAccount = contact.getSystemAccount().split("#");
226				long id = Long.parseLong(systemAccount[0]);
227				Uri uri = Contacts.getLookupUri(id, systemAccount[1]);
228				intent.setDataAndType(uri, Contacts.CONTENT_ITEM_TYPE);
229				intent.putExtra("finishActivityOnSaveCompleted", true);
230				startActivity(intent);
231			}
232			break;
233		}
234		return super.onOptionsItemSelected(menuItem);
235	}
236
237	@Override
238	public boolean onCreateOptionsMenu(Menu menu) {
239		getMenuInflater().inflate(R.menu.contact_details, menu);
240		return true;
241	}
242
243	private void populateView() {
244		send.setOnCheckedChangeListener(null);
245		receive.setOnCheckedChangeListener(null);
246		setTitle(contact.getDisplayName());
247		if (contact.getOption(Contact.Options.FROM)) {
248			send.setText(R.string.send_presence_updates);
249			send.setChecked(true);
250		} else if (contact
251				.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
252			send.setChecked(false);
253			send.setText(R.string.send_presence_updates);
254		} else {
255			send.setText(R.string.preemptively_grant);
256			if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
257				send.setChecked(true);
258			} else {
259				send.setChecked(false);
260			}
261		}
262		if (contact.getOption(Contact.Options.TO)) {
263			receive.setText(R.string.receive_presence_updates);
264			receive.setChecked(true);
265		} else {
266			receive.setText(R.string.ask_for_presence_updates);
267			if (contact.getOption(Contact.Options.ASKING)) {
268				receive.setChecked(true);
269			} else {
270				receive.setChecked(false);
271			}
272		}
273		if (contact.getAccount().getStatus() == Account.STATUS_ONLINE) {
274			receive.setEnabled(true);
275			send.setEnabled(true);
276		} else {
277			receive.setEnabled(false);
278			send.setEnabled(false);
279		}
280
281		send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
282		receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
283
284		lastseen.setText(UIHelper.lastseen(getApplicationContext(),
285				contact.lastseen.time));
286
287		switch (contact.getMostAvailableStatus()) {
288		case Presences.CHAT:
289			status.setText(R.string.contact_status_free_to_chat);
290			status.setTextColor(mColorGreen);
291			break;
292		case Presences.ONLINE:
293			status.setText(R.string.contact_status_online);
294			status.setTextColor(mColorGreen);
295			break;
296		case Presences.AWAY:
297			status.setText(R.string.contact_status_away);
298			status.setTextColor(mColorOrange);
299			break;
300		case Presences.XA:
301			status.setText(R.string.contact_status_extended_away);
302			status.setTextColor(mColorOrange);
303			break;
304		case Presences.DND:
305			status.setText(R.string.contact_status_do_not_disturb);
306			status.setTextColor(mColorRed);
307			break;
308		case Presences.OFFLINE:
309			status.setText(R.string.contact_status_offline);
310			status.setTextColor(mSecondaryTextColor);
311			break;
312		default:
313			status.setText(R.string.contact_status_offline);
314			status.setTextColor(mSecondaryTextColor);
315			break;
316		}
317		if (contact.getPresences().size() > 1) {
318			contactJidTv.setText(contact.getJid() + " ("
319					+ contact.getPresences().size() + ")");
320		} else {
321			contactJidTv.setText(contact.getJid());
322		}
323		accountJidTv.setText(getString(R.string.using_account, contact
324				.getAccount().getJid()));
325		prepareContactBadge(badge, contact);
326		if (contact.getSystemAccount() == null) {
327			badge.setOnClickListener(onBadgeClick);
328		}
329
330		keys.removeAllViews();
331		boolean hasKeys = false;
332		LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
333		for (Iterator<String> iterator = contact.getOtrFingerprints()
334				.iterator(); iterator.hasNext();) {
335			hasKeys = true;
336			final String otrFingerprint = iterator.next();
337			View view = inflater.inflate(R.layout.contact_key, keys, false);
338			TextView key = (TextView) view.findViewById(R.id.key);
339			TextView keyType = (TextView) view.findViewById(R.id.key_type);
340			ImageButton remove = (ImageButton) view
341					.findViewById(R.id.button_remove);
342			remove.setVisibility(View.VISIBLE);
343			keyType.setText("OTR Fingerprint");
344			key.setText(otrFingerprint);
345			keys.addView(view);
346			remove.setOnClickListener(new OnClickListener() {
347
348				@Override
349				public void onClick(View v) {
350					confirmToDeleteFingerprint(otrFingerprint);
351				}
352			});
353		}
354		if (contact.getPgpKeyId() != 0) {
355			hasKeys = true;
356			View view = inflater.inflate(R.layout.contact_key, keys, false);
357			TextView key = (TextView) view.findViewById(R.id.key);
358			TextView keyType = (TextView) view.findViewById(R.id.key_type);
359			keyType.setText("PGP Key ID");
360			key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
361			view.setOnClickListener(new OnClickListener() {
362
363				@Override
364				public void onClick(View v) {
365					PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService
366							.getPgpEngine();
367					if (pgp != null) {
368						PendingIntent intent = pgp.getIntentForKey(contact);
369						if (intent != null) {
370							try {
371								startIntentSenderForResult(
372										intent.getIntentSender(), 0, null, 0,
373										0, 0);
374							} catch (SendIntentException e) {
375
376							}
377						}
378					}
379				}
380			});
381			keys.addView(view);
382		}
383		if (hasKeys) {
384			keys.setVisibility(View.VISIBLE);
385		} else {
386			keys.setVisibility(View.GONE);
387		}
388	}
389
390	private void prepareContactBadge(QuickContactBadge badge, Contact contact) {
391		if (contact.getSystemAccount() != null) {
392			String[] systemAccount = contact.getSystemAccount().split("#");
393			long id = Long.parseLong(systemAccount[0]);
394			badge.assignContactUri(Contacts.getLookupUri(id, systemAccount[1]));
395		}
396		badge.setImageBitmap(avatarService().get(contact, getPixel(72)));
397	}
398
399	protected void confirmToDeleteFingerprint(final String fingerprint) {
400		AlertDialog.Builder builder = new AlertDialog.Builder(this);
401		builder.setTitle(R.string.delete_fingerprint);
402		builder.setMessage(R.string.sure_delete_fingerprint);
403		builder.setNegativeButton(R.string.cancel, null);
404		builder.setPositiveButton(R.string.delete,
405				new android.content.DialogInterface.OnClickListener() {
406
407					@Override
408					public void onClick(DialogInterface dialog, int which) {
409						if (contact.deleteOtrFingerprint(fingerprint)) {
410							populateView();
411							xmppConnectionService.syncRosterToDisk(contact
412									.getAccount());
413						}
414					}
415
416				});
417		builder.create().show();
418	}
419
420	@Override
421	public void onBackendConnected() {
422		xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
423		xmppConnectionService
424				.setOnAccountListChangedListener(this.accountUpdate);
425		if ((accountJid != null) && (contactJid != null)) {
426			Account account = xmppConnectionService
427					.findAccountByJid(accountJid);
428			if (account == null) {
429				return;
430			}
431			this.contact = account.getRoster().getContact(contactJid);
432			populateView();
433		}
434	}
435
436	@Override
437	protected void onStop() {
438		super.onStop();
439		xmppConnectionService.removeOnRosterUpdateListener();
440		xmppConnectionService.removeOnAccountListChangedListener();
441	}
442
443}