ContactDetailsActivity.java

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