package com.electronapps.LJPro; import java.io.IOException; import java.lang.ref.WeakReference; import java.math.BigInteger; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import com.commonsware.cwac.wakeful.WakefulIntentService; import com.electronapps.LJPro.LJTypes.Friend; import com.electronapps.LJPro.LJTypes.FriendGroup; import android.app.Activity; import android.app.AlertDialog; import android.app.ListActivity; import android.app.Notification; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteCursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.Html; import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewManager; import android.view.View.OnClickListener; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TabHost; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; public class EditFriendGroups extends ListActivity { private Cursor mFriendsCursor; private Cursor mGroupsCursor; private LJDB LJDBAdapter; private SharedPreferences appPrefs; private final Object mLock = new Object(); private HashMap<Integer,BigInteger> groupsCache=new HashMap<Integer,BigInteger>(); private FriendGroupsAdapter m_adapter; private static Context mContext; private ObjectMapper serializer=new ObjectMapper(); boolean refreshing=false; boolean addShown=false; private int clickIndex; private boolean DEBUG=false; private boolean[] checked=new boolean[30]; private String journalname=""; private FriendGroup lpObj; private boolean[] fgSel; private boolean deleting=false; private boolean adding=false; private HashMap<Integer, Boolean> groupHash; private int fnameInd; private int fgroupsInd; private int gnameInd; private int gidInd; public static final String TAG = Accounts.class.getSimpleName(); protected static final boolean[] fgroupSel = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState!=null) { refreshing=savedInstanceState.getBoolean("updating"); addShown=savedInstanceState.getBoolean("addShown"); groupsCache=(HashMap<Integer, BigInteger>) savedInstanceState.getSerializable("groupsCache"); checked=savedInstanceState.getBooleanArray("checked"); } mContext=getApplicationContext(); Intent intent=getIntent(); journalname=intent.getStringExtra("journalname"); View friends=View.inflate(this,R.layout.friendsgroups,null); TextView header=(TextView) friends.findViewById(R.id.fgheader); if (header!=null) { header.setText(journalname); header.invalidate(); } setContentView(friends); m_adapter = new FriendGroupsAdapter(EditFriendGroups.this,null,R.layout.friendrow); setListAdapter(m_adapter); if (addShown) { showAddFriend(friends); } if(refreshing) { showUpdating(); } appPrefs=PreferenceManager.getDefaultSharedPreferences(this); registerForContextMenu(getListView()); populateFriendList(); mContext=getApplicationContext(); } private void populateFriendList() { Runnable createFriendsList=new Runnable() { public void run() { getFriends(); } }; Thread thread = new Thread(null,createFriendsList, "FriendList Background"); thread.start(); ListView listView=getListView(); listView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> adapter, View view, int position, long arg3) { clickIndex=position; showEditGroupsDialog(); } }); } protected void getFriends() { try { String[] fields=new String[2]; fields[0]=LJDB.KEY_FRIENDNAME; fields[1]=LJDB.KEY_GROUPMASK; LJDBAdapter=LJDB.getDB(getApplicationContext()); LJDBAdapter.open(); mFriendsCursor=LJDBAdapter.getFriends(journalname,fields); mGroupsCursor=LJDBAdapter.getFriendGroups(journalname,null); startManagingCursor(mFriendsCursor); startManagingCursor(mGroupsCursor); getColumnIndices(); getGroupHash(); runOnUiThread(new Runnable() {public void run() { m_adapter = new FriendGroupsAdapter(EditFriendGroups.this,mGroupsCursor,R.layout.friendgrouprow); setListAdapter(m_adapter); }}); Date d=new Date(); if (!refreshing&&(DEBUG|(d.getTime()-appPrefs.getLong(journalname+"friends_lastupdate",0)>appPrefs.getLong("friendsSync", 900000 )))) { refreshing=true; Intent updatefriends=new Intent(LJNet.LJ_GETFRIENDS); updatefriends.putExtra("journalname",journalname); WakefulIntentService.sendWakefulWork(mContext,updatefriends); } else { hideUpdating(); } } catch (Throwable r) { Log.e(TAG,r.getMessage(),r); } } void getColumnIndices() { fnameInd=mFriendsCursor.getColumnIndex(LJDB.KEY_FRIENDNAME); fgroupsInd=mFriendsCursor.getColumnIndex(LJDB.KEY_GROUPMASK); gnameInd=mGroupsCursor.getColumnIndex(LJDB.KEY_NAME); gidInd=mGroupsCursor.getColumnIndex(LJDB.KEY_ID); } void getGroupHash() { if (groupHash==null) groupHash=new HashMap<Integer,Boolean>(); mGroupsCursor.moveToFirst(); while(!mGroupsCursor.isAfterLast()) { groupHash.put(mGroupsCursor.getInt(gidInd), true); mGroupsCursor.moveToNext(); } } @Override protected void onSaveInstanceState(Bundle outState){ super.onSaveInstanceState(outState); outState.putBoolean("updating",refreshing); outState.putBoolean("addShown", addShown); outState.putSerializable("groupsCache", groupsCache); outState.putBooleanArray("checked", checked); } @Override public void onResume() { super.onResume(); IntentFilter friendfilter=new IntentFilter(); friendfilter.addAction(LJNet.LJ_XMLERROR); friendfilter.addAction(LJNet.LJ_FRIENDSUPDATED); friendfilter.addAction(LJNet.LJ_GROUPADDED); friendfilter.addAction(LJNet.LJ_GROUPEDITED); friendfilter.addAction(LJNet.LJ_GROUPDELETED); registerReceiver(LJFriendsReceiver,friendfilter); } @Override public void onPause() { super.onPause(); unregisterReceiver(LJFriendsReceiver); } @Override public void onDestroy() { super.onDestroy(); } public BroadcastReceiver LJFriendsReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action=intent.getAction(); if (action.equals(LJNet.LJ_XMLERROR)) { removeStickyBroadcast(intent); LJPro app=(LJPro) getApplication(); app.alertNetworkError(EditFriendGroups.this); refreshing = false; View updating = findViewById(R.id.updatingfriends); updating.setVisibility(View.GONE); } else if(action.equals(LJNet.LJ_FRIENDSUPDATED)) { removeStickyBroadcast(intent); if (refreshing) { refreshing=false; View updating=findViewById(R.id.updatingfriends); updating.setVisibility(View.GONE); doneToast(getString(R.string.groupsupdated)); } updateFriends(); } else if(action.equals(LJNet.LJ_GROUPADDED)) { removeStickyBroadcast(intent); addShown=false; hideUpdating(); broadcastUpdate(); final Bundle extras=intent.getExtras(); EditText addfriend=(EditText) findViewById(R.id.addfriend); addfriend.setText(""); Toast.makeText(EditFriendGroups.this, R.string.groupadded, Toast.LENGTH_LONG).show(); final Runnable addGroup=new Runnable(){ public void run() { ContentValues group=new ContentValues(); group.put("accountname", journalname); group.put("name",extras.getString("addgroup")); group.put("id",extras.getInt("addid")); group.put("updated",System.currentTimeMillis()/1000l); boolean success=LJDBAdapter.addDummyGroup(group); if (success) updateFriends(); } }; Thread friendadd=new Thread(null,addGroup,"Add Friend"); friendadd.start(); } else if(action.equals(LJNet.LJ_GROUPDELETED)||action.equals(LJNet.LJ_GROUPEDITED)) { removeStickyBroadcast(intent); updateFriends(); hideUpdating(); broadcastUpdate(); } } }; private void updateFriends() { SharedPreferences.Editor editor = appPrefs.edit(); Date d=new Date(); editor.putLong(journalname+"friends_lastupdate",d.getTime()); editor.commit(); // Very important Thread thread = new Thread(null, reQueryInBackground, "RefreshGroupsList Background"); try {thread.start();} catch(Throwable e) {Log.e(TAG,e.getMessage(),e);} } private Runnable reQueryInBackground = new Runnable() { public void run() { checked=new boolean[30]; mFriendsCursor.requery(); mGroupsCursor = LJDBAdapter.getFriendGroups(journalname, null); startManagingCursor(mGroupsCursor); checked = new boolean[mFriendsCursor.getCount()]; updateUI(); synchronized(mLock) { groupsCache.clear(); } } }; Runnable refreshList=new Runnable() { public void run() { m_adapter.changeCursor(mGroupsCursor);}}; private void updateUI() { runOnUiThread(refreshList); } protected void broadcastUpdate() { Intent updatefriends=new Intent(LJNet.LJ_GETFRIENDS); updatefriends.putExtra("journalname",journalname); WakefulIntentService.sendWakefulWork(mContext,updatefriends); } protected void doneToast(String text) { Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.fgroupsops, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { case R.id.addfriend: View editfriends=findViewById(R.id.editfriendgroups); showAddFriend(editfriends); break; case R.id.settings: Intent prefs=new Intent(getApplicationContext(),LJProPrefs.class); prefs.putExtra("scope", journalname); startActivity(prefs); break; case R.id.refresh: Intent updatefriends=new Intent(LJNet.LJ_GETFRIENDS); updatefriends.putExtra("journalname",journalname); WakefulIntentService.sendWakefulWork(mContext,updatefriends); showUpdating(); break; case R.id.help: Toast.makeText(this, "You pressed the Help!", Toast.LENGTH_LONG).show(); break; case R.id.removefriends: showDelDialog(); break; } return true; } private void showAddFriend(View view) { if (mGroupsCursor.getCount()==30) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.maxfriendgroups); builder.setMessage(R.string.maxfgroupsmsg); builder.setCancelable(true); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); }}); AlertDialog maxfriends=builder.create(); maxfriends.show(); } else { addShown=true; View addfriend=view.findViewById(R.id.addfgroupfooter); if (addfriend!=null) addfriend.setVisibility(View.VISIBLE); Button add=(Button) addfriend.findViewById(R.id.pfriendbutton); if (add!=null) {add.setOnClickListener(new OnClickListener() { public void onClick(View v) { EditText addfriend=(EditText) findViewById(R.id.addfriend); InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(addfriend.getWindowToken(), 0); String addFriend=addfriend.getText().toString(); if (addFriend.length()>0) { CheckBox publicview=(CheckBox) findViewById(R.id.publicvis); Boolean publicvis=publicview.isChecked(); addShown=false; View updating=findViewById(R.id.addfgroupfooter); updating.setVisibility(View.GONE); showUpdating(); int k=1; Integer addid=null; while (k<31) { if (groupHash.containsKey(k)) { k++; } else { addid=k; break; } } Intent editfriends=new Intent(LJNet.LJ_EDITFRIENDGROUPS); editfriends.putExtra("journalname", journalname); editfriends.putExtra("public", publicvis?1:0); editfriends.putExtra("addid",addid.toString()); editfriends.putExtra("addgroup", addFriend); WakefulIntentService.sendWakefulWork(mContext,editfriends); } else { View addfooter=findViewById(R.id.addfgroupfooter); addfooter.setVisibility(View.GONE); } } }); } } } private boolean[] fgSelO; protected void showEditGroupsDialog() { //TODO check for groups, still harvesting?? int numFriends=mFriendsCursor.getCount(); fgSel=new boolean[numFriends]; fgSelO=new boolean[numFriends]; final CharSequence[] items=new CharSequence[numFriends]; mGroupsCursor.moveToPosition(clickIndex); int id=mGroupsCursor.getInt(gidInd); mFriendsCursor.moveToFirst(); synchronized(mLock) { while (!mFriendsCursor.isAfterLast()){ int i=mFriendsCursor.getPosition(); items[i]=mFriendsCursor.getString(fnameInd); BigInteger groups=groupsCache.get(i); if (groups==null) { groups=BigInteger.valueOf(mFriendsCursor.getInt(fgroupsInd)); groupsCache.put(i, groups); } fgSel[i]=groups.testBit(id)?true:false; fgSelO[i]=fgSel[i]; mFriendsCursor.moveToNext(); } } AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.editgroupfriends)); builder.setMultiChoiceItems(items, fgSel,fgroupListener); builder.setCancelable(true); if (items.length>0) { builder.setPositiveButton("Update", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { showUpdating(); Runnable getGroupMasks=new Runnable() { public void run() { HashMap<String,Integer> groupmask=new HashMap<String, Integer>(); for (int i=0;i<items.length;i++) { if (fgSelO[i]!=fgSel[i]) { groupmask.put(items[i].toString(), groupsCache.get(i).intValue()); } } Intent editgroups=new Intent(LJNet.LJ_EDITFRIENDGROUPS); editgroups.putExtra("journalname", journalname); editgroups.putExtra("groupmask", groupmask); WakefulIntentService.sendWakefulWork(mContext,editgroups); } }; Thread dofgedits=new Thread(getGroupMasks,"groupMask Background"); dofgedits.start(); } } ); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } else { builder.setTitle(getString(R.string.nofgroups)); builder.setNegativeButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } AlertDialog alert = builder.create(); alert.setOwnerActivity(EditFriendGroups.this); alert.show(); } int buildGroupMask(char[] groups) { int max=0; for (int i=1;i<32;i++) { if (groups[i]=='1') { max=1; } } String groupMask=new String(groups); groupMask=groupMask.substring(0,max+1); groupMask=(new StringBuffer(groupMask).reverse()).toString(); int groupmask=Integer.parseInt(groupMask, 2); return groupmask; } private DialogInterface.OnMultiChoiceClickListener fgroupListener=new DialogInterface.OnMultiChoiceClickListener(){ public void onClick(DialogInterface dialog, int which, boolean isChecked) { synchronized(mLock) { BigInteger groups=groupsCache.get(clickIndex); int id=mGroupsCursor.getInt(gidInd); if(groups==null) { mFriendsCursor.moveToPosition(which); groups=BigInteger.valueOf(mFriendsCursor.getInt(fgroupsInd)); groupsCache.put(id, groups); } fgSel[which]=isChecked; mGroupsCursor.moveToPosition(clickIndex); if(isChecked) groupsCache.put(id,groups.setBit(which)); else groupsCache.put(id,groups.clearBit(which)); } } }; //protected boolean groupedits=false; private void showDelDialog() { final ArrayList<CharSequence> del=new ArrayList<CharSequence>(); ArrayList<Integer> delId=new ArrayList<Integer>(); for (int i=0;i<mGroupsCursor.getCount();i++) { if (checked[i]){ mGroupsCursor.moveToPosition(i); del.add(mGroupsCursor.getString(gnameInd)); delId.add(mGroupsCursor.getInt(gidInd)); } } final CharSequence[] items=(CharSequence[]) del.toArray(new CharSequence[del.size()]); final Integer[] itemID=(Integer[]) delId.toArray(new Integer[delId.size()]); AlertDialog.Builder builder = new AlertDialog.Builder(this); if (items.length>0) builder.setTitle(getString(R.string.confirmdel)); else builder.setTitle(getString(R.string.nofgchecked)); builder.setItems(items, null); builder.setCancelable(true); if (items.length>0) { builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Intent delfriends=new Intent(LJNet.LJ_EDITFRIENDGROUPS); showUpdating(); delfriends.putExtra("journalname",journalname); delfriends.putExtra("delgroups", itemID); WakefulIntentService.sendWakefulWork(mContext,delfriends); Runnable delFriends=new Runnable() { public void run() { boolean success=LJDBAdapter.deleteGroup(del,journalname); if (success) { updateFriends(); } } }; Thread thread = new Thread(null, delFriends, "delFriends Background"); try {thread.start();} catch(Throwable e) {Log.e(TAG,e.getMessage(),e);} } } ); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } else { builder.setNegativeButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); } AlertDialog alert = builder.create(); alert.setOwnerActivity(EditFriendGroups.this); alert.show(); } private void showUpdating() { runOnUiThread( new Runnable() { public void run() {refreshing=true; View updating=findViewById(R.id.updatingfriends); TextView updatemsg=(TextView)updating.findViewById(R.id.updatemsg); updatemsg.setText(R.string.updatingfgroups); updatemsg.invalidate(); updating.setVisibility(View.VISIBLE); } }); } private void hideUpdating() { runOnUiThread( new Runnable() { public void run() { refreshing=true; View updating=findViewById(R.id.updatingfriends); updating.setVisibility(View.GONE); } }); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; clickIndex=info.position; mGroupsCursor.moveToPosition(clickIndex); MenuInflater inflater = getMenuInflater(); if (checked[clickIndex]) { inflater.inflate(R.menu.friendscontext2, menu); } else { inflater.inflate(R.menu.friendscontext, menu); } menu.setHeaderTitle(mGroupsCursor.getString(gnameInd)); } @Override public boolean onContextItemSelected(MenuItem item) { super.onContextItemSelected(item); switch (item.getItemId()) { case R.id.markdelete: toggleDeletion(); break; case R.id.unmarkdelete: toggleDeletion(); break; case R.id.editgroups: showEditGroupsDialog(); break; } return true; } public void toggleDeletion() { ListView listView=getListView(); int wantedPosition=clickIndex; int firstPosition = listView.getFirstVisiblePosition(); // This is the same as child #0 int wantedChild = wantedPosition - firstPosition; // Say, first visible position is 8, you want position 10, wantedChild will now be 2 // So that means your view is child #2 in the ViewGroup: if (wantedChild < 0 || wantedChild >= listView.getChildCount()) { Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen."); } else { // Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead. View row = listView.getChildAt(wantedChild); if (row!=null) { CheckBox checked=(CheckBox) row.findViewById(R.id.delete); checked.setChecked(!checked.isChecked()); checked.invalidate(); } } } public boolean getChecked(int index) { // TODO Auto-generated method stub return checked[index]; } public void setChecked(Integer position,boolean isChecked) { checked[position]=isChecked; } }