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