Home | History | Annotate | Download | only in list
      1 /*
      2  * Copyright (C) 2011 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.app.Activity;
     19 import android.app.Fragment;
     20 import android.app.LoaderManager;
     21 import android.app.LoaderManager.LoaderCallbacks;
     22 import android.content.CursorLoader;
     23 import android.content.Loader;
     24 import android.content.res.Resources;
     25 import android.database.Cursor;
     26 import android.graphics.Rect;
     27 import android.net.Uri;
     28 import android.os.Bundle;
     29 import android.view.LayoutInflater;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.widget.ListView;
     33 import android.widget.TextView;
     34 
     35 import com.android.contacts.ContactPhotoManager;
     36 import com.android.contacts.ContactTileLoaderFactory;
     37 import com.android.contacts.R;
     38 import com.android.contacts.list.ContactTileAdapter.DisplayType;
     39 
     40 /**
     41  * Fragment containing a list of starred contacts followed by a list of frequently contacted.
     42  *
     43  * TODO: Make this an abstract class so that the favorites, frequent, and group list functionality
     44  * can be separated out. This will make it easier to customize any of those lists if necessary
     45  * (i.e. adding header views to the ListViews in the fragment). This work was started
     46  * by creating {@link ContactTileFrequentFragment}.
     47  */
     48 public class ContactTileListFragment extends Fragment {
     49     private static final String TAG = ContactTileListFragment.class.getSimpleName();
     50 
     51     public interface Listener {
     52         void onContactSelected(Uri contactUri, Rect targetRect);
     53         void onCallNumberDirectly(String phoneNumber);
     54     }
     55 
     56     private Listener mListener;
     57     private ContactTileAdapter mAdapter;
     58     private DisplayType mDisplayType;
     59     private TextView mEmptyView;
     60     private ListView mListView;
     61 
     62     private boolean mOptionsMenuHasFrequents;
     63 
     64     @Override
     65     public void onAttach(Activity activity) {
     66         super.onAttach(activity);
     67 
     68         Resources res = getResources();
     69         int columnCount = res.getInteger(R.integer.contact_tile_column_count_in_favorites);
     70 
     71         mAdapter = new ContactTileAdapter(activity, mAdapterListener,
     72                 columnCount, mDisplayType);
     73         mAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
     74     }
     75 
     76     @Override
     77     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     78             Bundle savedInstanceState) {
     79         return inflateAndSetupView(inflater, container, savedInstanceState,
     80                 R.layout.contact_tile_list);
     81     }
     82 
     83     protected View inflateAndSetupView(LayoutInflater inflater, ViewGroup container,
     84             Bundle savedInstanceState, int layoutResourceId) {
     85         View listLayout = inflater.inflate(layoutResourceId, container, false);
     86 
     87         mEmptyView = (TextView) listLayout.findViewById(R.id.contact_tile_list_empty);
     88         mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list);
     89 
     90         mListView.setItemsCanFocus(true);
     91         mListView.setAdapter(mAdapter);
     92         return listLayout;
     93     }
     94 
     95     @Override
     96     public void onStart() {
     97         super.onStart();
     98 
     99         // initialize the loader for this display type and destroy all others
    100         final DisplayType[] loaderTypes = mDisplayType.values();
    101         for (int i = 0; i < loaderTypes.length; i++) {
    102             if (loaderTypes[i] == mDisplayType) {
    103                 getLoaderManager().initLoader(mDisplayType.ordinal(), null,
    104                         mContactTileLoaderListener);
    105             } else {
    106                 getLoaderManager().destroyLoader(loaderTypes[i].ordinal());
    107             }
    108         }
    109     }
    110 
    111     /**
    112      * Returns whether there are any frequents with the side effect of setting the
    113      * internal flag mOptionsMenuHasFrequents to the value.  This should be called externally
    114      * by the activity that is about to prepare the options menu with the clear frequents
    115      * menu item.
    116      */
    117     public boolean hasFrequents() {
    118         mOptionsMenuHasFrequents = internalHasFrequents();
    119         return mOptionsMenuHasFrequents;
    120     }
    121 
    122     /**
    123      * Returns whether there are any frequents.
    124      */
    125     private boolean internalHasFrequents() {
    126         return mAdapter.getNumFrequents() > 0;
    127     }
    128 
    129     public void setColumnCount(int columnCount) {
    130         mAdapter.setColumnCount(columnCount);
    131     }
    132 
    133     public void setDisplayType(DisplayType displayType) {
    134         mDisplayType = displayType;
    135         mAdapter.setDisplayType(mDisplayType);
    136     }
    137 
    138     public void enableQuickContact(boolean enableQuickContact) {
    139         mAdapter.enableQuickContact(enableQuickContact);
    140     }
    141 
    142     private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
    143             new LoaderCallbacks<Cursor>() {
    144 
    145         @Override
    146         public CursorLoader onCreateLoader(int id, Bundle args) {
    147             switch (mDisplayType) {
    148               case STARRED_ONLY:
    149                   return ContactTileLoaderFactory.createStarredLoader(getActivity());
    150               case STREQUENT:
    151                   return ContactTileLoaderFactory.createStrequentLoader(getActivity());
    152               case STREQUENT_PHONE_ONLY:
    153                   return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
    154               case FREQUENT_ONLY:
    155                   return ContactTileLoaderFactory.createFrequentLoader(getActivity());
    156               default:
    157                   throw new IllegalStateException(
    158                       "Unrecognized DisplayType " + mDisplayType);
    159             }
    160         }
    161 
    162         @Override
    163         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    164             mAdapter.setContactCursor(data);
    165             mEmptyView.setText(getEmptyStateText());
    166             mListView.setEmptyView(mEmptyView);
    167 
    168             // invalidate the menu options if needed
    169             invalidateOptionsMenuIfNeeded();
    170         }
    171 
    172         @Override
    173         public void onLoaderReset(Loader<Cursor> loader) {}
    174     };
    175 
    176     private boolean isOptionsMenuChanged() {
    177         return mOptionsMenuHasFrequents != internalHasFrequents();
    178     }
    179 
    180     private void invalidateOptionsMenuIfNeeded() {
    181         if (isOptionsMenuChanged()) {
    182             getActivity().invalidateOptionsMenu();
    183         }
    184     }
    185 
    186     private String getEmptyStateText() {
    187         String emptyText;
    188         switch (mDisplayType) {
    189             case STREQUENT:
    190             case STREQUENT_PHONE_ONLY:
    191             case STARRED_ONLY:
    192                 emptyText = getString(R.string.listTotalAllContactsZeroStarred);
    193                 break;
    194             case FREQUENT_ONLY:
    195             case GROUP_MEMBERS:
    196                 emptyText = getString(R.string.noContacts);
    197                 break;
    198             default:
    199                 throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
    200         }
    201         return emptyText;
    202     }
    203 
    204     public void setListener(Listener listener) {
    205         mListener = listener;
    206     }
    207 
    208     private ContactTileView.Listener mAdapterListener =
    209             new ContactTileView.Listener() {
    210         @Override
    211         public void onContactSelected(Uri contactUri, Rect targetRect) {
    212             if (mListener != null) {
    213                 mListener.onContactSelected(contactUri, targetRect);
    214             }
    215         }
    216 
    217         @Override
    218         public void onCallNumberDirectly(String phoneNumber) {
    219             if (mListener != null) {
    220                 mListener.onCallNumberDirectly(phoneNumber);
    221             }
    222         }
    223 
    224         @Override
    225         public int getApproximateTileWidth() {
    226             return getView().getWidth() / mAdapter.getColumnCount();
    227         }
    228     };
    229 }
    230