ContactBrowseListFragment.java revision b3edee9ccf5b56e98c8dd21942685d4fbd4fac94
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.contacts.list;
17
18import com.android.contacts.R;
19import com.android.contacts.widget.ListViewUtils;
20
21import android.app.LoaderManager.LoaderCallbacks;
22import android.content.CursorLoader;
23import android.content.Loader;
24import android.content.SharedPreferences;
25import android.database.Cursor;
26import android.net.Uri;
27import android.os.Bundle;
28import android.provider.ContactsContract;
29import android.provider.ContactsContract.Contacts;
30import android.provider.ContactsContract.Directory;
31import android.text.TextUtils;
32import android.widget.ListView;
33
34/**
35 * Fragment containing a contact list used for browsing (as compared to
36 * picking a contact with one of the PICK intents).
37 */
38public abstract class ContactBrowseListFragment extends
39        ContactEntryListFragment<ContactListAdapter> {
40
41    private static final String KEY_SELECTED_URI = "selectedUri";
42    private static final String KEY_SELECTION_VERIFIED = "selectionVerified";
43
44    private static final int SELECTED_ID_LOADER = -3;
45
46    private static final int SELECTION_VISIBILITY_REQUEST_NONE = 0;
47    private static final int SELECTION_VISIBILITY_REQUEST_SMOOTH = 1;
48    private static final int SELECTION_VISIBILITY_REQUEST_INSTANT = 2;
49
50    private Uri mSelectedContactUri;
51    private long mSelectedContactDirectoryId;
52    private String mSelectedContactLookupKey;
53    private int mSelectionVisibilityRequest;
54    private boolean mSelectionVerified;
55    private boolean mLoadingLookupKey;
56
57    protected OnContactBrowserActionListener mListener;
58
59    private LoaderCallbacks<Cursor> mIdLoaderCallbacks = new LoaderCallbacks<Cursor>() {
60
61        @Override
62        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
63            return new CursorLoader(getContext(),
64                    mSelectedContactUri,
65                    new String[] { Contacts.LOOKUP_KEY },
66                    null,
67                    null,
68                    null);
69        }
70
71        @Override
72        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
73            mLoadingLookupKey = false;
74            String lookupKey = null;
75            if (data != null) {
76                if (data.moveToFirst()) {
77                    lookupKey = data.getString(0);
78                }
79            }
80            if (!TextUtils.equals(mSelectedContactLookupKey, lookupKey)) {
81                mSelectedContactLookupKey = lookupKey;
82                configureContactSelection();
83            }
84        }
85    };
86
87    @Override
88    public void restoreSavedState(Bundle savedState) {
89        super.restoreSavedState(savedState);
90
91        if (savedState == null) {
92            return;
93        }
94
95        mSelectedContactUri = savedState.getParcelable(KEY_SELECTED_URI);
96        mSelectionVerified = savedState.getBoolean(KEY_SELECTION_VERIFIED);
97        parseSelectedContactUri();
98    }
99
100    @Override
101    public void onSaveInstanceState(Bundle outState) {
102        super.onSaveInstanceState(outState);
103        outState.putParcelable(KEY_SELECTED_URI, mSelectedContactUri);
104        outState.putBoolean(KEY_SELECTION_VERIFIED, mSelectionVerified);
105    }
106
107    @Override
108    public void onStart() {
109        // Refresh the currently selected lookup in case it changed while we were sleeping
110        startLoadingContactLookupKey();
111        super.onStart();
112   }
113
114    protected void startLoadingContactLookupKey() {
115        if (isSelectionVisible() && mSelectedContactUri != null &&
116                (mSelectedContactDirectoryId == Directory.DEFAULT ||
117                        mSelectedContactDirectoryId == Directory.LOCAL_INVISIBLE)) {
118            mLoadingLookupKey = true;
119            getLoaderManager().restartLoader(SELECTED_ID_LOADER, null, mIdLoaderCallbacks);
120        } else {
121            getLoaderManager().stopLoader(SELECTED_ID_LOADER);
122        }
123    }
124
125    @Override
126    protected void prepareEmptyView() {
127        if (isSearchMode()) {
128            return;
129        } else if (isSyncActive()) {
130            if (hasIccCard()) {
131                setEmptyText(R.string.noContactsHelpTextWithSync);
132            } else {
133                setEmptyText(R.string.noContactsNoSimHelpTextWithSync);
134            }
135        } else {
136            if (hasIccCard()) {
137                setEmptyText(R.string.noContactsHelpText);
138            } else {
139                setEmptyText(R.string.noContactsNoSimHelpText);
140            }
141        }
142    }
143
144    public Uri getSelectedContactUri() {
145        return mSelectedContactUri;
146    }
147
148    public void setSelectedContactUri(Uri uri) {
149        if (mSelectedContactUri == null
150                || (mSelectedContactUri != null && !mSelectedContactUri.equals(uri))) {
151            mSelectedContactUri = uri;
152
153            parseSelectedContactUri();
154
155            if (isAdded()) {
156                // Configure the adapter to show the selection based on the lookup key extracted
157                // from the URI
158                configureAdapter();
159
160                // Also, launch a loader to pick up a new lookup key in case it has changed
161                startLoadingContactLookupKey();
162            }
163        }
164    }
165
166    private void parseSelectedContactUri() {
167        if (mSelectedContactUri != null) {
168            if (!mSelectedContactUri.toString()
169                    .startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
170                throw new IllegalStateException(
171                        "Contact list contains a non-lookup URI: " + mSelectedContactUri);
172            }
173
174            String directoryParam =
175                    mSelectedContactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
176            mSelectedContactDirectoryId = TextUtils.isEmpty(directoryParam)
177                    ? Directory.DEFAULT
178                    : Long.parseLong(directoryParam);
179            mSelectedContactLookupKey =
180                    Uri.encode(mSelectedContactUri.getPathSegments().get(2));
181        } else {
182            mSelectedContactDirectoryId = Directory.DEFAULT;
183            mSelectedContactLookupKey = null;
184        }
185    }
186
187    @Override
188    protected void configureAdapter() {
189        super.configureAdapter();
190        configureContactSelection();
191    }
192
193    /**
194     * Configures the adapter with the identity of the currently selected contact.
195     */
196    private void configureContactSelection() {
197        ContactListAdapter adapter = getAdapter();
198        if (adapter == null) {
199            return;
200        }
201
202        adapter.setSelectedContact(mSelectedContactDirectoryId, mSelectedContactLookupKey);
203        checkSelection();
204    }
205
206    @Override
207    protected void onPartitionLoaded(int partitionIndex, Cursor data) {
208        super.onPartitionLoaded(partitionIndex, data);
209        checkSelection();
210    }
211
212    private void checkSelection() {
213        if (mSelectionVerified || isSearchMode()) {
214            return;
215        }
216
217        ContactListAdapter adapter = getAdapter();
218        if (adapter.isLoading() || mLoadingLookupKey) {
219            return;
220        }
221
222        if (adapter.hasValidSelection()) {
223            mSelectionVerified = true;
224            requestSelectionOnScreenIfNeeded();
225            return;
226        }
227
228        notifyInvalidSelection();
229    }
230
231    public Uri getFirstContactUri() {
232        ContactListAdapter adapter = getAdapter();
233        return adapter.getFirstContactUri();
234    }
235
236    @Override
237    protected void startLoading() {
238        mSelectionVerified = false;
239        super.startLoading();
240    }
241
242    @Override
243    public void reloadData() {
244        mSelectionVerified = false;
245        super.reloadData();
246    }
247
248    public void setOnContactListActionListener(OnContactBrowserActionListener listener) {
249        mListener = listener;
250    }
251
252    public void createNewContact() {
253        mListener.onCreateNewContactAction();
254    }
255
256    public void viewContact(Uri contactUri) {
257        mListener.onViewContactAction(contactUri);
258    }
259
260    public void editContact(Uri contactUri) {
261        mListener.onEditContactAction(contactUri);
262    }
263
264    public void deleteContact(Uri contactUri) {
265        mListener.onDeleteContactAction(contactUri);
266    }
267
268    public void addToFavorites(Uri contactUri) {
269        mListener.onAddToFavoritesAction(contactUri);
270    }
271
272    public void removeFromFavorites(Uri contactUri) {
273        mListener.onRemoveFromFavoritesAction(contactUri);
274    }
275
276    public void callContact(Uri contactUri) {
277        mListener.onCallContactAction(contactUri);
278    }
279
280    public void smsContact(Uri contactUri) {
281        mListener.onSmsContactAction(contactUri);
282    }
283
284    private void notifyInvalidSelection() {
285        mListener.onInvalidSelection();
286    }
287
288    @Override
289    protected void finish() {
290        super.finish();
291        mListener.onFinishAction();
292    }
293
294    public void requestSelectionOnScreen(boolean smooth) {
295        mSelectionVisibilityRequest = smooth
296                ? SELECTION_VISIBILITY_REQUEST_SMOOTH
297                : SELECTION_VISIBILITY_REQUEST_INSTANT;
298        requestSelectionOnScreenIfNeeded();
299    }
300
301    @Override
302    protected void completeRestoreInstanceState() {
303        super.completeRestoreInstanceState();
304        requestSelectionOnScreenIfNeeded();
305    }
306
307    private void requestSelectionOnScreenIfNeeded() {
308        if (mSelectionVisibilityRequest == SELECTION_VISIBILITY_REQUEST_NONE) {
309            return;
310        }
311
312        ContactListAdapter adapter = getAdapter();
313        if (adapter == null) {
314            return;
315        }
316
317        int position = adapter.getSelectedContactPosition();
318        if (position != -1) {
319            boolean smooth = mSelectionVisibilityRequest == SELECTION_VISIBILITY_REQUEST_SMOOTH;
320            mSelectionVisibilityRequest = SELECTION_VISIBILITY_REQUEST_NONE;
321            ListView listView = getListView();
322            ListViewUtils.requestPositionToScreen(
323                    listView, position + listView.getHeaderViewsCount(), smooth);
324        }
325    }
326
327    public void saveSelectedUri(SharedPreferences preferences) {
328    }
329
330    public void restoreSelectedUri(SharedPreferences preferences) {
331    }
332}
333