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.common.list; 17 18import android.content.CursorLoader; 19import android.content.Intent; 20import android.content.Loader; 21import android.database.Cursor; 22import android.net.Uri; 23import android.os.Bundle; 24import android.text.TextUtils; 25import android.util.Log; 26import android.view.LayoutInflater; 27import android.view.MenuItem; 28import android.view.View; 29import android.view.View.OnClickListener; 30import android.view.ViewGroup; 31 32import com.android.contacts.common.R; 33import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; 34import com.android.contacts.common.util.AccountFilterUtil; 35 36/** 37 * Fragment containing a phone number list for picking. 38 */ 39public class PhoneNumberPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter> 40 implements OnShortcutIntentCreatedListener { 41 private static final String TAG = PhoneNumberPickerFragment.class.getSimpleName(); 42 43 private static final int REQUEST_CODE_ACCOUNT_FILTER = 1; 44 45 private static final String KEY_SHORTCUT_ACTION = "shortcutAction"; 46 47 private OnPhoneNumberPickerActionListener mListener; 48 private String mShortcutAction; 49 50 private ContactListFilter mFilter; 51 52 private View mAccountFilterHeader; 53 /** 54 * Lives as ListView's header and is shown when {@link #mAccountFilterHeader} is set 55 * to View.GONE. 56 */ 57 private View mPaddingView; 58 59 private static final String KEY_FILTER = "filter"; 60 61 /** true if the loader has started at least once. */ 62 private boolean mLoaderStarted; 63 64 private boolean mUseCallableUri; 65 66 private ContactListItemView.PhotoPosition mPhotoPosition = 67 ContactListItemView.getDefaultPhotoPosition(false /* normal/non opposite */); 68 69 private class FilterHeaderClickListener implements OnClickListener { 70 @Override 71 public void onClick(View view) { 72 AccountFilterUtil.startAccountFilterActivityForResult( 73 PhoneNumberPickerFragment.this, 74 REQUEST_CODE_ACCOUNT_FILTER, 75 mFilter); 76 } 77 } 78 private OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener(); 79 80 public PhoneNumberPickerFragment() { 81 setQuickContactEnabled(false); 82 setPhotoLoaderEnabled(true); 83 setSectionHeaderDisplayEnabled(true); 84 setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE); 85 86 // Show nothing instead of letting caller Activity show something. 87 setHasOptionsMenu(true); 88 } 89 90 public void setDirectorySearchEnabled(boolean flag) { 91 setDirectorySearchMode(flag ? DirectoryListLoader.SEARCH_MODE_DEFAULT 92 : DirectoryListLoader.SEARCH_MODE_NONE); 93 } 94 95 public void setOnPhoneNumberPickerActionListener(OnPhoneNumberPickerActionListener listener) { 96 this.mListener = listener; 97 } 98 99 public OnPhoneNumberPickerActionListener getOnPhoneNumberPickerListener() { 100 return mListener; 101 } 102 103 @Override 104 protected void onCreateView(LayoutInflater inflater, ViewGroup container) { 105 super.onCreateView(inflater, container); 106 107 View paddingView = inflater.inflate(R.layout.contact_detail_list_padding, null, false); 108 mPaddingView = paddingView.findViewById(R.id.contact_detail_list_padding); 109 getListView().addHeaderView(paddingView); 110 111 mAccountFilterHeader = getView().findViewById(R.id.account_filter_header_container); 112 mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener); 113 updateFilterHeaderView(); 114 115 setVisibleScrollbarEnabled(getVisibleScrollbarEnabled()); 116 } 117 118 protected boolean getVisibleScrollbarEnabled() { 119 return true; 120 } 121 122 @Override 123 protected void setSearchMode(boolean flag) { 124 super.setSearchMode(flag); 125 updateFilterHeaderView(); 126 } 127 128 private void updateFilterHeaderView() { 129 final ContactListFilter filter = getFilter(); 130 if (mAccountFilterHeader == null || filter == null) { 131 return; 132 } 133 final boolean shouldShowHeader = 134 !isSearchMode() && 135 AccountFilterUtil.updateAccountFilterTitleForPhone( 136 mAccountFilterHeader, filter, false); 137 if (shouldShowHeader) { 138 mPaddingView.setVisibility(View.GONE); 139 mAccountFilterHeader.setVisibility(View.VISIBLE); 140 } else { 141 mPaddingView.setVisibility(View.VISIBLE); 142 mAccountFilterHeader.setVisibility(View.GONE); 143 } 144 } 145 146 @Override 147 public void restoreSavedState(Bundle savedState) { 148 super.restoreSavedState(savedState); 149 150 if (savedState == null) { 151 return; 152 } 153 154 mFilter = savedState.getParcelable(KEY_FILTER); 155 mShortcutAction = savedState.getString(KEY_SHORTCUT_ACTION); 156 } 157 158 @Override 159 public void onSaveInstanceState(Bundle outState) { 160 super.onSaveInstanceState(outState); 161 outState.putParcelable(KEY_FILTER, mFilter); 162 outState.putString(KEY_SHORTCUT_ACTION, mShortcutAction); 163 } 164 165 @Override 166 public boolean onOptionsItemSelected(MenuItem item) { 167 final int itemId = item.getItemId(); 168 if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled() 169 if (mListener != null) { 170 mListener.onHomeInActionBarSelected(); 171 } 172 return true; 173 } 174 return super.onOptionsItemSelected(item); 175 } 176 177 /** 178 * @param shortcutAction either {@link Intent#ACTION_CALL} or 179 * {@link Intent#ACTION_SENDTO} or null. 180 */ 181 public void setShortcutAction(String shortcutAction) { 182 this.mShortcutAction = shortcutAction; 183 } 184 185 @Override 186 protected void onItemClick(int position, long id) { 187 final Uri phoneUri = getPhoneUri(position); 188 189 if (phoneUri != null) { 190 pickPhoneNumber(phoneUri); 191 } else { 192 final String number = getPhoneNumber(position); 193 if (!TextUtils.isEmpty(number)) { 194 cacheContactInfo(position); 195 mListener.onCallNumberDirectly(number); 196 } else { 197 Log.w(TAG, "Item at " + position + " was clicked before" 198 + " adapter is ready. Ignoring"); 199 } 200 } 201 } 202 203 protected void cacheContactInfo(int position) { 204 // Not implemented. Hook for child classes 205 } 206 207 protected String getPhoneNumber(int position) { 208 final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter(); 209 return adapter.getPhoneNumber(position); 210 } 211 212 protected Uri getPhoneUri(int position) { 213 final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter(); 214 return adapter.getDataUri(position); 215 } 216 217 @Override 218 protected void startLoading() { 219 mLoaderStarted = true; 220 super.startLoading(); 221 } 222 223 @Override 224 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 225 super.onLoadFinished(loader, data); 226 227 // disable scroll bar if there is no data 228 setVisibleScrollbarEnabled(data != null && data.getCount() > 0); 229 } 230 231 public void setUseCallableUri(boolean useCallableUri) { 232 mUseCallableUri = useCallableUri; 233 } 234 235 public boolean usesCallableUri() { 236 return mUseCallableUri; 237 } 238 239 @Override 240 protected ContactEntryListAdapter createListAdapter() { 241 PhoneNumberListAdapter adapter = new PhoneNumberListAdapter(getActivity()); 242 adapter.setDisplayPhotos(true); 243 adapter.setUseCallableUri(mUseCallableUri); 244 return adapter; 245 } 246 247 @Override 248 protected void configureAdapter() { 249 super.configureAdapter(); 250 251 final ContactEntryListAdapter adapter = getAdapter(); 252 if (adapter == null) { 253 return; 254 } 255 256 if (!isSearchMode() && mFilter != null) { 257 adapter.setFilter(mFilter); 258 } 259 260 setPhotoPosition(adapter); 261 } 262 263 protected void setPhotoPosition(ContactEntryListAdapter adapter) { 264 ((PhoneNumberListAdapter) adapter).setPhotoPosition(mPhotoPosition); 265 } 266 267 @Override 268 protected View inflateView(LayoutInflater inflater, ViewGroup container) { 269 return inflater.inflate(R.layout.contact_list_content, null); 270 } 271 272 public void pickPhoneNumber(Uri uri) { 273 if (mShortcutAction == null) { 274 mListener.onPickPhoneNumberAction(uri); 275 } else { 276 startPhoneNumberShortcutIntent(uri); 277 } 278 } 279 280 protected void startPhoneNumberShortcutIntent(Uri uri) { 281 ShortcutIntentBuilder builder = new ShortcutIntentBuilder(getActivity(), this); 282 builder.createPhoneNumberShortcutIntent(uri, mShortcutAction); 283 } 284 285 public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) { 286 mListener.onShortcutIntentCreated(shortcutIntent); 287 } 288 289 @Override 290 public void onPickerResult(Intent data) { 291 mListener.onPickPhoneNumberAction(data.getData()); 292 } 293 294 @Override 295 public void onActivityResult(int requestCode, int resultCode, Intent data) { 296 if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) { 297 if (getActivity() != null) { 298 AccountFilterUtil.handleAccountFilterResult( 299 ContactListFilterController.getInstance(getActivity()), resultCode, data); 300 } else { 301 Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()"); 302 } 303 } 304 } 305 306 public ContactListFilter getFilter() { 307 return mFilter; 308 } 309 310 public void setFilter(ContactListFilter filter) { 311 if ((mFilter == null && filter == null) || 312 (mFilter != null && mFilter.equals(filter))) { 313 return; 314 } 315 316 mFilter = filter; 317 if (mLoaderStarted) { 318 reloadData(); 319 } 320 updateFilterHeaderView(); 321 } 322 323 public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) { 324 mPhotoPosition = photoPosition; 325 326 final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter(); 327 if (adapter != null) { 328 adapter.setPhotoPosition(photoPosition); 329 } 330 } 331} 332