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.Menu;
 25import android.view.MenuItem;
 26import android.view.View;
 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.ListView;
 36import android.widget.Spinner;
 37import eu.siacs.conversations.R;
 38import eu.siacs.conversations.entities.Account;
 39import eu.siacs.conversations.entities.Bookmark;
 40import eu.siacs.conversations.entities.Contact;
 41import eu.siacs.conversations.entities.Conversation;
 42import eu.siacs.conversations.entities.ListItem;
 43import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
 44import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 45import eu.siacs.conversations.ui.adapter.ListItemAdapter;
 46import eu.siacs.conversations.utils.Validator;
 47
 48public class StartConversationActivity 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	private OnRosterUpdate onRosterUpdate = new OnRosterUpdate() {
144		
145		@Override
146		public void onRosterUpdate() {
147			runOnUiThread(new Runnable() {
148				
149				@Override
150				public void run() {
151					filter(mSearchEditText.getText().toString());
152				}
153			});
154		}
155	};
156
157	@Override
158	public void onCreate(Bundle savedInstanceState) {
159		super.onCreate(savedInstanceState);
160		setContentView(R.layout.activity_start_conversation);
161		mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
162		ActionBar actionBar = getActionBar();
163		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
164
165		mContactsTab = actionBar.newTab().setText(R.string.contacts)
166				.setTabListener(mTabListener);
167		mConferencesTab = actionBar.newTab().setText(R.string.conferences)
168				.setTabListener(mTabListener);
169		actionBar.addTab(mContactsTab);
170		actionBar.addTab(mConferencesTab);
171
172		mViewPager.setOnPageChangeListener(mOnPageChangeListener);
173		mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
174
175			@Override
176			public int getCount() {
177				return 2;
178			}
179
180			@Override
181			public Fragment getItem(int position) {
182				if (position == 0) {
183					return mContactsListFragment;
184				} else {
185					return mConferenceListFragment;
186				}
187			}
188		});
189
190		mConferenceAdapter = new ListItemAdapter(getApplicationContext(),conferences);
191		mConferenceListFragment.setListAdapter(mConferenceAdapter);
192		mConferenceListFragment.setContextMenu(R.menu.conference_context);
193		mConferenceListFragment
194				.setOnListItemClickListener(new OnItemClickListener() {
195
196					@Override
197					public void onItemClick(AdapterView<?> arg0, View arg1,
198							int position, long arg3) {
199						openConversationForBookmark(position);
200					}
201				});
202
203		mContactsAdapter = new ListItemAdapter(getApplicationContext(),contacts);
204		mContactsListFragment.setListAdapter(mContactsAdapter);
205		mContactsListFragment.setContextMenu(R.menu.contact_context);
206		mContactsListFragment
207				.setOnListItemClickListener(new OnItemClickListener() {
208
209					@Override
210					public void onItemClick(AdapterView<?> arg0, View arg1,
211							int position, long arg3) {
212						openConversationForContact(position);
213					}
214				});
215
216	}
217	
218	@Override
219	public void onStop() {
220		super.onStop();
221		xmppConnectionService.removeOnRosterUpdateListener();
222	}
223
224	protected void openConversationForContact(int position) {
225		Contact contact = (Contact) contacts.get(position);
226		Conversation conversation = xmppConnectionService
227				.findOrCreateConversation(contact.getAccount(),
228						contact.getJid(), false);
229		switchToConversation(conversation);
230	}
231
232	protected void openConversationForContact() {
233		int position = contact_context_id;
234		openConversationForContact(position);
235	}
236
237	protected void openConversationForBookmark() {
238		openConversationForBookmark(conference_context_id);
239	}
240
241	protected void openConversationForBookmark(int position) {
242		Bookmark bookmark = (Bookmark) conferences.get(position);
243		Conversation conversation = xmppConnectionService
244				.findOrCreateConversation(bookmark.getAccount(),
245						bookmark.getJid(), true);
246		conversation.setBookmark(bookmark);
247		if (!conversation.getMucOptions().online()) {
248			xmppConnectionService.joinMuc(conversation);
249		}
250		if (!bookmark.autojoin()) {
251			bookmark.setAutojoin(true);
252			xmppConnectionService.pushBookmarks(bookmark.getAccount());
253		}
254		switchToConversation(conversation);
255	}
256
257	protected void openDetailsForContact() {
258		int position = contact_context_id;
259		Contact contact = (Contact) contacts.get(position);
260		switchToContactDetails(contact);
261	}
262
263	protected void deleteContact() {
264		int position = contact_context_id;
265		final Contact contact = (Contact) contacts.get(position);
266		AlertDialog.Builder builder = new AlertDialog.Builder(this);
267		builder.setNegativeButton(R.string.cancel, null);
268		builder.setTitle(R.string.action_delete_contact);
269		builder.setMessage(
270				getString(R.string.remove_contact_text,
271						contact.getJid()));
272		builder.setPositiveButton(R.string.delete,new OnClickListener() {
273			
274			@Override
275			public void onClick(DialogInterface dialog, int which) {
276				xmppConnectionService.deleteContactOnServer(contact);
277				filter(mSearchEditText.getText().toString());
278			}
279		});
280		builder.create().show();
281		
282	}
283
284	protected void deleteConference() {
285		int position = conference_context_id;
286		final Bookmark bookmark = (Bookmark) conferences.get(position);
287		
288		AlertDialog.Builder builder = new AlertDialog.Builder(this);
289		builder.setNegativeButton(R.string.cancel, null);
290		builder.setTitle(R.string.delete_bookmark);
291		builder.setMessage(
292				getString(R.string.remove_bookmark_text,
293						bookmark.getJid()));
294		builder.setPositiveButton(R.string.delete,new OnClickListener() {
295			
296			@Override
297			public void onClick(DialogInterface dialog, int which) {
298				bookmark.unregisterConversation();
299				Account account = bookmark.getAccount();
300				account.getBookmarks().remove(bookmark);
301				xmppConnectionService.pushBookmarks(account);
302				filter(mSearchEditText.getText().toString());
303			}
304		});
305		builder.create().show();
306		
307	}
308
309	protected void showCreateContactDialog() {
310		AlertDialog.Builder builder = new AlertDialog.Builder(this);
311		builder.setTitle(R.string.create_contact);
312		View dialogView = getLayoutInflater().inflate(
313				R.layout.create_contact_dialog, null);
314		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
315		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
316				.findViewById(R.id.jid);
317		jid.setAdapter(new KnownHostsAdapter(this,
318				android.R.layout.simple_list_item_1, mKnownHosts));
319		populateAccountSpinner(spinner);
320		builder.setView(dialogView);
321		builder.setNegativeButton(R.string.cancel, null);
322		builder.setPositiveButton(R.string.create, null);
323		final AlertDialog dialog = builder.create();
324		dialog.show();
325		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
326				new View.OnClickListener() {
327
328					@Override
329					public void onClick(View v) {
330						if (Validator.isValidJid(jid.getText().toString())) {
331							String accountJid = (String) spinner
332									.getSelectedItem();
333							String contactJid = jid.getText().toString();
334							Account account = xmppConnectionService
335									.findAccountByJid(accountJid);
336							Contact contact = account.getRoster().getContact(
337									contactJid);
338							if (contact.showInRoster()) {
339								jid.setError(getString(R.string.contact_already_exists));
340							} else {
341								xmppConnectionService.createContact(contact);
342								switchToConversation(contact);
343								dialog.dismiss();
344							}
345						} else {
346							jid.setError(getString(R.string.invalid_jid));
347						}
348					}
349				});
350
351	}
352
353	protected void showJoinConferenceDialog() {
354		AlertDialog.Builder builder = new AlertDialog.Builder(this);
355		builder.setTitle(R.string.join_conference);
356		View dialogView = getLayoutInflater().inflate(
357				R.layout.join_conference_dialog, null);
358		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
359		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
360				.findViewById(R.id.jid);
361		jid.setAdapter(new KnownHostsAdapter(this,
362				android.R.layout.simple_list_item_1, mKnownConferenceHosts));
363		populateAccountSpinner(spinner);
364		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
365				.findViewById(R.id.bookmark);
366		builder.setView(dialogView);
367		builder.setNegativeButton(R.string.cancel, null);
368		builder.setPositiveButton(R.string.join, null);
369		final AlertDialog dialog = builder.create();
370		dialog.show();
371		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
372				new View.OnClickListener() {
373
374					@Override
375					public void onClick(View v) {
376						if (Validator.isValidJid(jid.getText().toString())) {
377							String accountJid = (String) spinner
378									.getSelectedItem();
379							String conferenceJid = jid.getText().toString();
380							Account account = xmppConnectionService
381									.findAccountByJid(accountJid);
382							if (bookmarkCheckBox.isChecked()) {
383								if (account.hasBookmarkFor(conferenceJid)) {
384									jid.setError(getString(R.string.bookmark_already_exists));
385								} else {
386									Bookmark bookmark = new Bookmark(account,
387											conferenceJid);
388									bookmark.setAutojoin(true);
389									account.getBookmarks().add(bookmark);
390									xmppConnectionService
391											.pushBookmarks(account);
392									Conversation conversation = xmppConnectionService
393											.findOrCreateConversation(account,
394													conferenceJid, true);
395									conversation.setBookmark(bookmark);
396									if (!conversation.getMucOptions().online()) {
397										xmppConnectionService.joinMuc(conversation);
398									}
399									switchToConversation(conversation);
400								}
401							} else {
402								Conversation conversation = xmppConnectionService
403										.findOrCreateConversation(account,
404												conferenceJid, true);
405								if (!conversation.getMucOptions().online()) {
406									xmppConnectionService.joinMuc(conversation);
407								}
408								switchToConversation(conversation);
409							}
410						} else {
411							jid.setError(getString(R.string.invalid_jid));
412						}
413					}
414				});
415	}
416
417	protected void switchToConversation(Contact contact) {
418		Conversation conversation = xmppConnectionService
419				.findOrCreateConversation(contact.getAccount(),
420						contact.getJid(), false);
421		switchToConversation(conversation);
422	}
423
424	private void populateAccountSpinner(Spinner spinner) {
425		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
426				android.R.layout.simple_spinner_item, mActivatedAccounts);
427		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
428		spinner.setAdapter(adapter);
429	}
430
431	@Override
432	public boolean onCreateOptionsMenu(Menu menu) {
433		getMenuInflater().inflate(R.menu.start_conversation, menu);
434		MenuItem menuCreateContact = (MenuItem) menu
435				.findItem(R.id.action_create_contact);
436		MenuItem menuCreateConference = (MenuItem) menu
437				.findItem(R.id.action_join_conference);
438		MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
439		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
440		View mSearchView = menuSearchView.getActionView();
441		mSearchEditText = (EditText) mSearchView
442				.findViewById(R.id.search_field);
443		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
444		if (getActionBar().getSelectedNavigationIndex() == 0) {
445			menuCreateConference.setVisible(false);
446		} else {
447			menuCreateContact.setVisible(false);
448		}
449		return true;
450	}
451
452	@Override
453	public boolean onOptionsItemSelected(MenuItem item) {
454		switch (item.getItemId()) {
455		case R.id.action_create_contact:
456			showCreateContactDialog();
457			break;
458		case R.id.action_join_conference:
459			showJoinConferenceDialog();
460			break;
461		}
462		return super.onOptionsItemSelected(item);
463	}
464
465	@Override
466	void onBackendConnected() {
467		xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate );
468		if (mSearchEditText != null) {
469			filter(mSearchEditText.getText().toString());
470		} else {
471			filter(null);
472		}
473		this.mActivatedAccounts.clear();
474		for (Account account : xmppConnectionService.getAccounts()) {
475			if (account.getStatus() != Account.STATUS_DISABLED) {
476				this.mActivatedAccounts.add(account.getJid());
477			}
478		}
479		this.mKnownHosts = xmppConnectionService.getKnownHosts();
480		this.mKnownConferenceHosts = xmppConnectionService
481				.getKnownConferenceHosts();
482	}
483
484	protected void filter(String needle) {
485		this.filterContacts(needle);
486		this.filterConferences(needle);
487	}
488
489	protected void filterContacts(String needle) {
490		this.contacts.clear();
491		for (Account account : xmppConnectionService.getAccounts()) {
492			if (account.getStatus() != Account.STATUS_DISABLED) {
493				for (Contact contact : account.getRoster().getContacts()) {
494					if (contact.showInRoster() && contact.match(needle)) {
495						this.contacts.add(contact);
496					}
497				}
498			}
499		}
500		Collections.sort(this.contacts);
501		mContactsAdapter.notifyDataSetChanged();
502	}
503
504	protected void filterConferences(String needle) {
505		this.conferences.clear();
506		for (Account account : xmppConnectionService.getAccounts()) {
507			if (account.getStatus() != Account.STATUS_DISABLED) {
508				for (Bookmark bookmark : account.getBookmarks()) {
509					if (bookmark.match(needle)) {
510						this.conferences.add(bookmark);
511					}
512				}
513			}
514		}
515		Collections.sort(this.conferences);
516		mConferenceAdapter.notifyDataSetChanged();
517	}
518
519	private void onTabChanged() {
520		invalidateOptionsMenu();
521	}
522
523	public static class MyListFragment extends ListFragment {
524		private AdapterView.OnItemClickListener mOnItemClickListener;
525		private int mResContextMenu;
526
527		public void setContextMenu(int res) {
528			this.mResContextMenu = res;
529		}
530
531		@Override
532		public void onListItemClick(ListView l, View v, int position, long id) {
533			if (mOnItemClickListener != null) {
534				mOnItemClickListener.onItemClick(l, v, position, id);
535			}
536		}
537
538		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
539			this.mOnItemClickListener = l;
540		}
541
542		@Override
543		public void onViewCreated(View view, Bundle savedInstanceState) {
544			super.onViewCreated(view, savedInstanceState);
545			registerForContextMenu(getListView());
546		}
547
548		@Override
549		public void onCreateContextMenu(ContextMenu menu, View v,
550				ContextMenuInfo menuInfo) {
551			super.onCreateContextMenu(menu, v, menuInfo);
552			StartConversationActivity activity = (StartConversationActivity) getActivity();
553			activity.getMenuInflater().inflate(mResContextMenu, menu);
554			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
555			if (mResContextMenu == R.menu.conference_context) {
556				activity.conference_context_id = acmi.position;
557			} else {
558				activity.contact_context_id = acmi.position;
559			}
560		}
561
562		@Override
563		public boolean onContextItemSelected(MenuItem item) {
564			StartConversationActivity activity = (StartConversationActivity) getActivity();
565			switch (item.getItemId()) {
566			case R.id.context_start_conversation:
567				activity.openConversationForContact();
568				break;
569			case R.id.context_contact_details:
570				activity.openDetailsForContact();
571				break;
572			case R.id.context_delete_contact:
573				activity.deleteContact();
574				break;
575			case R.id.context_join_conference:
576				activity.openConversationForBookmark();
577				break;
578			case R.id.context_delete_conference:
579				activity.deleteConference();
580			}
581			return true;
582		}
583	}
584}