StartConversationActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.ArrayList;
  4import java.util.Collections;
  5import java.util.List;
  6
  7import android.app.ActionBar;
  8import android.app.ActionBar.Tab;
  9import android.app.ActionBar.TabListener;
 10import android.app.AlertDialog;
 11import android.app.Fragment;
 12import android.app.FragmentTransaction;
 13import android.app.ListFragment;
 14import android.content.Context;
 15import android.content.DialogInterface;
 16import android.content.DialogInterface.OnClickListener;
 17import android.os.Bundle;
 18import android.support.v13.app.FragmentPagerAdapter;
 19import android.support.v4.view.ViewPager;
 20import android.text.Editable;
 21import android.text.TextWatcher;
 22import android.view.ContextMenu;
 23import android.view.ContextMenu.ContextMenuInfo;
 24import android.view.KeyEvent;
 25import android.view.Menu;
 26import android.view.MenuItem;
 27import android.view.View;
 28import android.view.inputmethod.InputMethodManager;
 29import android.widget.AdapterView;
 30import android.widget.AdapterView.AdapterContextMenuInfo;
 31import android.widget.AdapterView.OnItemClickListener;
 32import android.widget.ArrayAdapter;
 33import android.widget.AutoCompleteTextView;
 34import android.widget.CheckBox;
 35import android.widget.EditText;
 36import android.widget.ListView;
 37import android.widget.Spinner;
 38import eu.siacs.conversations.R;
 39import eu.siacs.conversations.entities.Account;
 40import eu.siacs.conversations.entities.Bookmark;
 41import eu.siacs.conversations.entities.Contact;
 42import eu.siacs.conversations.entities.Conversation;
 43import eu.siacs.conversations.entities.ListItem;
 44import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 45import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 46import eu.siacs.conversations.ui.adapter.ListItemAdapter;
 47import eu.siacs.conversations.utils.Validator;
 48
 49public class StartConversationActivity extends XmppActivity {
 50
 51	private Tab mContactsTab;
 52	private Tab mConferencesTab;
 53	private ViewPager mViewPager;
 54
 55	private MyListFragment mContactsListFragment = new MyListFragment();
 56	private List<ListItem> contacts = new ArrayList<ListItem>();
 57	private ArrayAdapter<ListItem> mContactsAdapter;
 58
 59	private MyListFragment mConferenceListFragment = new MyListFragment();
 60	private List<ListItem> conferences = new ArrayList<ListItem>();
 61	private ArrayAdapter<ListItem> mConferenceAdapter;
 62
 63	private List<String> mActivatedAccounts = new ArrayList<String>();
 64	private List<String> mKnownHosts;
 65	private List<String> mKnownConferenceHosts;
 66
 67	private Menu mOptionsMenu;
 68	private EditText mSearchEditText;
 69
 70	public int conference_context_id;
 71	public int contact_context_id;
 72
 73	private TabListener mTabListener = new TabListener() {
 74
 75		@Override
 76		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
 77			return;
 78		}
 79
 80		@Override
 81		public void onTabSelected(Tab tab, FragmentTransaction ft) {
 82			mViewPager.setCurrentItem(tab.getPosition());
 83			onTabChanged();
 84		}
 85
 86		@Override
 87		public void onTabReselected(Tab tab, FragmentTransaction ft) {
 88			return;
 89		}
 90	};
 91
 92	private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
 93		@Override
 94		public void onPageSelected(int position) {
 95			getActionBar().setSelectedNavigationItem(position);
 96			onTabChanged();
 97		}
 98	};
 99
100	private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
101
102		@Override
103		public boolean onMenuItemActionExpand(MenuItem item) {
104			mSearchEditText.post(new Runnable() {
105
106				@Override
107				public void run() {
108					mSearchEditText.requestFocus();
109					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
110					imm.showSoftInput(mSearchEditText,
111							InputMethodManager.SHOW_IMPLICIT);
112				}
113			});
114
115			return true;
116		}
117
118		@Override
119		public boolean onMenuItemActionCollapse(MenuItem item) {
120			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
121			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
122					InputMethodManager.HIDE_IMPLICIT_ONLY);
123			mSearchEditText.setText("");
124			filter(null);
125			return true;
126		}
127	};
128	private TextWatcher mSearchTextWatcher = new TextWatcher() {
129
130		@Override
131		public void afterTextChanged(Editable editable) {
132			filter(editable.toString());
133		}
134
135		@Override
136		public void beforeTextChanged(CharSequence s, int start, int count,
137				int after) {
138		}
139
140		@Override
141		public void onTextChanged(CharSequence s, int start, int before,
142				int count) {
143		}
144	};
145	private OnRosterUpdate onRosterUpdate = new OnRosterUpdate() {
146
147		@Override
148		public void onRosterUpdate() {
149			runOnUiThread(new Runnable() {
150
151				@Override
152				public void run() {
153					if (mSearchEditText != null) {
154						filter(mSearchEditText.getText().toString());
155					}
156				}
157			});
158		}
159	};
160
161	@Override
162	public void onCreate(Bundle savedInstanceState) {
163		super.onCreate(savedInstanceState);
164		setContentView(R.layout.activity_start_conversation);
165		mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
166		ActionBar actionBar = getActionBar();
167		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
168
169		mContactsTab = actionBar.newTab().setText(R.string.contacts)
170				.setTabListener(mTabListener);
171		mConferencesTab = actionBar.newTab().setText(R.string.conferences)
172				.setTabListener(mTabListener);
173		actionBar.addTab(mContactsTab);
174		actionBar.addTab(mConferencesTab);
175
176		mViewPager.setOnPageChangeListener(mOnPageChangeListener);
177		mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
178
179			@Override
180			public int getCount() {
181				return 2;
182			}
183
184			@Override
185			public Fragment getItem(int position) {
186				if (position == 0) {
187					return mContactsListFragment;
188				} else {
189					return mConferenceListFragment;
190				}
191			}
192		});
193
194		mConferenceAdapter = new ListItemAdapter(getApplicationContext(),
195				conferences);
196		mConferenceListFragment.setListAdapter(mConferenceAdapter);
197		mConferenceListFragment.setContextMenu(R.menu.conference_context);
198		mConferenceListFragment
199				.setOnListItemClickListener(new OnItemClickListener() {
200
201					@Override
202					public void onItemClick(AdapterView<?> arg0, View arg1,
203							int position, long arg3) {
204						openConversationForBookmark(position);
205					}
206				});
207
208		mContactsAdapter = new ListItemAdapter(getApplicationContext(),
209				contacts);
210		mContactsListFragment.setListAdapter(mContactsAdapter);
211		mContactsListFragment.setContextMenu(R.menu.contact_context);
212		mContactsListFragment
213				.setOnListItemClickListener(new OnItemClickListener() {
214
215					@Override
216					public void onItemClick(AdapterView<?> arg0, View arg1,
217							int position, long arg3) {
218						openConversationForContact(position);
219					}
220				});
221
222	}
223
224	@Override
225	public void onStop() {
226		super.onStop();
227		xmppConnectionService.removeOnRosterUpdateListener();
228	}
229
230	protected void openConversationForContact(int position) {
231		Contact contact = (Contact) contacts.get(position);
232		Conversation conversation = xmppConnectionService
233				.findOrCreateConversation(contact.getAccount(),
234						contact.getJid(), false);
235		switchToConversation(conversation);
236	}
237
238	protected void openConversationForContact() {
239		int position = contact_context_id;
240		openConversationForContact(position);
241	}
242
243	protected void openConversationForBookmark() {
244		openConversationForBookmark(conference_context_id);
245	}
246
247	protected void openConversationForBookmark(int position) {
248		Bookmark bookmark = (Bookmark) conferences.get(position);
249		Conversation conversation = xmppConnectionService
250				.findOrCreateConversation(bookmark.getAccount(),
251						bookmark.getJid(), true);
252		conversation.setBookmark(bookmark);
253		if (!conversation.getMucOptions().online()) {
254			xmppConnectionService.joinMuc(conversation);
255		}
256		if (!bookmark.autojoin()) {
257			bookmark.setAutojoin(true);
258			xmppConnectionService.pushBookmarks(bookmark.getAccount());
259		}
260		switchToConversation(conversation);
261	}
262
263	protected void openDetailsForContact() {
264		int position = contact_context_id;
265		Contact contact = (Contact) contacts.get(position);
266		switchToContactDetails(contact);
267	}
268
269	protected void deleteContact() {
270		int position = contact_context_id;
271		final Contact contact = (Contact) contacts.get(position);
272		AlertDialog.Builder builder = new AlertDialog.Builder(this);
273		builder.setNegativeButton(R.string.cancel, null);
274		builder.setTitle(R.string.action_delete_contact);
275		builder.setMessage(getString(R.string.remove_contact_text,
276				contact.getJid()));
277		builder.setPositiveButton(R.string.delete, new OnClickListener() {
278
279			@Override
280			public void onClick(DialogInterface dialog, int which) {
281				xmppConnectionService.deleteContactOnServer(contact);
282				filter(mSearchEditText.getText().toString());
283			}
284		});
285		builder.create().show();
286
287	}
288
289	protected void deleteConference() {
290		int position = conference_context_id;
291		final Bookmark bookmark = (Bookmark) conferences.get(position);
292
293		AlertDialog.Builder builder = new AlertDialog.Builder(this);
294		builder.setNegativeButton(R.string.cancel, null);
295		builder.setTitle(R.string.delete_bookmark);
296		builder.setMessage(getString(R.string.remove_bookmark_text,
297				bookmark.getJid()));
298		builder.setPositiveButton(R.string.delete, new OnClickListener() {
299
300			@Override
301			public void onClick(DialogInterface dialog, int which) {
302				bookmark.unregisterConversation();
303				Account account = bookmark.getAccount();
304				account.getBookmarks().remove(bookmark);
305				xmppConnectionService.pushBookmarks(account);
306				filter(mSearchEditText.getText().toString());
307			}
308		});
309		builder.create().show();
310
311	}
312
313	protected void showCreateContactDialog() {
314		AlertDialog.Builder builder = new AlertDialog.Builder(this);
315		builder.setTitle(R.string.create_contact);
316		View dialogView = getLayoutInflater().inflate(
317				R.layout.create_contact_dialog, null);
318		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
319		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
320				.findViewById(R.id.jid);
321		jid.setAdapter(new KnownHostsAdapter(this,
322				android.R.layout.simple_list_item_1, mKnownHosts));
323		populateAccountSpinner(spinner);
324		builder.setView(dialogView);
325		builder.setNegativeButton(R.string.cancel, null);
326		builder.setPositiveButton(R.string.create, null);
327		final AlertDialog dialog = builder.create();
328		dialog.show();
329		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
330				new View.OnClickListener() {
331
332					@Override
333					public void onClick(View v) {
334						if (!xmppConnectionServiceBound) {
335							return;
336						}
337						if (Validator.isValidJid(jid.getText().toString())) {
338							String accountJid = (String) spinner
339									.getSelectedItem();
340							String contactJid = jid.getText().toString();
341							Account account = xmppConnectionService
342									.findAccountByJid(accountJid);
343							if (account == null) {
344								dialog.dismiss();
345								return;
346							}
347							Contact contact = account.getRoster().getContact(
348									contactJid);
349							if (contact.showInRoster()) {
350								jid.setError(getString(R.string.contact_already_exists));
351							} else {
352								xmppConnectionService.createContact(contact);
353								switchToConversation(contact);
354								dialog.dismiss();
355							}
356						} else {
357							jid.setError(getString(R.string.invalid_jid));
358						}
359					}
360				});
361
362	}
363
364	protected void showJoinConferenceDialog() {
365		AlertDialog.Builder builder = new AlertDialog.Builder(this);
366		builder.setTitle(R.string.join_conference);
367		View dialogView = getLayoutInflater().inflate(
368				R.layout.join_conference_dialog, null);
369		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
370		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
371				.findViewById(R.id.jid);
372		jid.setAdapter(new KnownHostsAdapter(this,
373				android.R.layout.simple_list_item_1, mKnownConferenceHosts));
374		populateAccountSpinner(spinner);
375		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
376				.findViewById(R.id.bookmark);
377		builder.setView(dialogView);
378		builder.setNegativeButton(R.string.cancel, null);
379		builder.setPositiveButton(R.string.join, null);
380		final AlertDialog dialog = builder.create();
381		dialog.show();
382		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
383				new View.OnClickListener() {
384
385					@Override
386					public void onClick(View v) {
387						if (!xmppConnectionServiceBound) {
388							return;
389						}
390						if (Validator.isValidJid(jid.getText().toString())) {
391							String accountJid = (String) spinner
392									.getSelectedItem();
393							String conferenceJid = jid.getText().toString();
394							Account account = xmppConnectionService
395									.findAccountByJid(accountJid);
396							if (bookmarkCheckBox.isChecked()) {
397								if (account.hasBookmarkFor(conferenceJid)) {
398									jid.setError(getString(R.string.bookmark_already_exists));
399								} else {
400									Bookmark bookmark = new Bookmark(account,
401											conferenceJid);
402									bookmark.setAutojoin(true);
403									account.getBookmarks().add(bookmark);
404									xmppConnectionService
405											.pushBookmarks(account);
406									Conversation conversation = xmppConnectionService
407											.findOrCreateConversation(account,
408													conferenceJid, true);
409									conversation.setBookmark(bookmark);
410									if (!conversation.getMucOptions().online()) {
411										xmppConnectionService
412												.joinMuc(conversation);
413									}
414									switchToConversation(conversation);
415								}
416							} else {
417								Conversation conversation = xmppConnectionService
418										.findOrCreateConversation(account,
419												conferenceJid, true);
420								if (!conversation.getMucOptions().online()) {
421									xmppConnectionService.joinMuc(conversation);
422								}
423								switchToConversation(conversation);
424							}
425						} else {
426							jid.setError(getString(R.string.invalid_jid));
427						}
428					}
429				});
430	}
431
432	protected void switchToConversation(Contact contact) {
433		Conversation conversation = xmppConnectionService
434				.findOrCreateConversation(contact.getAccount(),
435						contact.getJid(), false);
436		switchToConversation(conversation);
437	}
438
439	private void populateAccountSpinner(Spinner spinner) {
440		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
441				android.R.layout.simple_spinner_item, mActivatedAccounts);
442		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
443		spinner.setAdapter(adapter);
444	}
445
446	@Override
447	public boolean onCreateOptionsMenu(Menu menu) {
448		this.mOptionsMenu = menu;
449		getMenuInflater().inflate(R.menu.start_conversation, menu);
450		MenuItem menuCreateContact = (MenuItem) menu
451				.findItem(R.id.action_create_contact);
452		MenuItem menuCreateConference = (MenuItem) menu
453				.findItem(R.id.action_join_conference);
454		MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
455		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
456		View mSearchView = menuSearchView.getActionView();
457		mSearchEditText = (EditText) mSearchView
458				.findViewById(R.id.search_field);
459		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
460		if (getActionBar().getSelectedNavigationIndex() == 0) {
461			menuCreateConference.setVisible(false);
462		} else {
463			menuCreateContact.setVisible(false);
464		}
465		return true;
466	}
467
468	@Override
469	public boolean onOptionsItemSelected(MenuItem item) {
470		switch (item.getItemId()) {
471		case R.id.action_create_contact:
472			showCreateContactDialog();
473			break;
474		case R.id.action_join_conference:
475			showJoinConferenceDialog();
476			break;
477		}
478		return super.onOptionsItemSelected(item);
479	}
480
481	@Override
482	public boolean onKeyUp(int keyCode, KeyEvent event) {
483		if (keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress()) {
484			mOptionsMenu.findItem(R.id.action_search).expandActionView();
485			return true;
486		}
487		return super.onKeyUp(keyCode, event);
488	}
489
490	@Override
491	void onBackendConnected() {
492		xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate);
493		if (mSearchEditText != null) {
494			filter(mSearchEditText.getText().toString());
495		} else {
496			filter(null);
497		}
498		this.mActivatedAccounts.clear();
499		for (Account account : xmppConnectionService.getAccounts()) {
500			if (account.getStatus() != Account.STATUS_DISABLED) {
501				this.mActivatedAccounts.add(account.getJid());
502			}
503		}
504		this.mKnownHosts = xmppConnectionService.getKnownHosts();
505		this.mKnownConferenceHosts = xmppConnectionService
506				.getKnownConferenceHosts();
507	}
508
509	protected void filter(String needle) {
510		if (xmppConnectionServiceBound) {
511			this.filterContacts(needle);
512			this.filterConferences(needle);
513		}
514	}
515
516	protected void filterContacts(String needle) {
517		this.contacts.clear();
518		for (Account account : xmppConnectionService.getAccounts()) {
519			if (account.getStatus() != Account.STATUS_DISABLED) {
520				for (Contact contact : account.getRoster().getContacts()) {
521					if (contact.showInRoster() && contact.match(needle)) {
522						this.contacts.add(contact);
523					}
524				}
525			}
526		}
527		Collections.sort(this.contacts);
528		mContactsAdapter.notifyDataSetChanged();
529	}
530
531	protected void filterConferences(String needle) {
532		this.conferences.clear();
533		for (Account account : xmppConnectionService.getAccounts()) {
534			if (account.getStatus() != Account.STATUS_DISABLED) {
535				for (Bookmark bookmark : account.getBookmarks()) {
536					if (bookmark.match(needle)) {
537						this.conferences.add(bookmark);
538					}
539				}
540			}
541		}
542		Collections.sort(this.conferences);
543		mConferenceAdapter.notifyDataSetChanged();
544	}
545
546	private void onTabChanged() {
547		invalidateOptionsMenu();
548	}
549
550	public static class MyListFragment extends ListFragment {
551		private AdapterView.OnItemClickListener mOnItemClickListener;
552		private int mResContextMenu;
553
554		public void setContextMenu(int res) {
555			this.mResContextMenu = res;
556		}
557
558		@Override
559		public void onListItemClick(ListView l, View v, int position, long id) {
560			if (mOnItemClickListener != null) {
561				mOnItemClickListener.onItemClick(l, v, position, id);
562			}
563		}
564
565		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
566			this.mOnItemClickListener = l;
567		}
568
569		@Override
570		public void onViewCreated(View view, Bundle savedInstanceState) {
571			super.onViewCreated(view, savedInstanceState);
572			registerForContextMenu(getListView());
573		}
574
575		@Override
576		public void onCreateContextMenu(ContextMenu menu, View v,
577				ContextMenuInfo menuInfo) {
578			super.onCreateContextMenu(menu, v, menuInfo);
579			StartConversationActivity activity = (StartConversationActivity) getActivity();
580			activity.getMenuInflater().inflate(mResContextMenu, menu);
581			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
582			if (mResContextMenu == R.menu.conference_context) {
583				activity.conference_context_id = acmi.position;
584			} else {
585				activity.contact_context_id = acmi.position;
586			}
587		}
588
589		@Override
590		public boolean onContextItemSelected(MenuItem item) {
591			StartConversationActivity activity = (StartConversationActivity) getActivity();
592			switch (item.getItemId()) {
593			case R.id.context_start_conversation:
594				activity.openConversationForContact();
595				break;
596			case R.id.context_contact_details:
597				activity.openDetailsForContact();
598				break;
599			case R.id.context_delete_contact:
600				activity.deleteContact();
601				break;
602			case R.id.context_join_conference:
603				activity.openConversationForBookmark();
604				break;
605			case R.id.context_delete_conference:
606				activity.deleteConference();
607			}
608			return true;
609		}
610	}
611}