package cri.sanity.screen; import cri.sanity.*; import cri.sanity.util.*; import java.util.Map; import java.util.HashMap; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceCategory; import android.preference.CheckBoxPreference; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.CommonDataKinds.GroupMembership; import android.provider.ContactsContract.Data; import android.util.Pair; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; public class ContactsActivity extends ScreenActivity { private static final String SEP = FilterActivity.SEP; private static final int CODE_SEARCH = 1; private PreferenceCategory prefGroup; private String sect; private boolean changed, grouped; private Map<String,Pref> prefs; private Handler handler = new Handler() { @Override @SuppressWarnings("unchecked") public void handleMessage(Message msg) { if(msg == null) return; Pair<Pref,CharSequence> pair = (Pair<Pref,CharSequence>)msg.obj; pair.first.setSummary(pair.second); } }; //---- overriding @Override public void onCreate(Bundle savedInstanceState) { skipAllKeys = true; screener(ContactsActivity.class, R.xml.filter_contacts, R.layout.img_contacts); super.onCreate(savedInstanceState); prefGroup = (PreferenceCategory)pref("filter_contacts"); Intent i = getIntent(); sect = i.getStringExtra(FilterActivity.EXTRA_SECT ); String t = i.getStringExtra(FilterActivity.EXTRA_TITLE); if(!A.empty(t)) pref("filter_header").setTitle(prefGroup.getTitle()+" ("+t+')'); on("filter_search", new Click(){ public boolean on(){ search(); return true; }}); readContacts(); changed = false; grouped = false; } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.contacts, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.search : search(); break; case R.id.selall : selall(); break; case R.id.selnone: selnone(); break; case R.id.canc : canc(); break; default: return super.onOptionsItemSelected(item); } return true; } @Override public void onStart() { super.onStart(); if(!grouped) new Async(){ public void run(){ readContactGroups(this); }}.execute(); } @Override public void onBackPressed() { if(isFinishing()) return; Intent i = new Intent(); i.putExtra(FilterActivity.EXTRA_SECT, saveList()); setResult(RESULT_OK, i); super.onBackPressed(); } @Override public void onActivityResult(int code, int res, Intent i) { if(i==null || code!=CODE_SEARCH) return; Cursor c = A.resolver().query(i.getData(), new String[]{ Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null); if(c.moveToFirst()) { Pref p = prefs.get(c.getString(c.getColumnIndex(Contacts._ID))); int msgId = p!=null? p.isChecked()? R.string.msg_contact_unsel : R.string.msg_contact_sel : R.string.msg_contact_err; A.toast(String.format(A.s(msgId), c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME)))); if(p == null) return; p.setChecked(!p.isChecked()); changed = true; } c.close(); } //---- private api private void readContacts() { Cursor c = A.resolver().query( Contacts.CONTENT_URI, new String[]{ Contacts._ID, Contacts.DISPLAY_NAME, Contacts.STARRED }, Contacts.HAS_PHONE_NUMBER+"=1", null, Contacts.DISPLAY_NAME ); final int n = c.getCount(); if(n <= 0) return; final String starred = A.s(R.string.starred); final int colId = c.getColumnIndex(Contacts._ID); final int colName = c.getColumnIndex(Contacts.DISPLAY_NAME); final int colStar = c.getColumnIndex(Contacts.STARRED); prefs = new HashMap<String,Pref>(n); Pref[] arr = new Pref[n]; // read all contacts for(int i=0; c.moveToNext(); i++) { String con = c.getString(colId); Pref pref = new Pref(con, c.getString(colName)); if(c.getString(colStar).equals("1")) pref.setSummary(starred); prefs.put(con, pref); arr[i] = pref; } c.close(); // first, put all already selected contacts for(String con : A.gets(keyAll()).split(SEP)) { Pref p = prefs.get(con); if(p == null) continue; prefGroup.addPreference(p); p.setChecked(true); } // after, put all remaining contacts for(Pref p : arr) if(!p.isChecked()) prefGroup.addPreference(p); } private void readContactGroups(Async async) { Cursor c = A.resolver().query( Data.CONTENT_URI, new String[]{ GroupMembership.GROUP_ROW_ID, GroupMembership.CONTACT_ID }, Data.MIMETYPE+"='"+GroupMembership.CONTENT_ITEM_TYPE+'\'', null, GroupMembership.CONTACT_ID ); if(async!=null && !async.isCancelled()) readContactGroups(async, c); c.close(); } private void readContactGroups(Async async, Cursor c) { if(!c.moveToFirst()) return; Map<String,String> groups = cri.sanity.util.Contacts.groups(); if(async!=null && async.isCancelled()) return; final int colGrp = c.getColumnIndex(GroupMembership.GROUP_ROW_ID); final int colCon = c.getColumnIndex(GroupMembership.CONTACT_ID); Pref lastPref = null; CharSequence sum = null; do { if(prefs == null) return; Pref p = prefs .get(c.getString(colCon)); String g = groups.get(c.getString(colGrp)); if(p==null || g==null) continue; if(p == lastPref) sum = sum+", "+g; else { if(lastPref != null) lastPref.setSummaryAsync(sum); sum = p.getSummary(); sum = sum==null || sum.length()<=0 ? g : sum+", "+g; lastPref = p; } if(async!=null && async.isCancelled()) return; } while(c.moveToNext()); if(lastPref != null) lastPref.setSummaryAsync(sum); grouped = true; } private int saveList() { if(changed) for(String con : A.gets(keyAll()).split(SEP)) A.del(keySect(con)); String cons = ""; int k = 0; int n = prefGroup.getPreferenceCount(); if(n > 0) { final StringBuilder sb = new StringBuilder(256); boolean first = true; for(int i=0; i<n; i++) { Pref pref = (Pref)prefGroup.getPreference(i); if(!pref.isChecked()) continue; ++k; if(!changed) continue; String con = pref.con; A.put(keySect(con), true); if(first) first = false; else sb.append(SEP); sb.append(con); } if(n > k) cons = sb.toString(); } if(changed) { if(n==0 || n>k) A.put(keyAll(), cons).putc(keyCount(), k); else A.put(keyAll(), "" ).putc(keyCount(), k = -1); } return k; // return number of selected contacts } private String keyAll() { return "filter_contacts_"+sect; } private String keyCount() { return "filter_contacts_count_"+sect; } private String keySect(String val) { return "filter_contact_"+val+sect; } private void search() { startActivityForResult(new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI), CODE_SEARCH); } private void selall() { final int n = prefGroup.getPreferenceCount(); if(n < 1) return; for(int i=0; i<n; i++) ((Pref)prefGroup.getPreference(i)).setChecked(true); A.toast(String.format(A.s(R.string.msg_selected_all), n+"")); changed = true; } private void selnone() { final int n = prefGroup.getPreferenceCount(); if(n < 1) return; for(int i=0; i<n; i++) ((Pref)prefGroup.getPreference(i)).setChecked(false); changed = true; } private void canc() { if(!changed) { finish(); return; } Alert.msg( A.s(R.string.ask_canc_all), new Alert.Click(){ public void on(){ changed = false; dismiss(); finish(); }}, null, Alert.OKCANC ); } //---- inner class private abstract class Async extends A.Async {} private class Pref extends CheckBoxPreference implements OnPreferenceChangeListener { private String con; private Pref(String con, String title) { super(ContactsActivity.this); this.con = con; setPersistent(false); setTitle(title); setOnPreferenceChangeListener(this); } private void setSummaryAsync(CharSequence sum) { Message msg = new Message(); msg.obj = new Pair<Pref,CharSequence>(this, sum==null? "" : sum); handler.sendMessage(msg); } @Override public boolean onPreferenceChange(Preference p, Object v) { return changed = true; } } }