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