Java tutorial
/* * Tigase Mobile Messenger for Android * Copyright (C) 2011-2013 "Artur Hefczyc" <artur.hefczyc@tigase.org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. Look for COPYING file in the top folder. * If not, see http://www.gnu.org/licenses/. */ package org.tigase.mobile.bookmarks; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import org.tigase.mobile.MessengerApplication; import org.tigase.mobile.MultiJaxmpp; import org.tigase.mobile.R; import org.tigase.mobile.muc.JoinMucDialog; import tigase.jaxmpp.core.client.AsyncCallback; import tigase.jaxmpp.core.client.BareJID; import tigase.jaxmpp.core.client.JaxmppCore; import tigase.jaxmpp.core.client.PacketWriter; import tigase.jaxmpp.core.client.XMPPException.ErrorCondition; import tigase.jaxmpp.core.client.exceptions.JaxmppException; import tigase.jaxmpp.core.client.xml.DefaultElement; import tigase.jaxmpp.core.client.xml.Element; import tigase.jaxmpp.core.client.xml.XMLException; import tigase.jaxmpp.core.client.xmpp.modules.BookmarksModule; import tigase.jaxmpp.core.client.xmpp.modules.BookmarksModule.BookmarksAsyncCallback; import tigase.jaxmpp.core.client.xmpp.modules.muc.MucModule; import tigase.jaxmpp.core.client.xmpp.modules.muc.Room; import tigase.jaxmpp.core.client.xmpp.stanzas.Stanza; import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.util.Log; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AbsListView; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.ExpandableListView; import android.widget.ExpandableListView.ExpandableListContextMenuInfo; import android.widget.Toast; public class BookmarksActivity extends FragmentActivity { public static class Bookmark { protected BareJID accountJid; protected boolean autojoin; protected String id; protected BareJID jid; protected String name; protected String nick; protected String password; public Bookmark() { id = UUID.randomUUID().toString(); autojoin = false; } } private class BookmarksAsyncCallbackImpl extends BookmarksAsyncCallback { private final BareJID accountJid; private final BookmarksAdapter adapter; public BookmarksAsyncCallbackImpl(BareJID accountJid, BookmarksAdapter adapter2) { this.adapter = adapter2; this.accountJid = accountJid; } @Override public void onBookmarksReceived(final List<Element> bookmarks) { if (bookmarks == null) return; listView.post(new Runnable() { @Override public void run() { for (Element elem : bookmarks) { try { if ("conference".equals(elem.getName())) { Bookmark bookmark = new Bookmark(); bookmark.name = elem.getAttribute("name"); bookmark.accountJid = accountJid; bookmark.jid = BareJID.bareJIDInstance(elem.getAttribute("jid")); if (elem.getAttribute("autojoin") != null) { bookmark.autojoin = Boolean.parseBoolean(elem.getAttribute("autojoin")); } if (bookmark.name == null) { bookmark.name = bookmark.jid.toString(); } for (Element child : elem.getChildren()) { if ("nick".equals(child.getName())) { bookmark.nick = child.getValue(); } else if ("password".equals(child.getName())) { bookmark.password = child.getValue(); } } adapter.add(bookmark); } } catch (XMLException ex) { Log.e(TAG, "exception processing bookmarks", ex); } } for (int i = 0; i < adapter.getGroupCount(); i++) { listView.expandGroup(i); } // adapter.sort(new Comparator<Bookmark>() { // // @Override // public int compare(Bookmark lhs, Bookmark rhs) { // if (lhs == null || rhs == null) // return -1; // return lhs.name.compareTo(rhs.name); // } // // }); } }); } @Override public void onError(Stanza responseStanza, ErrorCondition error) throws JaxmppException { // TODO Auto-generated method stub } @Override public void onTimeout() throws JaxmppException { // TODO Auto-generated method stub } } private static final int DIALOG_EDIT_BOOKMARK = 1;; private static final String TAG = "BookmarksActivity"; private BookmarksAdapter adapter; private ExpandableListView listView; public void editItem(Bookmark bookmark) { Bundle data = new Bundle(); data.putBoolean("editMode", true); data.putString("id", bookmark.id); data.putString("account", bookmark.accountJid.toString()); data.putString("room", bookmark.jid.getLocalpart()); data.putString("server", bookmark.jid.getDomain()); data.putString("name", bookmark.name); data.putString("nick", bookmark.nick); data.putString("password", bookmark.password); data.putBoolean("autojoin", bookmark.autojoin); JoinMucDialog dlg = JoinMucDialog.newInstance(data); dlg.show(getSupportFragmentManager(), "dialog"); } @TargetApi(11) private void initializeContextActions() { listView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { private Bookmark getBookmarkFromFlatPosition(int pos) { long packed = listView.getExpandableListPosition(pos); int child = ExpandableListView.getPackedPositionChild(packed); int group = ExpandableListView.getPackedPositionGroup(packed); return (Bookmark) adapter.getChild(group, child); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { SparseBooleanArray selection = listView.getCheckedItemPositions(); if (item.getItemId() == R.id.edit) { for (int i = 0; i < selection.size(); i++) { if (selection.valueAt(i)) { int pos = selection.keyAt(i); Bookmark bookmark = getBookmarkFromFlatPosition(pos); editItem(bookmark); } } mode.finish(); // Action picked, so close the CAB return true; } else if (item.getItemId() == R.id.remove) { List<Bookmark> items = new ArrayList<Bookmark>(); for (int i = 0; i < selection.size(); i++) { if (selection.valueAt(i)) { int pos = selection.keyAt(i); Bookmark bookmark = getBookmarkFromFlatPosition(pos); if (bookmark != null) { items.add(bookmark); } } } removeItems(items); mode.finish(); return true; } else { return false; } } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.bookmarks_context_menu, menu); return true; } @Override public void onDestroyActionMode(ActionMode mode) { // TODO Auto-generated method stub } @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { Menu menu = mode.getMenu(); for (int i = 0; i < menu.size(); i++) { MenuItem mi = menu.getItem(i); if (mi.getItemId() == R.id.edit) { mi.setVisible(listView.getCheckedItemCount() < 2); } } } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // TODO Auto-generated method stub return true; } }); } @Override public boolean onContextItemSelected(MenuItem item) { ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) item.getMenuInfo(); if (item.getItemId() == R.id.edit) { Bookmark bookmark = adapter.getChildById(info.id); editItem(bookmark); return true; } else if (item.getItemId() == R.id.remove) { Bookmark bookmark = adapter.getChildById(info.id); List<Bookmark> bookmarks = new ArrayList<Bookmark>(); bookmarks.add(bookmark); removeItems(bookmarks); return true; } else { return super.onContextItemSelected(item); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.bookmarks_list); listView = (ExpandableListView) this.findViewById(R.id.bookmarksList); adapter = new BookmarksAdapter(this); listView.setAdapter(adapter); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { initializeContextActions(); } listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { final Bookmark bookmark = (Bookmark) adapter.getChild(groupPosition, childPosition); new Thread() { @Override public void run() { JaxmppCore jaxmpp = ((MessengerApplication) getApplicationContext()).getMultiJaxmpp() .get(bookmark.accountJid); try { Room room = jaxmpp.getModule(MucModule.class).join(bookmark.jid.getLocalpart(), bookmark.jid.getDomain().toString(), bookmark.nick, bookmark.password); Intent intent = new Intent(); intent.putExtra("roomId", room.getId()); setResult(RESULT_OK, intent); finish(); } catch (JaxmppException e) { Log.e(TAG, "exception while trying to join room"); } } }.start(); return true; } }); refresh(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.bookmarks_context_menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.add) { Bundle data = new Bundle(); data.putBoolean("editMode", true); JoinMucDialog dlg = JoinMucDialog.newInstance(data); dlg.show(getSupportFragmentManager(), "dialog"); return true; } else { return super.onOptionsItemSelected(item); } } @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.bookmarks_menu, menu); return true; } public void publishBookmarks(final BareJID accountJID, final List<Bookmark> bookmarks, final AsyncCallback callback) { new Thread() { @Override public void run() { List<Element> items = new ArrayList<Element>(); for (Bookmark bookmark : bookmarks) { try { Element item = new DefaultElement("conference"); if (bookmark.name != null && bookmark.name.length() > 0) { item.setAttribute("name", bookmark.name); } item.setAttribute("jid", bookmark.jid.toString()); if (bookmark.autojoin) { item.setAttribute("autojoin", "true"); } if (bookmark.nick != null && bookmark.nick.length() > 0) { item.addChild(new DefaultElement("nick", bookmark.nick, null)); } if (bookmark.password != null && bookmark.password.length() > 0) { item.addChild(new DefaultElement("password", bookmark.password, null)); } items.add(item); } catch (XMLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } MultiJaxmpp multi = ((MessengerApplication) getApplicationContext()).getMultiJaxmpp(); BookmarksModule module = multi.get(accountJID).getModule(BookmarksModule.class); try { module.publishBookmarks(items, callback); } catch (JaxmppException ex) { ex.printStackTrace(); } } }.start(); } private void refresh() { listView.post(new Runnable() { @Override public void run() { adapter.clear(); } }); MultiJaxmpp multi = ((MessengerApplication) getApplicationContext()).getMultiJaxmpp(); for (final JaxmppCore jaxmpp : multi.get()) { if (!jaxmpp.isConnected()) continue; new Thread() { @Override public void run() { BookmarksModule module = jaxmpp.getModule(BookmarksModule.class); if (module == null) { module = new BookmarksModule(jaxmpp.getSessionObject(), new PacketWriter() { @Override public void write(Element stanza) throws JaxmppException { jaxmpp.send((Stanza) stanza); } @Override public void write(Element stanza, AsyncCallback asyncCallback) throws JaxmppException { jaxmpp.send((Stanza) stanza, asyncCallback); } @Override public void write(Element stanza, Long timeout, AsyncCallback asyncCallback) throws JaxmppException { jaxmpp.send((Stanza) stanza, timeout, asyncCallback); } }); jaxmpp.getModulesManager().register(module); } try { BookmarksAsyncCallback callback = new BookmarksAsyncCallbackImpl( jaxmpp.getSessionObject().getUserBareJid(), adapter); module.retrieveBookmarks(callback); } catch (JaxmppException e) { Log.e(TAG, "exception retrieving bookmarks", e); } } }.start(); } this.registerForContextMenu(listView); } public void removeItems(List<Bookmark> bookmarks) { Map<BareJID, List<Bookmark>> map = new HashMap<BareJID, List<Bookmark>>(); for (int i = 0; i < adapter.getGroupCount(); i++) { BareJID account = (BareJID) adapter.getGroup(i); map.put(account, adapter.getChildrenForGroup(account)); } Set<BareJID> changedAccounts = new HashSet<BareJID>(); for (Bookmark bookmark : bookmarks) { List<Bookmark> list = map.get(bookmark.accountJid); list.remove(bookmark); changedAccounts.add(bookmark.accountJid); } // need to send changed bookmarks for (BareJID accountJID : changedAccounts) { publishBookmarks(accountJID, map.get(accountJID), new AsyncCallback() { @Override public void onError(Stanza responseStanza, ErrorCondition error) throws JaxmppException { refresh(); Toast.makeText(BookmarksActivity.this, "Could not remove bookmark", Toast.LENGTH_SHORT).show(); } @Override public void onSuccess(Stanza responseStanza) throws JaxmppException { refresh(); Toast.makeText(BookmarksActivity.this, "Bookmarks removed", Toast.LENGTH_SHORT).show(); } @Override public void onTimeout() throws JaxmppException { refresh(); Toast.makeText(BookmarksActivity.this, "Request timed out", Toast.LENGTH_SHORT).show(); } }); } } public void saveItem(Bundle data) { String id = data.getString("id"); BareJID account = BareJID.bareJIDInstance(data.getString("account")); List<Bookmark> bookmarks = adapter.getChildrenForGroup(account); if (bookmarks == null) { bookmarks = new ArrayList<Bookmark>(1); } Bookmark bookmark = null; for (Bookmark item : bookmarks) { if (id != null && id.equals(item.id)) { bookmark = item; } } if (bookmark == null) { bookmark = new Bookmark(); bookmark.accountJid = account; bookmarks.add(bookmark); } bookmark.jid = BareJID.bareJIDInstance(data.getString("room"), data.getString("server")); bookmark.name = data.getString("name"); bookmark.nick = data.getString("nick"); bookmark.password = data.getString("password"); bookmark.autojoin = data.getBoolean("autojoin"); publishBookmarks(account, bookmarks, new AsyncCallback() { @Override public void onError(Stanza responseStanza, ErrorCondition error) throws JaxmppException { refresh(); Toast.makeText(BookmarksActivity.this, "Could not remove bookmark", Toast.LENGTH_SHORT).show(); } @Override public void onSuccess(Stanza responseStanza) throws JaxmppException { refresh(); Toast.makeText(BookmarksActivity.this, "Bookmark saved", Toast.LENGTH_SHORT).show(); } @Override public void onTimeout() throws JaxmppException { refresh(); Toast.makeText(BookmarksActivity.this, "Request timed out", Toast.LENGTH_SHORT).show(); } }); } }