Java tutorial
/* * Copyright (c) 2014 ELAN e.V. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package de.elanev.studip.android.app.widget; import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.content.OperationApplicationException; import android.database.Cursor; import android.os.Bundle; import android.os.RemoteException; import android.support.v4.app.DialogFragment; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.Request.Method; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; import com.android.volley.VolleyError; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import de.elanev.studip.android.app.R; import de.elanev.studip.android.app.StudIPApplication; import de.elanev.studip.android.app.backend.datamodel.ContactGroups; import de.elanev.studip.android.app.backend.datamodel.Contacts; import de.elanev.studip.android.app.backend.datamodel.Server; import de.elanev.studip.android.app.backend.db.AbstractContract; import de.elanev.studip.android.app.backend.db.ContactsContract; import de.elanev.studip.android.app.backend.db.UsersContract; import de.elanev.studip.android.app.backend.net.SyncHelper; import de.elanev.studip.android.app.backend.net.oauth.OAuthConnector; import de.elanev.studip.android.app.backend.net.sync.ContactGroupHandler; import de.elanev.studip.android.app.backend.net.sync.ContactsHandler; import de.elanev.studip.android.app.backend.net.util.JacksonRequest; import de.elanev.studip.android.app.backend.net.util.StringRequest; import de.elanev.studip.android.app.util.Prefs; import de.elanev.studip.android.app.util.StuffUtil; import oauth.signpost.exception.OAuthCommunicationException; import oauth.signpost.exception.OAuthExpectationFailedException; import oauth.signpost.exception.OAuthMessageSignerException; import oauth.signpost.exception.OAuthNotAuthorizedException; /** * @author joern */ public abstract class UserListFragment extends ProgressListFragment implements LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { private static final String TAG = UserListFragment.class.getCanonicalName(); private static ContentResolver mResolver; private static String mApiUrl; protected UserListFragment() { } /* * (non-Javadoc) * * @see android.support.v4.app.Fragment#onCreate(android.os.Bundle) */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mResolver = mContext.getContentResolver(); mApiUrl = Prefs.getInstance(getActivity()).getServer().getApiUrl(); } /* * (non-Javadoc) * * @see android.support.v4.app.Fragment#onActivityCreated(android.os.Bundle) */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setEmptyMessage(R.string.no_users); setHasOptionsMenu(true); registerForContextMenu(mListView); } /** * Creating floating context menu */ @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getActivity().getMenuInflater(); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; Cursor listItemCursor = (Cursor) mListView.getAdapter().getItem(info.position); final String[] projection = new String[] { ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_NAME, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_ID, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_ID }; final String contactId = listItemCursor .getString(listItemCursor.getColumnIndex(UsersContract.Columns.USER_ID)); CursorLoader loader = new CursorLoader(getActivity(), ContactsContract.CONTENT_URI_CONTACTS.buildUpon().appendPath(contactId).build(), projection, null, null, ContactsContract.Columns.ContactGroups.GROUP_NAME + " ASC"); final Cursor c = loader.loadInBackground(); if (c.getCount() <= 0) { inflater.inflate(R.menu.user_add_context_menu, menu); } else { inflater.inflate(R.menu.user_context_menu, menu); c.moveToFirst(); while (!c.isAfterLast()) { String currGroupName = c .getString(c.getColumnIndex(ContactsContract.Columns.ContactGroups.GROUP_NAME)); if (TextUtils.equals(currGroupName, getString(R.string.studip_app_contacts_favorites))) { menu.removeItem(R.id.add_to_favorites); menu.findItem(R.id.remove_from_favorites).setVisible(true); } c.moveToNext(); } } c.close(); } @Override public boolean onContextItemSelected(MenuItem item) { // Workaround: Check if tab is visible, else pass call to the next tab if (getUserVisibleHint()) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int itemId = item.getItemId(); // Get userInfo from cursor Cursor c = (Cursor) mListView.getAdapter().getItem(info.position); String userId = c.getString(c.getColumnIndex(UsersContract.Columns.USER_ID)); int userIntId = c.getInt(c.getColumnIndex(UsersContract.Columns._ID)); switch (itemId) { // add to or remove user from favorites case R.id.add_to_favorites: { String favGroupId = null; Cursor favCursor1 = mContext.getContentResolver().query(ContactsContract.CONTENT_URI_CONTACT_GROUPS, new String[] { ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_ID }, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_NAME + "= ?", new String[] { mContext.getString(R.string.studip_app_contacts_favorites) }, ContactsContract.DEFAULT_SORT_ORDER_CONTACT_GROUPS); if (favCursor1.getCount() > 0) { favCursor1.moveToFirst(); favGroupId = favCursor1 .getString(favCursor1.getColumnIndex(ContactsContract.Columns.ContactGroups.GROUP_ID)); } favCursor1.close(); addUserToGroup(userId, favGroupId, mContext); return true; } case R.id.remove_from_favorites: { String favGroupId = null; int favGroupIntId = 0; Cursor favCursor2 = mContext.getContentResolver().query(ContactsContract.CONTENT_URI_CONTACT_GROUPS, new String[] { ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_ID, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_ID }, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_NAME + "= ?", new String[] { mContext.getString(R.string.studip_app_contacts_favorites) }, ContactsContract.DEFAULT_SORT_ORDER_CONTACT_GROUPS); if (favCursor2.getCount() > 0) { favCursor2.moveToFirst(); favGroupId = favCursor2 .getString(favCursor2.getColumnIndex(ContactsContract.Columns.ContactGroups.GROUP_ID)); favGroupIntId = favCursor2 .getInt(favCursor2.getColumnIndex(ContactsContract.Columns.ContactGroups._ID)); } favCursor2.close(); deleteUserFromGroup(userId, favGroupId, favGroupIntId, userIntId, mContext); return true; } // add to or remove from contacts case R.id.add_to_contacts: { addUserToContacts(userId, mContext); return true; } case R.id.remove_from_contacts: { deleteUserFromContacts(userId, mContext); return true; } case R.id.manage_groups: { Bundle args = new Bundle(); args.putString(ContactsContract.Columns.Contacts.USER_ID, userId); args.putInt(ContactsContract.Columns.Contacts._ID, userIntId); ContactGroupsDialogFragment frag = (ContactGroupsDialogFragment) ContactGroupsDialogFragment .instantiate(mContext, ContactGroupsDialogFragment.class.getName()); frag.setArguments(args); getFragmentManager().beginTransaction().add(frag, ContactGroupsDialogFragment.class.getName()) .commit(); return true; } default: return super.onContextItemSelected(item); } } else { return false; } } private static void addUserToGroup(final String userId, final String groupId, final Context context) { String contactsUrl = String.format(context.getString(R.string.restip_contacts_groups_groupid_userid), mApiUrl, groupId, userId); JacksonRequest<ContactGroups> userAddRequest = new JacksonRequest<ContactGroups>(contactsUrl, ContactGroups.class, null, new Listener<ContactGroups>() { public void onResponse(ContactGroups response) { try { mResolver.applyBatch(AbstractContract.CONTENT_AUTHORITY, new ContactGroupHandler(response.group).parse()); SyncHelper.getInstance(context).forcePerformContactsSync(null); } catch (RemoteException e) { e.printStackTrace(); } catch (OperationApplicationException e) { e.printStackTrace(); } Toast.makeText(context, R.string.successfully_added, Toast.LENGTH_SHORT).show(); } }, new ErrorListener() { public void onErrorResponse(VolleyError error) { if (error.getMessage() != null) Log.e(TAG, error.getMessage()); Toast.makeText(context, "Fehler: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } }, Method.PUT); try { Server server = Prefs.getInstance(context).getServer(); OAuthConnector.with(server).sign(userAddRequest); } catch (OAuthMessageSignerException e) { e.printStackTrace(); } catch (OAuthExpectationFailedException e) { e.printStackTrace(); } catch (OAuthCommunicationException e) { e.printStackTrace(); } catch (OAuthNotAuthorizedException e) { StuffUtil.startSignInActivity(context); } userAddRequest.setPriority(Request.Priority.IMMEDIATE); StudIPApplication.getInstance().addToRequestQueue(userAddRequest); } private static void deleteUserFromGroup(final String userId, final String groupId, final int groupIntId, final int userIntId, final Context context) { String contactsUrl = String.format(context.getString(R.string.restip_contacts_groups_groupid_userid), mApiUrl, groupId, userId); StringRequest request = new StringRequest(Method.DELETE, contactsUrl, new Listener<String>() { public void onResponse(String response) { context.getContentResolver() .delete(ContactsContract.CONTENT_URI_CONTACT_GROUP_MEMBERS.buildUpon() .appendPath(String.format("%d", groupIntId)).build(), ContactsContract.Columns.Contacts.USER_ID + "= ?", new String[] { String.format("%d", userIntId) }); SyncHelper.getInstance(context).forcePerformContactsSync(null); Toast.makeText(context, R.string.successfully_deleted, Toast.LENGTH_SHORT).show(); } }, new ErrorListener() { public void onErrorResponse(VolleyError error) { if (error.getMessage() != null) Log.e(TAG, error.getMessage()); Toast.makeText(context, "Fehler: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } }); try { Server server = Prefs.getInstance(context).getServer(); OAuthConnector.with(server).sign(request); } catch (OAuthMessageSignerException e) { e.printStackTrace(); } catch (OAuthExpectationFailedException e) { e.printStackTrace(); } catch (OAuthCommunicationException e) { e.printStackTrace(); } catch (OAuthNotAuthorizedException e) { StuffUtil.startSignInActivity(context); } request.setPriority(Request.Priority.IMMEDIATE); StudIPApplication.getInstance().addToRequestQueue(request); } private static void addUserToContacts(final String userId, final Context context) { String contactsUrl = String.format(context.getString(R.string.restip_contacts_contactid), mApiUrl, userId); JacksonRequest<Contacts> contactAddRequest = new JacksonRequest<Contacts>(contactsUrl, Contacts.class, null, new Listener<Contacts>() { public void onResponse(Contacts response) { try { mResolver.applyBatch(AbstractContract.CONTENT_AUTHORITY, new ContactsHandler(response).parse()); SyncHelper.getInstance(context).forcePerformContactsSync(null); } catch (RemoteException e) { e.printStackTrace(); } catch (OperationApplicationException e) { e.printStackTrace(); } Toast.makeText(context, R.string.successfully_added, Toast.LENGTH_SHORT).show(); } }, new ErrorListener() { /* * (non-Javadoc) * * @see com.android.volley.Response.ErrorListener * #onErrorResponse(com.android.volley. VolleyError) */ public void onErrorResponse(VolleyError error) { if (error.getMessage() != null) Log.e(TAG, error.getMessage()); Toast.makeText(context, "Fehler: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } }, Method.PUT); try { Server server = Prefs.getInstance(context).getServer(); OAuthConnector.with(server).sign(contactAddRequest); } catch (OAuthMessageSignerException e) { e.printStackTrace(); } catch (OAuthExpectationFailedException e) { e.printStackTrace(); } catch (OAuthCommunicationException e) { e.printStackTrace(); } catch (OAuthNotAuthorizedException e) { StuffUtil.startSignInActivity(context); } contactAddRequest.setPriority(Request.Priority.IMMEDIATE); StudIPApplication.getInstance().addToRequestQueue(contactAddRequest); } private static void deleteUserFromContacts(final String userId, final Context context) { String contactsUrl = String.format(context.getString(R.string.restip_contacts_contactid), mApiUrl, userId); StringRequest request = new StringRequest(Method.DELETE, contactsUrl, new Listener<String>() { public void onResponse(String response) { context.getContentResolver().delete(ContactsContract.CONTENT_URI_CONTACT_GROUP_MEMBERS, ContactsContract.Columns.ContactGroupMembers.USER_ID + "= ?", new String[] { "'" + userId + "'" }); context.getContentResolver().delete( ContactsContract.CONTENT_URI_CONTACTS.buildUpon().appendPath(userId).build(), null, null); SyncHelper.getInstance(context).forcePerformContactsSync(null); Toast.makeText(context, R.string.successfully_deleted, Toast.LENGTH_SHORT).show(); } }, new ErrorListener() { public void onErrorResponse(VolleyError error) { if (error.getMessage() != null) Log.e(TAG, error.getMessage()); Toast.makeText(context, "Fehler: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } }); try { Server server = Prefs.getInstance(context).getServer(); OAuthConnector.with(server).sign(request); } catch (OAuthMessageSignerException e) { e.printStackTrace(); } catch (OAuthExpectationFailedException e) { e.printStackTrace(); } catch (OAuthCommunicationException e) { e.printStackTrace(); } catch (OAuthNotAuthorizedException e) { StuffUtil.startSignInActivity(context); } request.setPriority(Request.Priority.IMMEDIATE); StudIPApplication.getInstance().addToRequestQueue(request); } protected interface UsersQuery { String[] projection = { UsersContract.Qualified.USERS_ID, UsersContract.Qualified.USERS_USER_ID, UsersContract.Qualified.USERS_USER_TITLE_PRE, UsersContract.Qualified.USERS_USER_FORENAME, UsersContract.Qualified.USERS_USER_LASTNAME, UsersContract.Qualified.USERS_USER_TITLE_POST, UsersContract.Qualified.USERS_USER_AVATAR_NORMAL, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_NAME, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_ID }; } public static class ContactGroupsDialogFragment extends DialogFragment { private String mUserId; private int mIntUserId; public ContactGroupsDialogFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUserId = getArguments().getString(ContactsContract.Columns.Contacts.USER_ID); mIntUserId = getArguments().getInt(ContactsContract.Columns.Contacts._ID); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final String[] projection = new String[] { ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_NAME, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_GROUP_ID, ContactsContract.Qualified.ContactGroups.CONTACT_GROUPS_ID }; final HashMap<String, Pair<Pair<String, Integer>, Boolean>> multimap = new HashMap<String, Pair<Pair<String, Integer>, Boolean>>(); final ArrayList<Pair<String, Integer>> allGroupIds = new ArrayList<Pair<String, Integer>>(); final ArrayList<String> allGroupNames = new ArrayList<String>(); // load all groups CursorLoader allGroupsloader = new CursorLoader(getActivity(), ContactsContract.CONTENT_URI_CONTACT_GROUPS, projection, ContactsContract.Columns.ContactGroups.GROUP_ID + " != ?", new String[] { getString(R.string.restip_contacts_groups_unassigned_id) }, ContactsContract.Columns.ContactGroups.GROUP_NAME + " ASC"); final Cursor cursorAllGroups = allGroupsloader.loadInBackground(); cursorAllGroups.moveToFirst(); while (!cursorAllGroups.isAfterLast()) { String groupName = cursorAllGroups.getString( cursorAllGroups.getColumnIndex(ContactsContract.Columns.ContactGroups.GROUP_NAME)); String groupId = cursorAllGroups .getString(cursorAllGroups.getColumnIndex(ContactsContract.Columns.ContactGroups.GROUP_ID)); int groupIntId = cursorAllGroups .getInt(cursorAllGroups.getColumnIndex(ContactsContract.Columns.ContactGroups._ID)); multimap.put(groupName, new Pair<Pair<String, Integer>, Boolean>( new Pair<String, Integer>(groupId, groupIntId), false)); cursorAllGroups.moveToNext(); } cursorAllGroups.close(); // load only the users groups CursorLoader selectedGroupsLoader = new CursorLoader(getActivity(), ContactsContract.CONTENT_URI_CONTACTS.buildUpon().appendPath(mUserId).build(), projection, null, null, ContactsContract.Columns.ContactGroups.GROUP_NAME + " ASC"); final Cursor userGroupsCursor = selectedGroupsLoader.loadInBackground(); userGroupsCursor.moveToFirst(); // set selected if group is users group while (!userGroupsCursor.isAfterLast()) { String userGroup = userGroupsCursor.getString( cursorAllGroups.getColumnIndex(ContactsContract.Columns.ContactGroups.GROUP_NAME)); if (multimap.containsKey(userGroup)) { Pair<String, Integer> groupIdPair = multimap.get(userGroup).first; multimap.put(userGroup, new Pair<Pair<String, Integer>, Boolean>(groupIdPair, true)); } userGroupsCursor.moveToNext(); } userGroupsCursor.close(); Iterator<Entry<String, Pair<Pair<String, Integer>, Boolean>>> it = multimap.entrySet().iterator(); int row = 0; boolean[] primitivValuesArr = new boolean[multimap.size()]; while (it.hasNext()) { Map.Entry<String, Pair<Pair<String, Integer>, Boolean>> pairs = (Map.Entry<String, Pair<Pair<String, Integer>, Boolean>>) it .next(); allGroupNames.add(pairs.getKey()); allGroupIds.add(pairs.getValue().first); primitivValuesArr[row] = pairs.getValue().second; row++; it.remove(); // avoids a ConcurrentModificationException } AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.manage_groups); builder.setMultiChoiceItems(allGroupNames.toArray(new CharSequence[allGroupNames.size()]), primitivValuesArr, new OnMultiChoiceClickListener() { public void onClick(DialogInterface dialog, int which, boolean isChecked) { if (isChecked) { addUserToGroup(mUserId, allGroupIds.get(which).first, getActivity()); } else { deleteUserFromGroup(mUserId, allGroupIds.get(which).first, allGroupIds.get(which).second, mIntUserId, getActivity()); } } }); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { /* * (non-Javadoc) * * @see * android.content.DialogInterface.OnClickListener#onClick * (android.content.DialogInterface, int) */ public void onClick(DialogInterface dialog, int which) { getDialog().cancel(); } }); return builder.create(); } } }