1ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng/*
2ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Copyright (C) 2009 The Android Open Source Project
3ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng *
4ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
5ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * you may not use this file except in compliance with the License.
6ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * You may obtain a copy of the License at
7ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng *
8ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
9ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng *
10ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Unless required by applicable law or agreed to in writing, software
11ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
12ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * See the License for the specific language governing permissions and
14ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * limitations under the License.
15ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */
16ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
17ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengpackage com.android.contacts.common.list;
18ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
19ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.app.ActionBar;
20ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.app.Activity;
21ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.app.AlertDialog;
22ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.app.LoaderManager.LoaderCallbacks;
23ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.app.ProgressDialog;
24ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.AsyncTaskLoader;
25ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.ContentProviderOperation;
26ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.ContentResolver;
27ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.ContentValues;
28ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.Context;
29ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.DialogInterface;
30ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.Intent;
31ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.Loader;
32ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.OperationApplicationException;
33ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.content.SharedPreferences;
34ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.database.Cursor;
35ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.net.Uri;
36ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.os.Bundle;
37ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.os.RemoteException;
38ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.preference.PreferenceManager;
39ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.provider.ContactsContract;
40ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.provider.ContactsContract.Groups;
41ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.provider.ContactsContract.Settings;
42ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.util.Log;
43ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.view.ContextMenu;
44ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.view.LayoutInflater;
45ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.view.MenuItem;
46ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.view.MenuItem.OnMenuItemClickListener;
47ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.view.View;
48ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.view.ViewGroup;
49ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.widget.BaseExpandableListAdapter;
50ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.widget.CheckBox;
51ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.widget.ExpandableListAdapter;
52ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.widget.ExpandableListView;
53ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.widget.ExpandableListView.ExpandableListContextMenuInfo;
54ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport android.widget.TextView;
55ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
56ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.R;
57ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.model.AccountTypeManager;
58ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.model.ValuesDelta;
59ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.model.account.AccountType;
60ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.model.account.AccountWithDataSet;
61ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.model.account.GoogleAccountType;
62ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.util.EmptyService;
63ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.util.LocalizedNameResolver;
64ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.android.contacts.common.util.WeakAsyncTask;
65ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport com.google.common.collect.Lists;
66ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
67ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport java.util.ArrayList;
68ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport java.util.Collections;
69ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport java.util.Comparator;
70ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengimport java.util.Iterator;
71ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
72ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng/**
73ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * Shows a list of all available {@link Groups} available, letting the user
74ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng * select which ones they want to be visible.
75ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng */
76ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Chengpublic class CustomContactListFilterActivity extends Activity
77ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        implements View.OnClickListener, ExpandableListView.OnChildClickListener,
78ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        LoaderCallbacks<CustomContactListFilterActivity.AccountSet>
79ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng{
80ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final String TAG = "CustomContactListFilterActivity";
81ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
82ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final int ACCOUNT_SET_LOADER_ID = 1;
83ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
84ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private ExpandableListView mList;
85ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private DisplayAdapter mAdapter;
86ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
87ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private SharedPreferences mPrefs;
88ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
89ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
90ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected void onCreate(Bundle icicle) {
91ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        super.onCreate(icicle);
92ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        setContentView(R.layout.contact_list_filter_custom);
93ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
94ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mList = (ExpandableListView) findViewById(android.R.id.list);
95ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mList.setOnChildClickListener(this);
96ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mList.setHeaderDividersEnabled(true);
97ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
98ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mAdapter = new DisplayAdapter(this);
99ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
100ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final LayoutInflater inflater = getLayoutInflater();
101ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
102ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        findViewById(R.id.btn_done).setOnClickListener(this);
103ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        findViewById(R.id.btn_discard).setOnClickListener(this);
104ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
105ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mList.setOnCreateContextMenuListener(this);
106ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
107ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mList.setAdapter(mAdapter);
108ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
109ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        ActionBar actionBar = getActionBar();
110ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (actionBar != null) {
111ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // android.R.id.home will be triggered in onOptionsItemSelected()
112ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            actionBar.setDisplayHomeAsUpEnabled(true);
113ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
114ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
115ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
116ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public static class CustomFilterConfigurationLoader extends AsyncTaskLoader<AccountSet> {
117ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
118ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private AccountSet mAccountSet;
119ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
120ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public CustomFilterConfigurationLoader(Context context) {
121ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            super(context);
122ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
123ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
124ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
125ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public AccountSet loadInBackground() {
126ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            Context context = getContext();
127ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
128ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final ContentResolver resolver = context.getContentResolver();
129ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
130ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountSet accounts = new AccountSet();
131ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            for (AccountWithDataSet account : accountTypes.getAccounts(false)) {
132ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final AccountType accountType = accountTypes.getAccountTypeForAccount(account);
133ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (accountType.isExtension() && !account.hasData(context)) {
134ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    // Extension with no data -- skip.
135ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    continue;
136ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
137ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
138ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                AccountDisplay accountDisplay =
139ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        new AccountDisplay(resolver, account.name, account.type, account.dataSet);
140ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
141ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final Uri.Builder groupsUri = Groups.CONTENT_URI.buildUpon()
142ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        .appendQueryParameter(Groups.ACCOUNT_NAME, account.name)
143ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        .appendQueryParameter(Groups.ACCOUNT_TYPE, account.type);
144ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (account.dataSet != null) {
145ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    groupsUri.appendQueryParameter(Groups.DATA_SET, account.dataSet).build();
146ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
147ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                android.content.EntityIterator iterator =
148ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        ContactsContract.Groups.newEntityIterator(resolver.query(
149ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        groupsUri.build(), null, null, null, null));
150ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                try {
151ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    boolean hasGroups = false;
152ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
153ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    // Create entries for each known group
154ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    while (iterator.hasNext()) {
155ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        final ContentValues values = iterator.next().getEntityValues();
156ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        final GroupDelta group = GroupDelta.fromBefore(values);
157ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        accountDisplay.addGroup(group);
158ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        hasGroups = true;
159ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    }
160ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    // Create single entry handling ungrouped status
161ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    accountDisplay.mUngrouped =
162ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        GroupDelta.fromSettings(resolver, account.name, account.type,
163ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                                account.dataSet, hasGroups);
164ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    accountDisplay.addGroup(accountDisplay.mUngrouped);
165ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                } finally {
166ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    iterator.close();
167ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
168ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
169ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                accounts.add(accountDisplay);
170ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
171ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
172ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return accounts;
173ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
174ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
175ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
176ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void deliverResult(AccountSet cursor) {
177ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (isReset()) {
178ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return;
179ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
180ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
181ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mAccountSet = cursor;
182ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
183ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (isStarted()) {
184ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                super.deliverResult(cursor);
185ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
186ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
187ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
188ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
189ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected void onStartLoading() {
190ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (mAccountSet != null) {
191ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                deliverResult(mAccountSet);
192ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
193ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (takeContentChanged() || mAccountSet == null) {
194ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                forceLoad();
195ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
196ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
197ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
198ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
199ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected void onStopLoading() {
200ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            cancelLoad();
201ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
202ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
203ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
204ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected void onReset() {
205ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            super.onReset();
206ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            onStopLoading();
207ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mAccountSet = null;
208ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
209ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
210ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
211ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
212ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected void onStart() {
213ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        getLoaderManager().initLoader(ACCOUNT_SET_LOADER_ID, null, this);
214ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        super.onStart();
215ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
216ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
217ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
218ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public Loader<AccountSet> onCreateLoader(int id, Bundle args) {
219ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        return new CustomFilterConfigurationLoader(this);
220ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
221ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
222ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
223ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public void onLoadFinished(Loader<AccountSet> loader, AccountSet data) {
224ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mAdapter.setAccounts(data);
225ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
226ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
227ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
228ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public void onLoaderReset(Loader<AccountSet> loader) {
229ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        mAdapter.setAccounts(null);
230ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
231ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
232ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final int DEFAULT_SHOULD_SYNC = 1;
233ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final int DEFAULT_VISIBLE = 0;
234ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
235ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
236ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * Entry holding any changes to {@link Groups} or {@link Settings} rows,
237ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * such as {@link Groups#SHOULD_SYNC} or {@link Groups#GROUP_VISIBLE}.
238ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
239ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected static class GroupDelta extends ValuesDelta {
240ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private boolean mUngrouped = false;
241ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private boolean mAccountHasGroups;
242ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
243ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private GroupDelta() {
244ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            super();
245ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
246ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
247ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
248ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Build {@link GroupDelta} from the {@link Settings} row for the given
249ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * {@link Settings#ACCOUNT_NAME}, {@link Settings#ACCOUNT_TYPE}, and
250ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * {@link Settings#DATA_SET}.
251ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
252ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public static GroupDelta fromSettings(ContentResolver resolver, String accountName,
253ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                String accountType, String dataSet, boolean accountHasGroups) {
254ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Uri.Builder settingsUri = Settings.CONTENT_URI.buildUpon()
255ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    .appendQueryParameter(Settings.ACCOUNT_NAME, accountName)
256ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType);
257ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (dataSet != null) {
258ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                settingsUri.appendQueryParameter(Settings.DATA_SET, dataSet);
259ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
260ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Cursor cursor = resolver.query(settingsUri.build(), new String[] {
261ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    Settings.SHOULD_SYNC, Settings.UNGROUPED_VISIBLE
262ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }, null, null, null);
263ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
264ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            try {
265ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final ContentValues values = new ContentValues();
266ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                values.put(Settings.ACCOUNT_NAME, accountName);
267ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                values.put(Settings.ACCOUNT_TYPE, accountType);
268ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                values.put(Settings.DATA_SET, dataSet);
269ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
270ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (cursor != null && cursor.moveToFirst()) {
271ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    // Read existing values when present
272ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    values.put(Settings.SHOULD_SYNC, cursor.getInt(0));
273ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    values.put(Settings.UNGROUPED_VISIBLE, cursor.getInt(1));
274ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return fromBefore(values).setUngrouped(accountHasGroups);
275ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                } else {
276ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    // Nothing found, so treat as create
277ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    values.put(Settings.SHOULD_SYNC, DEFAULT_SHOULD_SYNC);
278ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    values.put(Settings.UNGROUPED_VISIBLE, DEFAULT_VISIBLE);
279ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return fromAfter(values).setUngrouped(accountHasGroups);
280ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
281ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } finally {
282ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (cursor != null) cursor.close();
283ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
284ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
285ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
286ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public static GroupDelta fromBefore(ContentValues before) {
287ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final GroupDelta entry = new GroupDelta();
288ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            entry.mBefore = before;
289ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            entry.mAfter = new ContentValues();
290ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return entry;
291ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
292ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
293ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public static GroupDelta fromAfter(ContentValues after) {
294ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final GroupDelta entry = new GroupDelta();
295ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            entry.mBefore = null;
296ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            entry.mAfter = after;
297ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return entry;
298ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
299ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
300ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected GroupDelta setUngrouped(boolean accountHasGroups) {
301ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mUngrouped = true;
302ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mAccountHasGroups = accountHasGroups;
303ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return this;
304ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
305ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
306ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
307ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public boolean beforeExists() {
308ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return mBefore != null;
309ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
310ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
311ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public boolean getShouldSync() {
312ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return getAsInteger(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC,
313ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    DEFAULT_SHOULD_SYNC) != 0;
314ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
315ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
316ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public boolean getVisible() {
317ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return getAsInteger(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE,
318ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    DEFAULT_VISIBLE) != 0;
319ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
320ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
321ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void putShouldSync(boolean shouldSync) {
322ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            put(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
323ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
324ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
325ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void putVisible(boolean visible) {
326ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            put(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, visible ? 1 : 0);
327ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
328ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
329ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private String getAccountType() {
330ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return (mBefore == null ? mAfter : mBefore).getAsString(Settings.ACCOUNT_TYPE);
331ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
332ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
333ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public CharSequence getTitle(Context context) {
334ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (mUngrouped) {
335ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final String customAllContactsName =
336ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        LocalizedNameResolver.getAllContactsName(context, getAccountType());
337ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (customAllContactsName != null) {
338ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return customAllContactsName;
339ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
340ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (mAccountHasGroups) {
341ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return context.getText(R.string.display_ungrouped);
342ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                } else {
343ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return context.getText(R.string.display_all_contacts);
344ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
345ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
346ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final Integer titleRes = getAsInteger(Groups.TITLE_RES);
347ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (titleRes != null) {
348ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    final String packageName = getAsString(Groups.RES_PACKAGE);
349ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return context.getPackageManager().getText(packageName, titleRes, null);
350ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                } else {
351ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return getAsString(Groups.TITLE);
352ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
353ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
354ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
355ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
356ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
357ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Build a possible {@link ContentProviderOperation} to persist any
358ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * changes to the {@link Groups} or {@link Settings} row described by
359ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * this {@link GroupDelta}.
360ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
361ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public ContentProviderOperation buildDiff() {
362ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (isInsert()) {
363ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                // Only allow inserts for Settings
364ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (mUngrouped) {
365ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    mAfter.remove(mIdColumn);
366ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return ContentProviderOperation.newInsert(Settings.CONTENT_URI)
367ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .withValues(mAfter)
368ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .build();
369ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
370ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                else {
371ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    throw new IllegalStateException("Unexpected diff");
372ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
373ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else if (isUpdate()) {
374ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (mUngrouped) {
375ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    String accountName = this.getAsString(Settings.ACCOUNT_NAME);
376ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    String accountType = this.getAsString(Settings.ACCOUNT_TYPE);
377ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    String dataSet = this.getAsString(Settings.DATA_SET);
378ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    StringBuilder selection = new StringBuilder(Settings.ACCOUNT_NAME + "=? AND "
379ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            + Settings.ACCOUNT_TYPE + "=?");
380ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    String[] selectionArgs;
381ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    if (dataSet == null) {
382ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        selection.append(" AND " + Settings.DATA_SET + " IS NULL");
383ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        selectionArgs = new String[] {accountName, accountType};
384ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    } else {
385ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        selection.append(" AND " + Settings.DATA_SET + "=?");
386ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        selectionArgs = new String[] {accountName, accountType, dataSet};
387ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    }
388ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return ContentProviderOperation.newUpdate(Settings.CONTENT_URI)
389ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .withSelection(selection.toString(), selectionArgs)
390ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .withValues(mAfter)
391ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .build();
392ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                } else {
393ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    return ContentProviderOperation.newUpdate(
394ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                                    addCallerIsSyncAdapterParameter(Groups.CONTENT_URI))
395ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .withSelection(Groups._ID + "=" + this.getId(), null)
396ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .withValues(mAfter)
397ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            .build();
398ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
399ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
400ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return null;
401ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
402ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
403ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
404ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
405ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static Uri addCallerIsSyncAdapterParameter(Uri uri) {
406ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        return uri.buildUpon()
407ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
408ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            .build();
409ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
410ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
411ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
412ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * {@link Comparator} to sort by {@link Groups#_ID}.
413ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
414ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static Comparator<GroupDelta> sIdComparator = new Comparator<GroupDelta>() {
415ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public int compare(GroupDelta object1, GroupDelta object2) {
416ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Long id1 = object1.getId();
417ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Long id2 = object2.getId();
418ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (id1 == null && id2 == null) {
419ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return 0;
420ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else if (id1 == null) {
421ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return -1;
422ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else if (id2 == null) {
423ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return 1;
424ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else if (id1 < id2) {
425ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return -1;
426ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else if (id1 > id2) {
427ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return 1;
428ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
429ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return 0;
430ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
431ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
432ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    };
433ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
434ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
435ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * Set of all {@link AccountDisplay} entries, one for each source.
436ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
437ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected static class AccountSet extends ArrayList<AccountDisplay> {
438ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public ArrayList<ContentProviderOperation> buildDiff() {
439ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
440ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            for (AccountDisplay account : this) {
441ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                account.buildDiff(diff);
442ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
443ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return diff;
444ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
445ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
446ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
447ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
448ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * {@link GroupDelta} details for a single {@link AccountWithDataSet}, usually shown as
449ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * children under a single expandable group.
450ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
451ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected static class AccountDisplay {
452ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public final String mName;
453ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public final String mType;
454ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public final String mDataSet;
455ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
456ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public GroupDelta mUngrouped;
457ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList();
458ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public ArrayList<GroupDelta> mUnsyncedGroups = Lists.newArrayList();
459ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
460ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
461ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Build an {@link AccountDisplay} covering all {@link Groups} under the
462ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * given {@link AccountWithDataSet}.
463ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
464ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public AccountDisplay(ContentResolver resolver, String accountName, String accountType,
465ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                String dataSet) {
466ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mName = accountName;
467ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mType = accountType;
468ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mDataSet = dataSet;
469ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
470ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
471ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
472ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Add the given {@link GroupDelta} internally, filing based on its
473ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * {@link GroupDelta#getShouldSync()} status.
474ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
475ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private void addGroup(GroupDelta group) {
476ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (group.getShouldSync()) {
477ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                mSyncedGroups.add(group);
478ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
479ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                mUnsyncedGroups.add(group);
480ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
481ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
482ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
483ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
484ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Set the {@link GroupDelta#putShouldSync(boolean)} value for all
485ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * children {@link GroupDelta} rows.
486ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
487ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void setShouldSync(boolean shouldSync) {
488ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Iterator<GroupDelta> oppositeChildren = shouldSync ?
489ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    mUnsyncedGroups.iterator() : mSyncedGroups.iterator();
490ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            while (oppositeChildren.hasNext()) {
491ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final GroupDelta child = oppositeChildren.next();
492ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                setShouldSync(child, shouldSync, false);
493ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                oppositeChildren.remove();
494ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
495ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
496ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
497ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void setShouldSync(GroupDelta child, boolean shouldSync) {
498ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            setShouldSync(child, shouldSync, true);
499ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
500ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
501ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
502ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Set {@link GroupDelta#putShouldSync(boolean)}, and file internally
503ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * based on updated state.
504ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
505ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void setShouldSync(GroupDelta child, boolean shouldSync, boolean attemptRemove) {
506ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            child.putShouldSync(shouldSync);
507ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (shouldSync) {
508ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (attemptRemove) {
509ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    mUnsyncedGroups.remove(child);
510ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
511ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                mSyncedGroups.add(child);
512ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                Collections.sort(mSyncedGroups, sIdComparator);
513ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
514ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (attemptRemove) {
515ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    mSyncedGroups.remove(child);
516ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
517ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                mUnsyncedGroups.add(child);
518ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
519ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
520ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
521ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
522ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * Build set of {@link ContentProviderOperation} to persist any user
523ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * changes to {@link GroupDelta} rows under this {@link AccountWithDataSet}.
524ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
525ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void buildDiff(ArrayList<ContentProviderOperation> diff) {
526ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            for (GroupDelta group : mSyncedGroups) {
527ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final ContentProviderOperation oper = group.buildDiff();
528ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (oper != null) diff.add(oper);
529ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
530ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            for (GroupDelta group : mUnsyncedGroups) {
531ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final ContentProviderOperation oper = group.buildDiff();
532ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                if (oper != null) diff.add(oper);
533ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
534ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
535ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
536ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
537ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
538ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * {@link ExpandableListAdapter} that shows {@link GroupDelta} settings,
539ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * grouped by {@link AccountWithDataSet} type. Shows footer row when any groups are
540ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * unsynced, as determined through {@link AccountDisplay#mUnsyncedGroups}.
541ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
542ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected static class DisplayAdapter extends BaseExpandableListAdapter {
543ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private Context mContext;
544ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private LayoutInflater mInflater;
545ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private AccountTypeManager mAccountTypes;
546ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private AccountSet mAccounts;
547ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
548ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private boolean mChildWithPhones = false;
549ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
550ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public DisplayAdapter(Context context) {
551ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mContext = context;
552ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
553ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mAccountTypes = AccountTypeManager.getInstance(context);
554ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
555ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
556ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void setAccounts(AccountSet accounts) {
557ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mAccounts = accounts;
558ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            notifyDataSetChanged();
559ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
560ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
561ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /**
562ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * In group descriptions, show the number of contacts with phone
563ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         * numbers, in addition to the total contacts.
564ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng         */
565ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public void setChildDescripWithPhones(boolean withPhones) {
566ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mChildWithPhones = withPhones;
567ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
568ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
569ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
570ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
571ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                ViewGroup parent) {
572ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (convertView == null) {
573ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                convertView = mInflater.inflate(
574ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        R.layout.custom_contact_list_filter_account, parent, false);
575ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
576ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
577ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
578ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
579ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
580ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition);
581ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
582ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountType accountType = mAccountTypes.getAccountType(
583ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    account.mType, account.mDataSet);
584ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
585ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            text1.setText(account.mName);
586ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            text1.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
587ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            text2.setText(accountType.getDisplayLabel(mContext));
588ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
589ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return convertView;
590ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
591ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
592ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
593ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
594ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                View convertView, ViewGroup parent) {
595ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (convertView == null) {
596ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                convertView = mInflater.inflate(
597ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        R.layout.custom_contact_list_filter_group, parent, false);
598ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
599ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
600ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
601ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
602ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final CheckBox checkbox = (CheckBox)convertView.findViewById(android.R.id.checkbox);
603ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
604ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountDisplay account = mAccounts.get(groupPosition);
605ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final GroupDelta child = (GroupDelta)this.getChild(groupPosition, childPosition);
606ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (child != null) {
607ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                // Handle normal group, with title and checkbox
608ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final boolean groupVisible = child.getVisible();
609ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                checkbox.setVisibility(View.VISIBLE);
610ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                checkbox.setChecked(groupVisible);
611ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
612ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final CharSequence groupTitle = child.getTitle(mContext);
613ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                text1.setText(groupTitle);
614ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                text2.setVisibility(View.GONE);
615ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
616ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                // When unknown child, this is "more" footer view
617ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                checkbox.setVisibility(View.GONE);
618ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                text1.setText(R.string.display_more_groups);
619ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                text2.setVisibility(View.GONE);
620ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
621ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
622ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return convertView;
623ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
624ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
625ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
626ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public Object getChild(int groupPosition, int childPosition) {
627ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountDisplay account = mAccounts.get(groupPosition);
628ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final boolean validChild = childPosition >= 0
629ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    && childPosition < account.mSyncedGroups.size();
630ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (validChild) {
631ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return account.mSyncedGroups.get(childPosition);
632ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
633ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return null;
634ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
635ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
636ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
637ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
638ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public long getChildId(int groupPosition, int childPosition) {
639ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final GroupDelta child = (GroupDelta)getChild(groupPosition, childPosition);
640ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (child != null) {
641ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final Long childId = child.getId();
642ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return childId != null ? childId : Long.MIN_VALUE;
643ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } else {
644ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return Long.MIN_VALUE;
645ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
646ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
647ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
648ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
649ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public int getChildrenCount(int groupPosition) {
650ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // Count is any synced groups, plus possible footer
651ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AccountDisplay account = mAccounts.get(groupPosition);
652ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final boolean anyHidden = account.mUnsyncedGroups.size() > 0;
653ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return account.mSyncedGroups.size() + (anyHidden ? 1 : 0);
654ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
655ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
656ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
657ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public Object getGroup(int groupPosition) {
658ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return mAccounts.get(groupPosition);
659ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
660ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
661ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
662ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public int getGroupCount() {
663ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (mAccounts == null) {
664ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return 0;
665ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
666ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return mAccounts.size();
667ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
668ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
669ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
670ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public long getGroupId(int groupPosition) {
671ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return groupPosition;
672ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
673ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
674ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
675ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public boolean hasStableIds() {
676ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return true;
677ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
678ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
679ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
680ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public boolean isChildSelectable(int groupPosition, int childPosition) {
681ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return true;
682ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
683ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
684ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
685ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /** {@inheritDoc} */
686ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public void onClick(View view) {
687ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        switch (view.getId()) {
688ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            case R.id.btn_done: {
689ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                this.doSaveAction();
690ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                break;
691ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
692ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            case R.id.btn_discard: {
693ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                this.finish();
694ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                break;
695ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
696ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
697ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
698ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
699ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
700ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * Handle any clicks on {@link ExpandableListAdapter} children, which
701ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * usually mean toggling its visible state.
702ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
703ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
704ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public boolean onChildClick(ExpandableListView parent, View view, int groupPosition,
705ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            int childPosition, long id) {
706ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox);
707ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
708ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
709ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
710ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (child != null) {
711ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            checkbox.toggle();
712ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            child.putVisible(checkbox.isChecked());
713ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        } else {
714ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // Open context menu for bringing back unsynced
715ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            this.openContextMenu(view);
716ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
717ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        return true;
718ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
719ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
720ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    // TODO: move these definitions to framework constants when we begin
721ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    // defining this mode through <sync-adapter> tags
722ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final int SYNC_MODE_UNSUPPORTED = 0;
723ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final int SYNC_MODE_UNGROUPED = 1;
724ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private static final int SYNC_MODE_EVERYTHING = 2;
725ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
726ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected int getSyncMode(AccountDisplay account) {
727ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        // TODO: read sync mode through <sync-adapter> definition
728ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (GoogleAccountType.ACCOUNT_TYPE.equals(account.mType) && account.mDataSet == null) {
729ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return SYNC_MODE_EVERYTHING;
730ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        } else {
731ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return SYNC_MODE_UNSUPPORTED;
732ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
733ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
734ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
735ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
736ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public void onCreateContextMenu(ContextMenu menu, View view,
737ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            ContextMenu.ContextMenuInfo menuInfo) {
738ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        super.onCreateContextMenu(menu, view, menuInfo);
739ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
740ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        // Bail if not working with expandable long-press, or if not child
741ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (!(menuInfo instanceof ExpandableListContextMenuInfo)) return;
742ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
743ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo;
744ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
745ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
746ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
747ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        // Skip long-press on expandable parents
748ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (childPosition == -1) return;
749ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
750ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
751ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
752ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
753ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        // Ignore when selective syncing unsupported
754ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final int syncMode = getSyncMode(account);
755ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (syncMode == SYNC_MODE_UNSUPPORTED) return;
756ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
757ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (child != null) {
758ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            showRemoveSync(menu, account, child, syncMode);
759ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        } else {
760ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            showAddSync(menu, account, syncMode);
761ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
762ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
763ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
764ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected void showRemoveSync(ContextMenu menu, final AccountDisplay account,
765ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final GroupDelta child, final int syncMode) {
766ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final CharSequence title = child.getTitle(this);
767ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
768ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        menu.setHeaderTitle(title);
769ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        menu.add(R.string.menu_sync_remove).setOnMenuItemClickListener(
770ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                new OnMenuItemClickListener() {
771ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    public boolean onMenuItemClick(MenuItem item) {
772ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        handleRemoveSync(account, child, syncMode, title);
773ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        return true;
774ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    }
775ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                });
776ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
777ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
778ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected void handleRemoveSync(final AccountDisplay account, final GroupDelta child,
779ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final int syncMode, CharSequence title) {
780ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final boolean shouldSyncUngrouped = account.mUngrouped.getShouldSync();
781ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (syncMode == SYNC_MODE_EVERYTHING && shouldSyncUngrouped
782ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                && !child.equals(account.mUngrouped)) {
783ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // Warn before removing this group when it would cause ungrouped to stop syncing
784ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
785ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final CharSequence removeMessage = this.getString(
786ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    R.string.display_warn_remove_ungrouped, title);
787ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            builder.setTitle(R.string.menu_sync_remove);
788ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            builder.setMessage(removeMessage);
789ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            builder.setNegativeButton(android.R.string.cancel, null);
790ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
791ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                public void onClick(DialogInterface dialog, int which) {
792ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    // Mark both this group and ungrouped to stop syncing
793ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    account.setShouldSync(account.mUngrouped, false);
794ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    account.setShouldSync(child, false);
795ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    mAdapter.notifyDataSetChanged();
796ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                }
797ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            });
798ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            builder.show();
799ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        } else {
800ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // Mark this group to not sync
801ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            account.setShouldSync(child, false);
802ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mAdapter.notifyDataSetChanged();
803ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
804ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
805ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
806ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    protected void showAddSync(ContextMenu menu, final AccountDisplay account, final int syncMode) {
807ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        menu.setHeaderTitle(R.string.dialog_sync_add);
808ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
809ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        // Create item for each available, unsynced group
810ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        for (final GroupDelta child : account.mUnsyncedGroups) {
811ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            if (!child.getShouldSync()) {
812ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final CharSequence title = child.getTitle(this);
813ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() {
814ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    public boolean onMenuItemClick(MenuItem item) {
815ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        // Adding specific group for syncing
816ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        if (child.mUngrouped && syncMode == SYNC_MODE_EVERYTHING) {
817ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            account.setShouldSync(true);
818ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        } else {
819ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                            account.setShouldSync(child, true);
820ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        }
821ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        mAdapter.notifyDataSetChanged();
822ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                        return true;
823ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    }
824ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                });
825ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
826ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
827ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
828ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
829ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @SuppressWarnings("unchecked")
830ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    private void doSaveAction() {
831ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (mAdapter == null || mAdapter.mAccounts == null) {
832ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            finish();
833ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return;
834ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
835ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
836ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        setResult(RESULT_OK);
837ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
838ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        final ArrayList<ContentProviderOperation> diff = mAdapter.mAccounts.buildDiff();
839ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        if (diff.isEmpty()) {
840ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            finish();
841ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return;
842ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
843ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
844ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        new UpdateTask(this).execute(diff);
845ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
846ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
847ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    /**
848ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * Background task that persists changes to {@link Groups#GROUP_VISIBLE},
849ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     * showing spinner dialog to user while updating.
850ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng     */
851ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public static class UpdateTask extends
852ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            WeakAsyncTask<ArrayList<ContentProviderOperation>, Void, Void, Activity> {
853ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        private ProgressDialog mProgress;
854ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
855ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        public UpdateTask(Activity target) {
856ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            super(target);
857ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
858ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
859ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /** {@inheritDoc} */
860ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
861ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected void onPreExecute(Activity target) {
862ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Context context = target;
863ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
864ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            mProgress = ProgressDialog.show(
865ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                    context, null, context.getText(R.string.savingDisplayGroups));
866ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
867ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // Before starting this task, start an empty service to protect our
868ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // process from being reclaimed by the system.
869ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            context.startService(new Intent(context, EmptyService.class));
870ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
871ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
872ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /** {@inheritDoc} */
873ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
874ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected Void doInBackground(
875ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                Activity target, ArrayList<ContentProviderOperation>... params) {
876ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Context context = target;
877ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final ContentValues values = new ContentValues();
878ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final ContentResolver resolver = context.getContentResolver();
879ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
880ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            try {
881ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                final ArrayList<ContentProviderOperation> diff = params[0];
882ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                resolver.applyBatch(ContactsContract.AUTHORITY, diff);
883ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } catch (RemoteException e) {
884ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                Log.e(TAG, "Problem saving display groups", e);
885ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } catch (OperationApplicationException e) {
886ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                Log.e(TAG, "Problem saving display groups", e);
887ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
888ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
889ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            return null;
890ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
891ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
892ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        /** {@inheritDoc} */
893ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        @Override
894ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        protected void onPostExecute(Activity target, Void result) {
895ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            final Context context = target;
896ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
897ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            try {
898ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                mProgress.dismiss();
899ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            } catch (Exception e) {
900ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                Log.e(TAG, "Error dismissing progress dialog", e);
901ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            }
902ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
903ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            target.finish();
904ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
905ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            // Stop the service that was protecting us
906ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            context.stopService(new Intent(context, EmptyService.class));
907ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
908ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
909ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng
910ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    @Override
911ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    public boolean onOptionsItemSelected(MenuItem item) {
912ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        switch (item.getItemId()) {
913ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            case android.R.id.home:
914ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                // Pretend cancel.
915ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                setResult(Activity.RESULT_CANCELED);
916ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                finish();
917ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                return true;
918ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng            default:
919ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng                break;
920ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        }
921ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng        return super.onOptionsItemSelected(item);
922ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng    }
923ba2c125b07086a88a3517fcf381a3a400c42afd3Chiao Cheng}
924