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