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(),conferences);
195		mConferenceListFragment.setListAdapter(mConferenceAdapter);
196		mConferenceListFragment.setContextMenu(R.menu.conference_context);
197		mConferenceListFragment
198				.setOnListItemClickListener(new OnItemClickListener() {
199
200					@Override
201					public void onItemClick(AdapterView<?> arg0, View arg1,
202							int position, long arg3) {
203						openConversationForBookmark(position);
204					}
205				});
206
207		mContactsAdapter = new ListItemAdapter(getApplicationContext(),contacts);
208		mContactsListFragment.setListAdapter(mContactsAdapter);
209		mContactsListFragment.setContextMenu(R.menu.contact_context);
210		mContactsListFragment
211				.setOnListItemClickListener(new OnItemClickListener() {
212
213					@Override
214					public void onItemClick(AdapterView<?> arg0, View arg1,
215							int position, long arg3) {
216						openConversationForContact(position);
217					}
218				});
219
220	}
221	
222	@Override
223	public void onStop() {
224		super.onStop();
225		xmppConnectionService.removeOnRosterUpdateListener();
226	}
227
228	protected void openConversationForContact(int position) {
229		Contact contact = (Contact) contacts.get(position);
230		Conversation conversation = xmppConnectionService
231				.findOrCreateConversation(contact.getAccount(),
232						contact.getJid(), false);
233		switchToConversation(conversation);
234	}
235
236	protected void openConversationForContact() {
237		int position = contact_context_id;
238		openConversationForContact(position);
239	}
240
241	protected void openConversationForBookmark() {
242		openConversationForBookmark(conference_context_id);
243	}
244
245	protected void openConversationForBookmark(int position) {
246		Bookmark bookmark = (Bookmark) conferences.get(position);
247		Conversation conversation = xmppConnectionService
248				.findOrCreateConversation(bookmark.getAccount(),
249						bookmark.getJid(), true);
250		conversation.setBookmark(bookmark);
251		if (!conversation.getMucOptions().online()) {
252			xmppConnectionService.joinMuc(conversation);
253		}
254		if (!bookmark.autojoin()) {
255			bookmark.setAutojoin(true);
256			xmppConnectionService.pushBookmarks(bookmark.getAccount());
257		}
258		switchToConversation(conversation);
259	}
260
261	protected void openDetailsForContact() {
262		int position = contact_context_id;
263		Contact contact = (Contact) contacts.get(position);
264		switchToContactDetails(contact);
265	}
266
267	protected void deleteContact() {
268		int position = contact_context_id;
269		final Contact contact = (Contact) contacts.get(position);
270		AlertDialog.Builder builder = new AlertDialog.Builder(this);
271		builder.setNegativeButton(R.string.cancel, null);
272		builder.setTitle(R.string.action_delete_contact);
273		builder.setMessage(
274				getString(R.string.remove_contact_text,
275						contact.getJid()));
276		builder.setPositiveButton(R.string.delete,new OnClickListener() {
277			
278			@Override
279			public void onClick(DialogInterface dialog, int which) {
280				xmppConnectionService.deleteContactOnServer(contact);
281				filter(mSearchEditText.getText().toString());
282			}
283		});
284		builder.create().show();
285		
286	}
287
288	protected void deleteConference() {
289		int position = conference_context_id;
290		final Bookmark bookmark = (Bookmark) conferences.get(position);
291		
292		AlertDialog.Builder builder = new AlertDialog.Builder(this);
293		builder.setNegativeButton(R.string.cancel, null);
294		builder.setTitle(R.string.delete_bookmark);
295		builder.setMessage(
296				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 (Validator.isValidJid(jid.getText().toString())) {
335							String accountJid = (String) spinner
336									.getSelectedItem();
337							String contactJid = jid.getText().toString();
338							Account account = xmppConnectionService
339									.findAccountByJid(accountJid);
340							Contact contact = account.getRoster().getContact(
341									contactJid);
342							if (contact.showInRoster()) {
343								jid.setError(getString(R.string.contact_already_exists));
344							} else {
345								xmppConnectionService.createContact(contact);
346								switchToConversation(contact);
347								dialog.dismiss();
348							}
349						} else {
350							jid.setError(getString(R.string.invalid_jid));
351						}
352					}
353				});
354
355	}
356
357	protected void showJoinConferenceDialog() {
358		AlertDialog.Builder builder = new AlertDialog.Builder(this);
359		builder.setTitle(R.string.join_conference);
360		View dialogView = getLayoutInflater().inflate(
361				R.layout.join_conference_dialog, null);
362		final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
363		final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
364				.findViewById(R.id.jid);
365		jid.setAdapter(new KnownHostsAdapter(this,
366				android.R.layout.simple_list_item_1, mKnownConferenceHosts));
367		populateAccountSpinner(spinner);
368		final CheckBox bookmarkCheckBox = (CheckBox) dialogView
369				.findViewById(R.id.bookmark);
370		builder.setView(dialogView);
371		builder.setNegativeButton(R.string.cancel, null);
372		builder.setPositiveButton(R.string.join, null);
373		final AlertDialog dialog = builder.create();
374		dialog.show();
375		dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
376				new View.OnClickListener() {
377
378					@Override
379					public void onClick(View v) {
380						if (Validator.isValidJid(jid.getText().toString())) {
381							String accountJid = (String) spinner
382									.getSelectedItem();
383							String conferenceJid = jid.getText().toString();
384							Account account = xmppConnectionService
385									.findAccountByJid(accountJid);
386							if (bookmarkCheckBox.isChecked()) {
387								if (account.hasBookmarkFor(conferenceJid)) {
388									jid.setError(getString(R.string.bookmark_already_exists));
389								} else {
390									Bookmark bookmark = new Bookmark(account,
391											conferenceJid);
392									bookmark.setAutojoin(true);
393									account.getBookmarks().add(bookmark);
394									xmppConnectionService
395											.pushBookmarks(account);
396									Conversation conversation = xmppConnectionService
397											.findOrCreateConversation(account,
398													conferenceJid, true);
399									conversation.setBookmark(bookmark);
400									if (!conversation.getMucOptions().online()) {
401										xmppConnectionService.joinMuc(conversation);
402									}
403									switchToConversation(conversation);
404								}
405							} else {
406								Conversation conversation = xmppConnectionService
407										.findOrCreateConversation(account,
408												conferenceJid, true);
409								if (!conversation.getMucOptions().online()) {
410									xmppConnectionService.joinMuc(conversation);
411								}
412								switchToConversation(conversation);
413							}
414						} else {
415							jid.setError(getString(R.string.invalid_jid));
416						}
417					}
418				});
419	}
420
421	protected void switchToConversation(Contact contact) {
422		Conversation conversation = xmppConnectionService
423				.findOrCreateConversation(contact.getAccount(),
424						contact.getJid(), false);
425		switchToConversation(conversation);
426	}
427
428	private void populateAccountSpinner(Spinner spinner) {
429		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
430				android.R.layout.simple_spinner_item, mActivatedAccounts);
431		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
432		spinner.setAdapter(adapter);
433	}
434
435	@Override
436	public boolean onCreateOptionsMenu(Menu menu) {
437		this.mOptionsMenu = menu;
438		getMenuInflater().inflate(R.menu.start_conversation, menu);
439		MenuItem menuCreateContact = (MenuItem) menu
440				.findItem(R.id.action_create_contact);
441		MenuItem menuCreateConference = (MenuItem) menu
442				.findItem(R.id.action_join_conference);
443		MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
444		menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
445		View mSearchView = menuSearchView.getActionView();
446		mSearchEditText = (EditText) mSearchView
447				.findViewById(R.id.search_field);
448		mSearchEditText.addTextChangedListener(mSearchTextWatcher);
449		if (getActionBar().getSelectedNavigationIndex() == 0) {
450			menuCreateConference.setVisible(false);
451		} else {
452			menuCreateContact.setVisible(false);
453		}
454		return true;
455	}
456
457	@Override
458	public boolean onOptionsItemSelected(MenuItem item) {
459		switch (item.getItemId()) {
460		case R.id.action_create_contact:
461			showCreateContactDialog();
462			break;
463		case R.id.action_join_conference:
464			showJoinConferenceDialog();
465			break;
466		}
467		return super.onOptionsItemSelected(item);
468	}
469	
470	@Override
471	public boolean onKeyUp(int keyCode, KeyEvent event)
472	{		
473		if(keyCode == KeyEvent.KEYCODE_SEARCH && !event.isLongPress())
474		{
475			mOptionsMenu.findItem(R.id.action_search).expandActionView();
476			return true;
477		}
478		return super.onKeyUp(keyCode, event);
479	}
480
481	@Override
482	void onBackendConnected() {
483		xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate );
484		if (mSearchEditText != null) {
485			filter(mSearchEditText.getText().toString());
486		} else {
487			filter(null);
488		}
489		this.mActivatedAccounts.clear();
490		for (Account account : xmppConnectionService.getAccounts()) {
491			if (account.getStatus() != Account.STATUS_DISABLED) {
492				this.mActivatedAccounts.add(account.getJid());
493			}
494		}
495		this.mKnownHosts = xmppConnectionService.getKnownHosts();
496		this.mKnownConferenceHosts = xmppConnectionService
497				.getKnownConferenceHosts();
498	}
499
500	protected void filter(String needle) {
501		if (xmppConnectionServiceBound) {
502			this.filterContacts(needle);
503			this.filterConferences(needle);
504		}
505	}
506
507	protected void filterContacts(String needle) {
508		this.contacts.clear();
509		for (Account account : xmppConnectionService.getAccounts()) {
510			if (account.getStatus() != Account.STATUS_DISABLED) {
511				for (Contact contact : account.getRoster().getContacts()) {
512					if (contact.showInRoster() && contact.match(needle)) {
513						this.contacts.add(contact);
514					}
515				}
516			}
517		}
518		Collections.sort(this.contacts);
519		mContactsAdapter.notifyDataSetChanged();
520	}
521
522	protected void filterConferences(String needle) {
523		this.conferences.clear();
524		for (Account account : xmppConnectionService.getAccounts()) {
525			if (account.getStatus() != Account.STATUS_DISABLED) {
526				for (Bookmark bookmark : account.getBookmarks()) {
527					if (bookmark.match(needle)) {
528						this.conferences.add(bookmark);
529					}
530				}
531			}
532		}
533		Collections.sort(this.conferences);
534		mConferenceAdapter.notifyDataSetChanged();
535	}
536
537	private void onTabChanged() {
538		invalidateOptionsMenu();
539	}
540
541	public static class MyListFragment extends ListFragment {
542		private AdapterView.OnItemClickListener mOnItemClickListener;
543		private int mResContextMenu;
544
545		public void setContextMenu(int res) {
546			this.mResContextMenu = res;
547		}
548
549		@Override
550		public void onListItemClick(ListView l, View v, int position, long id) {
551			if (mOnItemClickListener != null) {
552				mOnItemClickListener.onItemClick(l, v, position, id);
553			}
554		}
555
556		public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
557			this.mOnItemClickListener = l;
558		}
559
560		@Override
561		public void onViewCreated(View view, Bundle savedInstanceState) {
562			super.onViewCreated(view, savedInstanceState);
563			registerForContextMenu(getListView());
564		}
565
566		@Override
567		public void onCreateContextMenu(ContextMenu menu, View v,
568				ContextMenuInfo menuInfo) {
569			super.onCreateContextMenu(menu, v, menuInfo);
570			StartConversationActivity activity = (StartConversationActivity) getActivity();
571			activity.getMenuInflater().inflate(mResContextMenu, menu);
572			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
573			if (mResContextMenu == R.menu.conference_context) {
574				activity.conference_context_id = acmi.position;
575			} else {
576				activity.contact_context_id = acmi.position;
577			}
578		}
579
580		@Override
581		public boolean onContextItemSelected(MenuItem item) {
582			StartConversationActivity activity = (StartConversationActivity) getActivity();
583			switch (item.getItemId()) {
584			case R.id.context_start_conversation:
585				activity.openConversationForContact();
586				break;
587			case R.id.context_contact_details:
588				activity.openDetailsForContact();
589				break;
590			case R.id.context_delete_contact:
591				activity.deleteContact();
592				break;
593			case R.id.context_join_conference:
594				activity.openConversationForBookmark();
595				break;
596			case R.id.context_delete_conference:
597				activity.deleteConference();
598			}
599			return true;
600		}
601	}
602}