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