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