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