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