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 */ 16 package com.android.contacts.list; 17 18 import android.content.Context; 19 import android.content.CursorLoader; 20 import android.content.Intent; 21 import android.net.Uri; 22 import android.provider.ContactsContract.Contacts; 23 import android.text.TextUtils; 24 import android.util.Log; 25 import android.view.LayoutInflater; 26 import android.view.View; 27 import android.view.View.OnClickListener; 28 import android.view.ViewGroup; 29 import android.view.accessibility.AccessibilityEvent; 30 import android.widget.Button; 31 import android.widget.FrameLayout; 32 import android.widget.ListView; 33 import android.widget.TextView; 34 35 import com.android.contacts.R; 36 import com.android.contacts.common.list.ContactListAdapter; 37 import com.android.contacts.common.list.ContactListFilter; 38 import com.android.contacts.common.list.ContactListFilterController; 39 import com.android.contacts.common.list.ContactListItemView; 40 import com.android.contacts.common.list.DefaultContactListAdapter; 41 import com.android.contacts.common.list.ProfileAndContactsLoader; 42 import com.android.contacts.common.util.ImplicitIntentsUtil; 43 import com.android.contacts.editor.ContactEditorFragment; 44 import com.android.contacts.common.util.AccountFilterUtil; 45 46 /** 47 * Fragment containing a contact list used for browsing (as compared to 48 * picking a contact with one of the PICK intents). 49 */ 50 public class DefaultContactBrowseListFragment extends ContactBrowseListFragment { 51 private static final String TAG = DefaultContactBrowseListFragment.class.getSimpleName(); 52 53 private static final int REQUEST_CODE_ACCOUNT_FILTER = 1; 54 55 private View mSearchHeaderView; 56 private View mAccountFilterHeader; 57 private FrameLayout mProfileHeaderContainer; 58 private View mProfileHeader; 59 private Button mProfileMessage; 60 private TextView mProfileTitle; 61 private View mSearchProgress; 62 private TextView mSearchProgressText; 63 64 private class FilterHeaderClickListener implements OnClickListener { 65 @Override onClick(View view)66 public void onClick(View view) { 67 AccountFilterUtil.startAccountFilterActivityForResult( 68 DefaultContactBrowseListFragment.this, 69 REQUEST_CODE_ACCOUNT_FILTER, 70 getFilter()); 71 } 72 } 73 private OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener(); 74 DefaultContactBrowseListFragment()75 public DefaultContactBrowseListFragment() { 76 setPhotoLoaderEnabled(true); 77 // Don't use a QuickContactBadge. Just use a regular ImageView. Using a QuickContactBadge 78 // inside the ListView prevents us from using MODE_FULLY_EXPANDED and messes up ripples. 79 setQuickContactEnabled(false); 80 setSectionHeaderDisplayEnabled(true); 81 setVisibleScrollbarEnabled(true); 82 } 83 84 @Override createCursorLoader(Context context)85 public CursorLoader createCursorLoader(Context context) { 86 return new ProfileAndContactsLoader(context); 87 } 88 89 @Override onItemClick(int position, long id)90 protected void onItemClick(int position, long id) { 91 final Uri uri = getAdapter().getContactUri(position); 92 if (uri == null) { 93 return; 94 } 95 viewContact(uri); 96 } 97 98 @Override createListAdapter()99 protected ContactListAdapter createListAdapter() { 100 DefaultContactListAdapter adapter = new DefaultContactListAdapter(getContext()); 101 adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled()); 102 adapter.setDisplayPhotos(true); 103 adapter.setPhotoPosition( 104 ContactListItemView.getDefaultPhotoPosition(/* opposite = */ false)); 105 return adapter; 106 } 107 108 @Override inflateView(LayoutInflater inflater, ViewGroup container)109 protected View inflateView(LayoutInflater inflater, ViewGroup container) { 110 return inflater.inflate(R.layout.contact_list_content, null); 111 } 112 113 @Override onCreateView(LayoutInflater inflater, ViewGroup container)114 protected void onCreateView(LayoutInflater inflater, ViewGroup container) { 115 super.onCreateView(inflater, container); 116 117 mAccountFilterHeader = getView().findViewById(R.id.account_filter_header_container); 118 mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener); 119 120 // Create an empty user profile header and hide it for now (it will be visible if the 121 // contacts list will have no user profile). 122 addEmptyUserProfileHeader(inflater); 123 showEmptyUserProfile(false); 124 125 // Putting the header view inside a container will allow us to make 126 // it invisible later. See checkHeaderViewVisibility() 127 FrameLayout headerContainer = new FrameLayout(inflater.getContext()); 128 mSearchHeaderView = inflater.inflate(R.layout.search_header, null, false); 129 headerContainer.addView(mSearchHeaderView); 130 getListView().addHeaderView(headerContainer, null, false); 131 checkHeaderViewVisibility(); 132 133 mSearchProgress = getView().findViewById(R.id.search_progress); 134 mSearchProgressText = (TextView) mSearchHeaderView.findViewById(R.id.totalContactsText); 135 } 136 137 @Override setSearchMode(boolean flag)138 protected void setSearchMode(boolean flag) { 139 super.setSearchMode(flag); 140 checkHeaderViewVisibility(); 141 if (!flag) showSearchProgress(false); 142 } 143 144 /** Show or hide the directory-search progress spinner. */ showSearchProgress(boolean show)145 private void showSearchProgress(boolean show) { 146 if (mSearchProgress != null) { 147 mSearchProgress.setVisibility(show ? View.VISIBLE : View.GONE); 148 } 149 } 150 checkHeaderViewVisibility()151 private void checkHeaderViewVisibility() { 152 updateFilterHeaderView(); 153 154 // Hide the search header by default. 155 if (mSearchHeaderView != null) { 156 mSearchHeaderView.setVisibility(View.GONE); 157 } 158 } 159 160 @Override setFilter(ContactListFilter filter)161 public void setFilter(ContactListFilter filter) { 162 super.setFilter(filter); 163 updateFilterHeaderView(); 164 } 165 updateFilterHeaderView()166 private void updateFilterHeaderView() { 167 if (mAccountFilterHeader == null) { 168 return; // Before onCreateView -- just ignore it. 169 } 170 final ContactListFilter filter = getFilter(); 171 if (filter != null && !isSearchMode()) { 172 final boolean shouldShowHeader = AccountFilterUtil.updateAccountFilterTitleForPeople( 173 mAccountFilterHeader, filter, false); 174 mAccountFilterHeader.setVisibility(shouldShowHeader ? View.VISIBLE : View.GONE); 175 } else { 176 mAccountFilterHeader.setVisibility(View.GONE); 177 } 178 } 179 180 @Override setProfileHeader()181 protected void setProfileHeader() { 182 mUserProfileExists = getAdapter().hasProfile(); 183 showEmptyUserProfile(!mUserProfileExists && !isSearchMode()); 184 185 if (isSearchMode()) { 186 ContactListAdapter adapter = getAdapter(); 187 if (adapter == null) { 188 return; 189 } 190 191 // In search mode we only display the header if there is nothing found 192 if (TextUtils.isEmpty(getQueryString()) || !adapter.areAllPartitionsEmpty()) { 193 mSearchHeaderView.setVisibility(View.GONE); 194 showSearchProgress(false); 195 } else { 196 mSearchHeaderView.setVisibility(View.VISIBLE); 197 if (adapter.isLoading()) { 198 mSearchProgressText.setText(R.string.search_results_searching); 199 showSearchProgress(true); 200 } else { 201 mSearchProgressText.setText(R.string.listFoundAllContactsZero); 202 mSearchProgressText.sendAccessibilityEvent( 203 AccessibilityEvent.TYPE_VIEW_SELECTED); 204 showSearchProgress(false); 205 } 206 } 207 showEmptyUserProfile(false); 208 } 209 } 210 211 @Override onActivityResult(int requestCode, int resultCode, Intent data)212 public void onActivityResult(int requestCode, int resultCode, Intent data) { 213 if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) { 214 if (getActivity() != null) { 215 AccountFilterUtil.handleAccountFilterResult( 216 ContactListFilterController.getInstance(getActivity()), resultCode, data); 217 } else { 218 Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()"); 219 } 220 } 221 } 222 showEmptyUserProfile(boolean show)223 private void showEmptyUserProfile(boolean show) { 224 // Changing visibility of just the mProfileHeader doesn't do anything unless 225 // you change visibility of its children, hence the call to mCounterHeaderView 226 // and mProfileTitle 227 mProfileHeaderContainer.setVisibility(show ? View.VISIBLE : View.GONE); 228 mProfileHeader.setVisibility(show ? View.VISIBLE : View.GONE); 229 mProfileTitle.setVisibility(show ? View.VISIBLE : View.GONE); 230 mProfileMessage.setVisibility(show ? View.VISIBLE : View.GONE); 231 } 232 233 /** 234 * This method creates a pseudo user profile contact. When the returned query doesn't have 235 * a profile, this methods creates 2 views that are inserted as headers to the listview: 236 * 1. A header view with the "ME" title and the contacts count. 237 * 2. A button that prompts the user to create a local profile 238 */ addEmptyUserProfileHeader(LayoutInflater inflater)239 private void addEmptyUserProfileHeader(LayoutInflater inflater) { 240 ListView list = getListView(); 241 // Add a header with the "ME" name. The view is embedded in a frame view since you cannot 242 // change the visibility of a view in a ListView without having a parent view. 243 mProfileHeader = inflater.inflate(R.layout.user_profile_header, null, false); 244 mProfileTitle = (TextView) mProfileHeader.findViewById(R.id.profile_title); 245 mProfileHeaderContainer = new FrameLayout(inflater.getContext()); 246 mProfileHeaderContainer.addView(mProfileHeader); 247 list.addHeaderView(mProfileHeaderContainer, null, false); 248 249 // Add a button with a message inviting the user to create a local profile 250 mProfileMessage = (Button) mProfileHeader.findViewById(R.id.user_profile_button); 251 mProfileMessage.setOnClickListener(new View.OnClickListener() { 252 public void onClick(View v) { 253 Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); 254 intent.putExtra(ContactEditorFragment.INTENT_EXTRA_NEW_LOCAL_PROFILE, true); 255 ImplicitIntentsUtil.startActivityInApp(getActivity(), intent); 256 } 257 }); 258 } 259 } 260