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.LinearLayout;
27import android.widget.QuickContactBadge;
28import android.widget.TextView;
29import eu.siacs.conversations.R;
30import eu.siacs.conversations.crypto.PgpEngine;
31import eu.siacs.conversations.entities.Account;
32import eu.siacs.conversations.entities.Contact;
33import eu.siacs.conversations.entities.Presences;
34import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
35import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
36import eu.siacs.conversations.utils.UIHelper;
37
38public class ContactDetailsActivity extends XmppActivity {
39 public static final String ACTION_VIEW_CONTACT = "view_contact";
40
41 protected ContactDetailsActivity activity = this;
42
43 private Contact contact;
44
45 private String accountJid;
46 private String contactJid;
47
48 private TextView contactJidTv;
49 private TextView accountJidTv;
50 private TextView status;
51 private TextView lastseen;
52 private CheckBox send;
53 private CheckBox receive;
54 private QuickContactBadge badge;
55
56 private DialogInterface.OnClickListener removeFromRoster = new DialogInterface.OnClickListener() {
57
58 @Override
59 public void onClick(DialogInterface dialog, int which) {
60 activity.xmppConnectionService.deleteContactOnServer(contact);
61 activity.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 activity.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(activity);
83 builder.setTitle(getString(R.string.action_add_phone_book));
84 builder.setMessage(getString(R.string.add_phone_book_text,
85 contact.getJid()));
86 builder.setNegativeButton(getString(R.string.cancel), null);
87 builder.setPositiveButton(getString(R.string.add), addToPhonebook);
88 builder.create().show();
89 }
90 };
91
92 private LinearLayout keys;
93
94 private OnRosterUpdate rosterUpdate = new OnRosterUpdate() {
95
96 @Override
97 public void onRosterUpdate() {
98 runOnUiThread(new Runnable() {
99
100 @Override
101 public void run() {
102 populateView();
103 }
104 });
105 }
106 };
107
108 private OnCheckedChangeListener mOnSendCheckedChange = new OnCheckedChangeListener() {
109
110 @Override
111 public void onCheckedChanged(CompoundButton buttonView,
112 boolean isChecked) {
113 if (isChecked) {
114 if (contact
115 .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
116 xmppConnectionService.sendPresencePacket(contact
117 .getAccount(),
118 xmppConnectionService.getPresenceGenerator()
119 .sendPresenceUpdatesTo(contact));
120 } else {
121 contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
122 }
123 } else {
124 contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
125 xmppConnectionService.sendPresencePacket(contact.getAccount(),
126 xmppConnectionService.getPresenceGenerator()
127 .stopPresenceUpdatesTo(contact));
128 }
129 }
130 };
131
132 private OnCheckedChangeListener mOnReceiveCheckedChange = new OnCheckedChangeListener() {
133
134 @Override
135 public void onCheckedChanged(CompoundButton buttonView,
136 boolean isChecked) {
137 if (isChecked) {
138 xmppConnectionService.sendPresencePacket(contact.getAccount(),
139 xmppConnectionService.getPresenceGenerator()
140 .requestPresenceUpdatesFrom(contact));
141 } else {
142 xmppConnectionService.sendPresencePacket(contact.getAccount(),
143 xmppConnectionService.getPresenceGenerator()
144 .stopPresenceUpdatesFrom(contact));
145 }
146 }
147 };
148
149 private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
150
151 @Override
152 public void onAccountUpdate() {
153 runOnUiThread(new Runnable() {
154
155 @Override
156 public void run() {
157 populateView();
158 }
159 });
160 }
161 };
162
163 @Override
164 protected void onCreate(Bundle savedInstanceState) {
165 super.onCreate(savedInstanceState);
166 if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
167 this.accountJid = getIntent().getExtras().getString("account");
168 this.contactJid = getIntent().getExtras().getString("contact");
169 }
170 setContentView(R.layout.activity_contact_details);
171
172 contactJidTv = (TextView) findViewById(R.id.details_contactjid);
173 accountJidTv = (TextView) findViewById(R.id.details_account);
174 status = (TextView) findViewById(R.id.details_contactstatus);
175 lastseen = (TextView) findViewById(R.id.details_lastseen);
176 send = (CheckBox) findViewById(R.id.details_send_presence);
177 receive = (CheckBox) findViewById(R.id.details_receive_presence);
178 badge = (QuickContactBadge) findViewById(R.id.details_contact_badge);
179 keys = (LinearLayout) findViewById(R.id.details_contact_keys);
180 getActionBar().setHomeButtonEnabled(true);
181 getActionBar().setDisplayHomeAsUpEnabled(true);
182
183 }
184
185 @Override
186 public boolean onOptionsItemSelected(MenuItem menuItem) {
187 AlertDialog.Builder builder = new AlertDialog.Builder(this);
188 builder.setNegativeButton(getString(R.string.cancel), null);
189 switch (menuItem.getItemId()) {
190 case android.R.id.home:
191 finish();
192 break;
193 case R.id.action_delete_contact:
194 builder.setTitle(getString(R.string.action_delete_contact))
195 .setMessage(
196 getString(R.string.remove_contact_text,
197 contact.getJid()))
198 .setPositiveButton(getString(R.string.delete),
199 removeFromRoster).create().show();
200 break;
201 case R.id.action_edit_contact:
202 if (contact.getSystemAccount() == null) {
203 quickEdit(contact.getDisplayName(), new OnValueEdited() {
204
205 @Override
206 public void onValueEdited(String value) {
207 contact.setServerName(value);
208 activity.xmppConnectionService
209 .pushContactToServer(contact);
210 populateView();
211 }
212 });
213 } else {
214 Intent intent = new Intent(Intent.ACTION_EDIT);
215 String[] systemAccount = contact.getSystemAccount().split("#");
216 long id = Long.parseLong(systemAccount[0]);
217 Uri uri = Contacts.getLookupUri(id, systemAccount[1]);
218 intent.setDataAndType(uri, Contacts.CONTENT_ITEM_TYPE);
219 intent.putExtra("finishActivityOnSaveCompleted", true);
220 startActivity(intent);
221 }
222 break;
223 }
224 return super.onOptionsItemSelected(menuItem);
225 }
226
227 @Override
228 public boolean onCreateOptionsMenu(Menu menu) {
229 getMenuInflater().inflate(R.menu.contact_details, menu);
230 return true;
231 }
232
233 private void populateView() {
234 send.setOnCheckedChangeListener(null);
235 receive.setOnCheckedChangeListener(null);
236 setTitle(contact.getDisplayName());
237 if (contact.getOption(Contact.Options.FROM)) {
238 send.setText(R.string.send_presence_updates);
239 send.setChecked(true);
240 } else if (contact
241 .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
242 send.setChecked(false);
243 send.setText(R.string.send_presence_updates);
244 } else {
245 send.setText(R.string.preemptively_grant);
246 if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
247 send.setChecked(true);
248 } else {
249 send.setChecked(false);
250 }
251 }
252 if (contact.getOption(Contact.Options.TO)) {
253 receive.setText(R.string.receive_presence_updates);
254 receive.setChecked(true);
255 } else {
256 receive.setText(R.string.ask_for_presence_updates);
257 if (contact.getOption(Contact.Options.ASKING)) {
258 receive.setChecked(true);
259 } else {
260 receive.setChecked(false);
261 }
262 }
263 if (contact.getAccount().getStatus() == Account.STATUS_ONLINE) {
264 receive.setEnabled(true);
265 send.setEnabled(true);
266 } else {
267 receive.setEnabled(false);
268 send.setEnabled(false);
269 }
270
271 send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
272 receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
273
274 lastseen.setText(UIHelper.lastseen(getApplicationContext(),
275 contact.lastseen.time));
276
277 switch (contact.getMostAvailableStatus()) {
278 case Presences.CHAT:
279 status.setText(R.string.contact_status_free_to_chat);
280 status.setTextColor(0xFF83b600);
281 break;
282 case Presences.ONLINE:
283 status.setText(R.string.contact_status_online);
284 status.setTextColor(0xFF83b600);
285 break;
286 case Presences.AWAY:
287 status.setText(R.string.contact_status_away);
288 status.setTextColor(0xFFffa713);
289 break;
290 case Presences.XA:
291 status.setText(R.string.contact_status_extended_away);
292 status.setTextColor(0xFFffa713);
293 break;
294 case Presences.DND:
295 status.setText(R.string.contact_status_do_not_disturb);
296 status.setTextColor(0xFFe92727);
297 break;
298 case Presences.OFFLINE:
299 status.setText(R.string.contact_status_offline);
300 status.setTextColor(0xFFe92727);
301 break;
302 default:
303 status.setText(R.string.contact_status_offline);
304 status.setTextColor(0xFFe92727);
305 break;
306 }
307 if (contact.getPresences().size() > 1) {
308 contactJidTv.setText(contact.getJid() + " ("
309 + contact.getPresences().size() + ")");
310 } else {
311 contactJidTv.setText(contact.getJid());
312 }
313 accountJidTv.setText(contact.getAccount().getJid());
314
315 UIHelper.prepareContactBadge(this, badge, contact,
316 getApplicationContext());
317
318 if (contact.getSystemAccount() == null) {
319 badge.setOnClickListener(onBadgeClick);
320 }
321
322 keys.removeAllViews();
323 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
324 for (Iterator<String> iterator = contact.getOtrFingerprints()
325 .iterator(); iterator.hasNext();) {
326 String otrFingerprint = iterator.next();
327 View view = (View) inflater.inflate(R.layout.contact_key, null);
328 TextView key = (TextView) view.findViewById(R.id.key);
329 TextView keyType = (TextView) view.findViewById(R.id.key_type);
330 keyType.setText("OTR Fingerprint");
331 key.setText(otrFingerprint);
332 keys.addView(view);
333 }
334 if (contact.getPgpKeyId() != 0) {
335 View view = (View) inflater.inflate(R.layout.contact_key, null);
336 TextView key = (TextView) view.findViewById(R.id.key);
337 TextView keyType = (TextView) view.findViewById(R.id.key_type);
338 keyType.setText("PGP Key ID");
339 key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
340 view.setOnClickListener(new OnClickListener() {
341
342 @Override
343 public void onClick(View v) {
344 PgpEngine pgp = activity.xmppConnectionService
345 .getPgpEngine();
346 if (pgp != null) {
347 PendingIntent intent = pgp.getIntentForKey(contact);
348 if (intent != null) {
349 try {
350 startIntentSenderForResult(
351 intent.getIntentSender(), 0, null, 0,
352 0, 0);
353 } catch (SendIntentException e) {
354
355 }
356 }
357 }
358 }
359 });
360 keys.addView(view);
361 }
362 }
363
364 @Override
365 public void onBackendConnected() {
366 xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
367 xmppConnectionService
368 .setOnAccountListChangedListener(this.accountUpdate);
369 if ((accountJid != null) && (contactJid != null)) {
370 Account account = xmppConnectionService
371 .findAccountByJid(accountJid);
372 if (account == null) {
373 return;
374 }
375 this.contact = account.getRoster().getContact(contactJid);
376 populateView();
377 }
378 }
379
380 @Override
381 protected void onStop() {
382 super.onStop();
383 xmppConnectionService.removeOnRosterUpdateListener();
384 xmppConnectionService.removeOnAccountListChangedListener();
385 }
386
387}