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}