ContactBrowseListFragment.java revision e20d3432a370dd3996deec2df4e3cdf726c94992
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.database.Cursor;
25import android.net.Uri;
26import android.os.Bundle;
27import android.provider.ContactsContract;
28import android.provider.ContactsContract.Contacts;
29import android.provider.ContactsContract.Directory;
30import android.text.TextUtils;
31import android.widget.ListView;
32
33/**
34 * Fragment containing a contact list used for browsing (as compared to
35 * picking a contact with one of the PICK intents).
36 */
37public abstract class ContactBrowseListFragment extends
38        ContactEntryListFragment<ContactListAdapter> {
39
40    private static final String KEY_SELECTED_URI = "selectedUri";
41
42    private static final int SELECTED_ID_LOADER = -3;
43
44    private static final int SELECTION_VISIBILITY_REQUEST_NONE = 0;
45    private static final int SELECTION_VISIBILITY_REQUEST_SMOOTH = 1;
46    private static final int SELECTION_VISIBILITY_REQUEST_INSTANT = 2;
47
48    private Uri mSelectedContactUri;
49    private long mSelectedContactDirectoryId;
50    private String mSelectedContactLookupKey;
51    private int mSelectionVisibilityRequest;
52
53    private OnContactBrowserActionListener mListener;
54
55    private LoaderCallbacks<Cursor> mIdLoaderCallbacks = new LoaderCallbacks<Cursor>() {
56
57        @Override
58        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
59            return new CursorLoader(getContext(),
60                    mSelectedContactUri,
61                    new String[] { Contacts.LOOKUP_KEY },
62                    null,
63                    null,
64                    null);
65        }
66
67        @Override
68        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
69            String lookupKey = null;
70            if (data != null) {
71                if (data.moveToFirst()) {
72                    lookupKey = data.getString(0);
73                }
74            }
75            if (!TextUtils.equals(mSelectedContactLookupKey, lookupKey)) {
76                mSelectedContactLookupKey = lookupKey;
77                configureContactSelection();
78            }
79            return;
80        }
81    };
82
83    @Override
84    public void restoreSavedState(Bundle savedState) {
85        super.restoreSavedState(savedState);
86
87        if (savedState == null) {
88            return;
89        }
90
91        mSelectedContactUri = savedState.getParcelable(KEY_SELECTED_URI);
92        parseSelectedContactUri();
93    }
94
95    @Override
96    public void onSaveInstanceState(Bundle outState) {
97        super.onSaveInstanceState(outState);
98        outState.putParcelable(KEY_SELECTED_URI, mSelectedContactUri);
99    }
100
101    @Override
102    public void onStart() {
103        // Refresh the currently selected lookup in case it changed while we were sleeping
104        startLoadingContactLookupKey();
105        super.onStart();
106   }
107
108    protected void startLoadingContactLookupKey() {
109        if (isSelectionVisible() && mSelectedContactUri != null &&
110                (mSelectedContactDirectoryId == Directory.DEFAULT ||
111                        mSelectedContactDirectoryId == Directory.LOCAL_INVISIBLE)) {
112            getLoaderManager().restartLoader(SELECTED_ID_LOADER, null, mIdLoaderCallbacks);
113        } else {
114            getLoaderManager().stopLoader(SELECTED_ID_LOADER);
115        }
116    }
117
118    @Override
119    protected void prepareEmptyView() {
120        if (isSearchMode()) {
121            return;
122        } else if (isSyncActive()) {
123            if (hasIccCard()) {
124                setEmptyText(R.string.noContactsHelpTextWithSync);
125            } else {
126                setEmptyText(R.string.noContactsNoSimHelpTextWithSync);
127            }
128        } else {
129            if (hasIccCard()) {
130                setEmptyText(R.string.noContactsHelpText);
131            } else {
132                setEmptyText(R.string.noContactsNoSimHelpText);
133            }
134        }
135    }
136
137    public Uri getSelectedContactUri() {
138        return mSelectedContactUri;
139    }
140
141    public void setSelectedContactUri(Uri uri) {
142        if (mSelectedContactUri == null
143                || (mSelectedContactUri != null && !mSelectedContactUri.equals(uri))) {
144            mSelectedContactUri = uri;
145
146            parseSelectedContactUri();
147
148            if (isAdded()) {
149                // Configure the adapter to show the selection based on the lookup key extracted
150                // from the URI
151                configureAdapter();
152
153                // Also, launch a loader to pick up a new lookup key in case it has changed
154                startLoadingContactLookupKey();
155            }
156        }
157    }
158
159    private void parseSelectedContactUri() {
160        if (mSelectedContactUri != null) {
161            if (!mSelectedContactUri.toString()
162                    .startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
163                throw new IllegalStateException(
164                        "Contact list contains a non-lookup URI: " + mSelectedContactUri);
165            }
166
167            String directoryParam =
168                mSelectedContactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
169            mSelectedContactDirectoryId = TextUtils.isEmpty(directoryParam)
170                    ? Directory.DEFAULT
171                    : Long.parseLong(directoryParam);
172            mSelectedContactLookupKey =
173                    Uri.encode(mSelectedContactUri.getPathSegments().get(2));
174        } else {
175            mSelectedContactDirectoryId = Directory.DEFAULT;
176            mSelectedContactLookupKey = null;
177        }
178    }
179
180    @Override
181    protected void configureAdapter() {
182        super.configureAdapter();
183        configureContactSelection();
184    }
185
186    /**
187     * Configures the adapter with the identity of the currently selected contact.
188     */
189    private void configureContactSelection() {
190        ContactListAdapter adapter = getAdapter();
191        if (adapter == null) {
192            return;
193        }
194
195        adapter.setSelectedContact(mSelectedContactDirectoryId, mSelectedContactLookupKey);
196    }
197
198    public void setOnContactListActionListener(OnContactBrowserActionListener listener) {
199        mListener = listener;
200    }
201
202    public void createNewContact() {
203        mListener.onCreateNewContactAction();
204    }
205
206    public void viewContact(Uri contactUri) {
207        mListener.onViewContactAction(contactUri);
208    }
209
210    public void editContact(Uri contactUri) {
211        mListener.onEditContactAction(contactUri);
212    }
213
214    public void deleteContact(Uri contactUri) {
215        mListener.onDeleteContactAction(contactUri);
216    }
217
218    public void addToFavorites(Uri contactUri) {
219        mListener.onAddToFavoritesAction(contactUri);
220    }
221
222    public void removeFromFavorites(Uri contactUri) {
223        mListener.onRemoveFromFavoritesAction(contactUri);
224    }
225
226    public void callContact(Uri contactUri) {
227        mListener.onCallContactAction(contactUri);
228    }
229
230    public void smsContact(Uri contactUri) {
231        mListener.onSmsContactAction(contactUri);
232    }
233
234    @Override
235    protected void finish() {
236        super.finish();
237        mListener.onFinishAction();
238    }
239
240    public void requestSelectionOnScreen(boolean smooth) {
241        mSelectionVisibilityRequest = smooth
242                ? SELECTION_VISIBILITY_REQUEST_SMOOTH
243                : SELECTION_VISIBILITY_REQUEST_INSTANT;
244        requestSelectionOnScreenIfNeeded();
245    }
246
247    @Override
248    protected void completeRestoreInstanceState() {
249        super.completeRestoreInstanceState();
250        requestSelectionOnScreenIfNeeded();
251    }
252
253    private void requestSelectionOnScreenIfNeeded() {
254        if (mSelectionVisibilityRequest == SELECTION_VISIBILITY_REQUEST_NONE) {
255            return;
256        }
257
258        ContactListAdapter adapter = getAdapter();
259        if (adapter == null) {
260            return;
261        }
262
263        int position = adapter.getSelectedContactPosition();
264        if (position != -1) {
265            boolean smooth = mSelectionVisibilityRequest == SELECTION_VISIBILITY_REQUEST_SMOOTH;
266            mSelectionVisibilityRequest = SELECTION_VISIBILITY_REQUEST_NONE;
267            ListView listView = getListView();
268            ListViewUtils.requestPositionToScreen(
269                    listView, position + listView.getHeaderViewsCount(), smooth);
270        }
271    }
272}
273