ConferenceDetailsActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.annotation.TargetApi;
  4import android.app.AlertDialog;
  5import android.app.PendingIntent;
  6import android.content.Context;
  7import android.content.DialogInterface;
  8import android.content.IntentSender.SendIntentException;
  9import android.graphics.Bitmap;
 10import android.os.Build;
 11import android.os.Bundle;
 12import android.view.ContextMenu;
 13import android.view.LayoutInflater;
 14import android.view.Menu;
 15import android.view.MenuItem;
 16import android.view.View;
 17import android.view.View.OnClickListener;
 18import android.widget.Button;
 19import android.widget.ImageButton;
 20import android.widget.ImageView;
 21import android.widget.LinearLayout;
 22import android.widget.TextView;
 23import android.widget.Toast;
 24
 25import org.openintents.openpgp.util.OpenPgpUtils;
 26
 27import java.util.ArrayList;
 28import java.util.Collections;
 29import java.util.Comparator;
 30
 31import eu.siacs.conversations.Config;
 32import eu.siacs.conversations.R;
 33import eu.siacs.conversations.crypto.PgpEngine;
 34import eu.siacs.conversations.entities.Account;
 35import eu.siacs.conversations.entities.Bookmark;
 36import eu.siacs.conversations.entities.Contact;
 37import eu.siacs.conversations.entities.Conversation;
 38import eu.siacs.conversations.entities.MucOptions;
 39import eu.siacs.conversations.entities.MucOptions.User;
 40import eu.siacs.conversations.services.XmppConnectionService;
 41import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
 42import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate;
 43import eu.siacs.conversations.xmpp.jid.Jid;
 44
 45public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnRoleChanged, XmppConnectionService.OnConferenceOptionsPushed {
 46	public static final String ACTION_VIEW_MUC = "view_muc";
 47	private Conversation mConversation;
 48	private OnClickListener inviteListener = new OnClickListener() {
 49
 50		@Override
 51		public void onClick(View v) {
 52			inviteToConversation(mConversation);
 53		}
 54	};
 55	private TextView mYourNick;
 56	private ImageView mYourPhoto;
 57	private ImageButton mEditNickButton;
 58	private TextView mRoleAffiliaton;
 59	private TextView mFullJid;
 60	private TextView mAccountJid;
 61	private LinearLayout membersView;
 62	private LinearLayout mMoreDetails;
 63	private TextView mConferenceType;
 64	private ImageButton mChangeConferenceSettingsButton;
 65	private Button mInviteButton;
 66	private String uuid = null;
 67	private User mSelectedUser = null;
 68
 69	private boolean mAdvancedMode = false;
 70
 71	private UiCallback<Conversation> renameCallback = new UiCallback<Conversation>() {
 72		@Override
 73		public void success(Conversation object) {
 74			runOnUiThread(new Runnable() {
 75				@Override
 76				public void run() {
 77					Toast.makeText(ConferenceDetailsActivity.this,getString(R.string.your_nick_has_been_changed),Toast.LENGTH_SHORT).show();
 78					updateView();
 79				}
 80			});
 81
 82		}
 83
 84		@Override
 85		public void error(final int errorCode, Conversation object) {
 86			runOnUiThread(new Runnable() {
 87				@Override
 88				public void run() {
 89					Toast.makeText(ConferenceDetailsActivity.this,getString(errorCode),Toast.LENGTH_SHORT).show();
 90				}
 91			});
 92		}
 93
 94		@Override
 95		public void userInputRequried(PendingIntent pi, Conversation object) {
 96
 97		}
 98	};
 99	private OnClickListener mChangeConferenceSettings = new OnClickListener() {
100		@Override
101		public void onClick(View v) {
102			final MucOptions mucOptions = mConversation.getMucOptions();
103			AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
104			builder.setTitle(R.string.conference_options);
105			final String[] options;
106			final boolean[] values;
107			if (mAdvancedMode) {
108				options = new String[]{
109						getString(R.string.members_only),
110						getString(R.string.moderated),
111						getString(R.string.non_anonymous)
112				};
113				values = new boolean[]{
114						mucOptions.membersOnly(),
115						mucOptions.moderated(),
116						mucOptions.nonanonymous()
117				};
118			} else {
119				options = new String[]{
120						getString(R.string.members_only),
121						getString(R.string.non_anonymous)
122				};
123				values = new boolean[]{
124						mucOptions.membersOnly(),
125						mucOptions.nonanonymous()
126				};
127			}
128			builder.setMultiChoiceItems(options,values,new DialogInterface.OnMultiChoiceClickListener() {
129				@Override
130				public void onClick(DialogInterface dialog, int which, boolean isChecked) {
131					values[which] = isChecked;
132				}
133			});
134			builder.setNegativeButton(R.string.cancel, null);
135			builder.setPositiveButton(R.string.confirm,new DialogInterface.OnClickListener() {
136				@Override
137				public void onClick(DialogInterface dialog, int which) {
138					if (!mucOptions.membersOnly() && values[0]) {
139						xmppConnectionService.changeAffiliationsInConference(mConversation,
140								MucOptions.Affiliation.NONE,
141								MucOptions.Affiliation.MEMBER);
142					}
143					Bundle options = new Bundle();
144					options.putString("muc#roomconfig_membersonly", values[0] ? "1" : "0");
145					if (values.length == 2) {
146						options.putString("muc#roomconfig_whois", values[1] ? "anyone" : "moderators");
147					} else if (values.length == 3) {
148						options.putString("muc#roomconfig_moderatedroom", values[1] ? "1" : "0");
149						options.putString("muc#roomconfig_whois", values[2] ? "anyone" : "moderators");
150					}
151					options.putString("muc#roomconfig_persistentroom", "1");
152					xmppConnectionService.pushConferenceConfiguration(mConversation,
153							options,
154							ConferenceDetailsActivity.this);
155				}
156			});
157			builder.create().show();
158		}
159	};
160	private OnValueEdited onSubjectEdited = new OnValueEdited() {
161
162		@Override
163		public void onValueEdited(String value) {
164			xmppConnectionService.pushSubjectToConference(mConversation,value);
165		}
166	};
167
168	@Override
169	public void onConversationUpdate() {
170		refreshUi();
171	}
172
173	@Override
174	public void onMucRosterUpdate() {
175		refreshUi();
176	}
177
178	@Override
179	protected void refreshUiReal() {
180		updateView();
181	}
182
183	@Override
184	protected void onCreate(Bundle savedInstanceState) {
185		super.onCreate(savedInstanceState);
186		setContentView(R.layout.activity_muc_details);
187		mYourNick = (TextView) findViewById(R.id.muc_your_nick);
188		mYourPhoto = (ImageView) findViewById(R.id.your_photo);
189		mEditNickButton = (ImageButton) findViewById(R.id.edit_nick_button);
190		mFullJid = (TextView) findViewById(R.id.muc_jabberid);
191		membersView = (LinearLayout) findViewById(R.id.muc_members);
192		mAccountJid = (TextView) findViewById(R.id.details_account);
193		mMoreDetails = (LinearLayout) findViewById(R.id.muc_more_details);
194		mMoreDetails.setVisibility(View.GONE);
195		mChangeConferenceSettingsButton = (ImageButton) findViewById(R.id.change_conference_button);
196		mChangeConferenceSettingsButton.setOnClickListener(this.mChangeConferenceSettings);
197		mConferenceType = (TextView) findViewById(R.id.muc_conference_type);
198		mInviteButton = (Button) findViewById(R.id.invite);
199		mInviteButton.setOnClickListener(inviteListener);
200		mConferenceType = (TextView) findViewById(R.id.muc_conference_type);
201		if (getActionBar() != null) {
202			getActionBar().setHomeButtonEnabled(true);
203			getActionBar().setDisplayHomeAsUpEnabled(true);
204		}
205		mEditNickButton.setOnClickListener(new OnClickListener() {
206
207			@Override
208			public void onClick(View v) {
209				quickEdit(mConversation.getMucOptions().getActualNick(),
210						new OnValueEdited() {
211
212							@Override
213							public void onValueEdited(String value) {
214								xmppConnectionService.renameInMuc(mConversation,value,renameCallback);
215							}
216						});
217			}
218		});
219		this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false);
220	}
221
222	@Override
223	public boolean onOptionsItemSelected(MenuItem menuItem) {
224		switch (menuItem.getItemId()) {
225			case android.R.id.home:
226				finish();
227				break;
228			case R.id.action_edit_subject:
229				if (mConversation != null) {
230					quickEdit(mConversation.getName(),this.onSubjectEdited);
231				}
232				break;
233			case R.id.action_save_as_bookmark:
234				saveAsBookmark();
235				break;
236			case R.id.action_delete_bookmark:
237				deleteBookmark();
238				break;
239			case R.id.action_advanced_mode:
240				this.mAdvancedMode = !menuItem.isChecked();
241				menuItem.setChecked(this.mAdvancedMode);
242				getPreferences().edit().putBoolean("advanced_muc_mode", mAdvancedMode).commit();
243				invalidateOptionsMenu();
244				updateView();
245				break;
246		}
247		return super.onOptionsItemSelected(menuItem);
248	}
249
250	@Override
251	protected String getShareableUri() {
252		if (mConversation != null) {
253			return "xmpp:" + mConversation.getJid().toBareJid().toString() + "?join";
254		} else {
255			return "";
256		}
257	}
258
259	@Override
260	public boolean onPrepareOptionsMenu(Menu menu) {
261		MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
262		MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
263		MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
264		menuItemAdvancedMode.setChecked(mAdvancedMode);
265		if (mConversation == null) {
266			return true;
267		}
268		Account account = mConversation.getAccount();
269		if (account.hasBookmarkFor(mConversation.getJid().toBareJid())) {
270			menuItemSaveBookmark.setVisible(false);
271			menuItemDeleteBookmark.setVisible(true);
272		} else {
273			menuItemDeleteBookmark.setVisible(false);
274			menuItemSaveBookmark.setVisible(true);
275		}
276		return true;
277	}
278
279	@Override
280	public boolean onCreateOptionsMenu(Menu menu) {
281		getMenuInflater().inflate(R.menu.muc_details, menu);
282		return true;
283	}
284
285	@Override
286	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
287		Object tag = v.getTag();
288		if (tag instanceof User) {
289			getMenuInflater().inflate(R.menu.muc_details_context,menu);
290			final User user = (User) tag;
291			final User self = mConversation.getMucOptions().getSelf();
292			this.mSelectedUser = user;
293			String name;
294			final Contact contact = user.getContact();
295			if (contact != null) {
296				name = contact.getDisplayName();
297			} else if (user.getJid() != null){
298				name = user.getJid().toBareJid().toString();
299			} else {
300				name = user.getName();
301			}
302			menu.setHeaderTitle(name);
303			if (user.getJid() != null) {
304				MenuItem showContactDetails = menu.findItem(R.id.action_contact_details);
305				MenuItem startConversation = menu.findItem(R.id.start_conversation);
306				MenuItem giveMembership = menu.findItem(R.id.give_membership);
307				MenuItem removeMembership = menu.findItem(R.id.remove_membership);
308				MenuItem giveAdminPrivileges = menu.findItem(R.id.give_admin_privileges);
309				MenuItem removeAdminPrivileges = menu.findItem(R.id.remove_admin_privileges);
310				MenuItem removeFromRoom = menu.findItem(R.id.remove_from_room);
311				MenuItem banFromConference = menu.findItem(R.id.ban_from_conference);
312				startConversation.setVisible(true);
313				if (contact != null) {
314					showContactDetails.setVisible(true);
315				}
316				if (self.getAffiliation().ranks(MucOptions.Affiliation.ADMIN) &&
317						self.getAffiliation().outranks(user.getAffiliation())) {
318					if (mAdvancedMode) {
319						if (user.getAffiliation() == MucOptions.Affiliation.NONE) {
320							giveMembership.setVisible(true);
321						} else {
322							removeMembership.setVisible(true);
323						}
324						banFromConference.setVisible(true);
325					} else {
326						removeFromRoom.setVisible(true);
327					}
328					if (user.getAffiliation() != MucOptions.Affiliation.ADMIN) {
329						giveAdminPrivileges.setVisible(true);
330					} else {
331						removeAdminPrivileges.setVisible(true);
332					}
333				}
334			} else {
335				MenuItem sendPrivateMessage = menu.findItem(R.id.send_private_message);
336				sendPrivateMessage.setVisible(true);
337			}
338
339		}
340		super.onCreateContextMenu(menu, v, menuInfo);
341	}
342
343	@Override
344	public boolean onContextItemSelected(MenuItem item) {
345		switch (item.getItemId()) {
346			case R.id.action_contact_details:
347				Contact contact = mSelectedUser.getContact();
348				if (contact != null) {
349					switchToContactDetails(contact);
350				}
351				return true;
352			case R.id.start_conversation:
353				startConversation(mSelectedUser);
354				return true;
355			case R.id.give_admin_privileges:
356				xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.ADMIN,this);
357				return true;
358			case R.id.give_membership:
359				xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.MEMBER,this);
360				return true;
361			case R.id.remove_membership:
362				xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.NONE,this);
363				return true;
364			case R.id.remove_admin_privileges:
365				xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.MEMBER,this);
366				return true;
367			case R.id.remove_from_room:
368				removeFromRoom(mSelectedUser);
369				return true;
370			case R.id.ban_from_conference:
371				xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.OUTCAST,this);
372				xmppConnectionService.changeRoleInConference(mConversation,mSelectedUser.getName(), MucOptions.Role.NONE,this);
373				return true;
374			case R.id.send_private_message:
375				privateMsgInMuc(mConversation,mSelectedUser.getName());
376				return true;
377			default:
378				return super.onContextItemSelected(item);
379		}
380	}
381
382	private void removeFromRoom(final User user) {
383		if (mConversation.getMucOptions().membersOnly()) {
384			xmppConnectionService.changeAffiliationInConference(mConversation,user.getJid(), MucOptions.Affiliation.NONE,this);
385			xmppConnectionService.changeRoleInConference(mConversation,mSelectedUser.getName(), MucOptions.Role.NONE,ConferenceDetailsActivity.this);
386		} else {
387			AlertDialog.Builder builder = new AlertDialog.Builder(this);
388			builder.setTitle(R.string.ban_from_conference);
389			builder.setMessage(getString(R.string.removing_from_public_conference,user.getName()));
390			builder.setNegativeButton(R.string.cancel,null);
391			builder.setPositiveButton(R.string.ban_now,new DialogInterface.OnClickListener() {
392				@Override
393				public void onClick(DialogInterface dialog, int which) {
394					xmppConnectionService.changeAffiliationInConference(mConversation,user.getJid(), MucOptions.Affiliation.OUTCAST,ConferenceDetailsActivity.this);
395					xmppConnectionService.changeRoleInConference(mConversation,mSelectedUser.getName(), MucOptions.Role.NONE,ConferenceDetailsActivity.this);
396				}
397			});
398			builder.create().show();
399		}
400	}
401
402	protected void startConversation(User user) {
403		if (user.getJid() != null) {
404			Conversation conversation = xmppConnectionService.findOrCreateConversation(this.mConversation.getAccount(),user.getJid().toBareJid(),false);
405			switchToConversation(conversation);
406		}
407	}
408
409	protected void saveAsBookmark() {
410		Account account = mConversation.getAccount();
411		Bookmark bookmark = new Bookmark(account, mConversation.getJid().toBareJid());
412		if (!mConversation.getJid().isBareJid()) {
413			bookmark.setNick(mConversation.getJid().getResourcepart());
414		}
415		bookmark.setAutojoin(true);
416		account.getBookmarks().add(bookmark);
417		xmppConnectionService.pushBookmarks(account);
418		mConversation.setBookmark(bookmark);
419	}
420
421	protected void deleteBookmark() {
422		Account account = mConversation.getAccount();
423		Bookmark bookmark = mConversation.getBookmark();
424		bookmark.unregisterConversation();
425		account.getBookmarks().remove(bookmark);
426		xmppConnectionService.pushBookmarks(account);
427	}
428
429	@Override
430	void onBackendConnected() {
431		if (mPendingConferenceInvite != null) {
432			mPendingConferenceInvite.execute(this);
433			mPendingConferenceInvite = null;
434		}
435		if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
436			this.uuid = getIntent().getExtras().getString("uuid");
437		}
438		if (uuid != null) {
439			this.mConversation = xmppConnectionService
440				.findConversationByUuid(uuid);
441			if (this.mConversation != null) {
442				updateView();
443			}
444		}
445	}
446
447	private void updateView() {
448		final MucOptions mucOptions = mConversation.getMucOptions();
449		final User self = mucOptions.getSelf();
450		String account;
451		if (Config.DOMAIN_LOCK != null) {
452			account = mConversation.getAccount().getJid().getLocalpart();
453		} else {
454			account = mConversation.getAccount().getJid().toBareJid().toString();
455		}
456		mAccountJid.setText(getString(R.string.using_account, account));
457		mYourPhoto.setImageBitmap(avatarService().get(mConversation.getAccount(), getPixel(48)));
458		setTitle(mConversation.getName());
459		mFullJid.setText(mConversation.getJid().toBareJid().toString());
460		mYourNick.setText(mucOptions.getActualNick());
461		mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
462		if (mucOptions.online()) {
463			mMoreDetails.setVisibility(View.VISIBLE);
464			final String status = getStatus(self);
465			if (status != null) {
466				mRoleAffiliaton.setVisibility(View.VISIBLE);
467				mRoleAffiliaton.setText(status);
468			} else {
469				mRoleAffiliaton.setVisibility(View.GONE);
470			}
471			if (mucOptions.membersOnly()) {
472				mConferenceType.setText(R.string.private_conference);
473			} else {
474				mConferenceType.setText(R.string.public_conference);
475			}
476			if (self.getAffiliation().ranks(MucOptions.Affiliation.OWNER)) {
477				mChangeConferenceSettingsButton.setVisibility(View.VISIBLE);
478			} else {
479				mChangeConferenceSettingsButton.setVisibility(View.GONE);
480			}
481		}
482		LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
483		membersView.removeAllViews();
484		final ArrayList<User> users = new ArrayList<>();
485		users.addAll(mConversation.getMucOptions().getUsers());
486		Collections.sort(users,new Comparator<User>() {
487			@Override
488			public int compare(User lhs, User rhs) {
489				return lhs.getName().compareToIgnoreCase(rhs.getName());
490			}
491		});
492		for (final User user : users) {
493			View view = inflater.inflate(R.layout.contact, membersView,false);
494			this.setListItemBackgroundOnView(view);
495			view.setOnClickListener(new OnClickListener() {
496				@Override
497				public void onClick(View view) {
498					highlightInMuc(mConversation, user.getName());
499				}
500			});
501			registerForContextMenu(view);
502			view.setTag(user);
503			TextView tvDisplayName = (TextView) view.findViewById(R.id.contact_display_name);
504			TextView tvKey = (TextView) view.findViewById(R.id.key);
505			TextView tvStatus = (TextView) view.findViewById(R.id.contact_jid);
506			if (mAdvancedMode && user.getPgpKeyId() != 0) {
507				tvKey.setVisibility(View.VISIBLE);
508				tvKey.setOnClickListener(new OnClickListener() {
509
510					@Override
511					public void onClick(View v) {
512						viewPgpKey(user);
513					}
514				});
515				tvKey.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId()));
516			}
517			Bitmap bm;
518			Contact contact = user.getContact();
519			if (contact != null) {
520				bm = avatarService().get(contact, getPixel(48));
521				tvDisplayName.setText(contact.getDisplayName());
522				tvStatus.setText(user.getName() + " \u2022 " + getStatus(user));
523			} else {
524				bm = avatarService().get(user.getName(), getPixel(48));
525				tvDisplayName.setText(user.getName());
526				tvStatus.setText(getStatus(user));
527
528			}
529			ImageView iv = (ImageView) view.findViewById(R.id.contact_photo);
530			iv.setImageBitmap(bm);
531			membersView.addView(view);
532			if (mConversation.getMucOptions().canInvite()) {
533				mInviteButton.setVisibility(View.VISIBLE);
534			} else {
535				mInviteButton.setVisibility(View.GONE);
536			}
537		}
538	}
539
540	private String getStatus(User user) {
541		if (mAdvancedMode) {
542			StringBuilder builder = new StringBuilder();
543			builder.append(getString(user.getAffiliation().getResId()));
544			builder.append(" (");
545			builder.append(getString(user.getRole().getResId()));
546			builder.append(')');
547			return builder.toString();
548		} else {
549			return getString(user.getAffiliation().getResId());
550		}
551	}
552
553	@SuppressWarnings("deprecation")
554	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
555	private void setListItemBackgroundOnView(View view) {
556		int sdk = android.os.Build.VERSION.SDK_INT;
557		if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
558			view.setBackgroundDrawable(getResources().getDrawable(R.drawable.greybackground));
559		} else {
560			view.setBackground(getResources().getDrawable(R.drawable.greybackground));
561		}
562	}
563
564	private void viewPgpKey(User user) {
565		PgpEngine pgp = xmppConnectionService.getPgpEngine();
566		if (pgp != null) {
567			PendingIntent intent = pgp.getIntentForKey(
568					mConversation.getAccount(), user.getPgpKeyId());
569			if (intent != null) {
570				try {
571					startIntentSenderForResult(intent.getIntentSender(), 0,
572							null, 0, 0, 0);
573				} catch (SendIntentException ignored) {
574
575				}
576			}
577		}
578	}
579
580	@Override
581	public void onAffiliationChangedSuccessful(Jid jid) {
582
583	}
584
585	@Override
586	public void onAffiliationChangeFailed(Jid jid, int resId) {
587		displayToast(getString(resId,jid.toBareJid().toString()));
588	}
589
590	@Override
591	public void onRoleChangedSuccessful(String nick) {
592
593	}
594
595	@Override
596	public void onRoleChangeFailed(String nick, int resId) {
597		displayToast(getString(resId,nick));
598	}
599
600	@Override
601	public void onPushSucceeded() {
602		displayToast(getString(R.string.modified_conference_options));
603	}
604
605	@Override
606	public void onPushFailed() {
607		displayToast(getString(R.string.could_not_modify_conference_options));
608	}
609
610	private void displayToast(final String msg) {
611		runOnUiThread(new Runnable() {
612			@Override
613			public void run() {
614				Toast.makeText(ConferenceDetailsActivity.this,msg,Toast.LENGTH_SHORT).show();
615			}
616		});
617	}
618}