/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.contacts.list; import android.app.Activity; import android.app.Fragment; import android.app.LoaderManager; import android.app.LoaderManager.LoaderCallbacks; import android.content.CursorLoader; import android.content.Loader; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.TextView; import com.android.contacts.R; import com.android.contacts.common.ContactPhotoManager; import com.android.contacts.common.ContactTileLoaderFactory; import com.android.contacts.common.list.ContactTileAdapter; import com.android.contacts.common.list.ContactTileAdapter.DisplayType; import com.android.contacts.common.list.ContactTileView; import com.android.contacts.common.util.ContactListViewUtils; import com.android.contacts.common.util.SchedulingUtils; /** * Fragment containing a list of starred contacts followed by a list of frequently contacted. * * TODO: Make this an abstract class so that the favorites, frequent, and group list functionality * can be separated out. This will make it easier to customize any of those lists if necessary * (i.e. adding header views to the ListViews in the fragment). This work was started * by creating {@link ContactTileFrequentFragment}. */ public class ContactTileListFragment extends Fragment { private static final String TAG = ContactTileListFragment.class.getSimpleName(); public interface Listener { void onContactSelected(Uri contactUri, Rect targetRect); void onCallNumberDirectly(String phoneNumber); } private Listener mListener; private ContactTileAdapter mAdapter; private DisplayType mDisplayType; private TextView mEmptyView; private ListView mListView; private boolean mOptionsMenuHasFrequents; @Override public void onAttach(Activity activity) { super.onAttach(activity); Resources res = getResources(); int columnCount = res.getInteger(R.integer.contact_tile_column_count_in_favorites); mAdapter = new ContactTileAdapter(activity, mAdapterListener, columnCount, mDisplayType); mAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity)); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflateAndSetupView(inflater, container, savedInstanceState, R.layout.contact_tile_list); } protected View inflateAndSetupView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState, int layoutResourceId) { View listLayout = inflater.inflate(layoutResourceId, container, false); mEmptyView = (TextView) listLayout.findViewById(R.id.contact_tile_list_empty); mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list); mListView.setItemsCanFocus(true); mListView.setAdapter(mAdapter); ContactListViewUtils.applyCardPaddingToView(getResources(), mListView, listLayout); return listLayout; } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (getActivity() != null && getView() != null && !hidden) { // If the padding was last applied when in a hidden state, it may have been applied // incorrectly. Therefore we need to reapply it. ContactListViewUtils.applyCardPaddingToView(getResources(), mListView, getView()); } } @Override public void onStart() { super.onStart(); // initialize the loader for this display type and destroy all others final DisplayType[] loaderTypes = mDisplayType.values(); for (int i = 0; i < loaderTypes.length; i++) { if (loaderTypes[i] == mDisplayType) { getLoaderManager().initLoader(mDisplayType.ordinal(), null, mContactTileLoaderListener); } else { getLoaderManager().destroyLoader(loaderTypes[i].ordinal()); } } } /** * Returns whether there are any frequents with the side effect of setting the * internal flag mOptionsMenuHasFrequents to the value. This should be called externally * by the activity that is about to prepare the options menu with the clear frequents * menu item. */ public boolean hasFrequents() { mOptionsMenuHasFrequents = internalHasFrequents(); return mOptionsMenuHasFrequents; } /** * Returns whether there are any frequents. */ private boolean internalHasFrequents() { return mAdapter.getNumFrequents() > 0; } public void setColumnCount(int columnCount) { mAdapter.setColumnCount(columnCount); } public void setDisplayType(DisplayType displayType) { mDisplayType = displayType; mAdapter.setDisplayType(mDisplayType); } public void enableQuickContact(boolean enableQuickContact) { mAdapter.enableQuickContact(enableQuickContact); } private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener = new LoaderCallbacks<Cursor>() { @Override public CursorLoader onCreateLoader(int id, Bundle args) { switch (mDisplayType) { case STARRED_ONLY: return ContactTileLoaderFactory.createStarredLoader(getActivity()); case STREQUENT: return ContactTileLoaderFactory.createStrequentLoader(getActivity()); case FREQUENT_ONLY: return ContactTileLoaderFactory.createFrequentLoader(getActivity()); default: throw new IllegalStateException( "Unrecognized DisplayType " + mDisplayType); } } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { if (data == null || data.isClosed()) { Log.e(TAG, "Failed to load contacts"); return; } mAdapter.setContactCursor(data); mEmptyView.setText(getEmptyStateText()); mListView.setEmptyView(mEmptyView); // invalidate the menu options if needed invalidateOptionsMenuIfNeeded(); } @Override public void onLoaderReset(Loader<Cursor> loader) {} }; private boolean isOptionsMenuChanged() { return mOptionsMenuHasFrequents != internalHasFrequents(); } private void invalidateOptionsMenuIfNeeded() { if (isOptionsMenuChanged()) { getActivity().invalidateOptionsMenu(); } } private String getEmptyStateText() { String emptyText; switch (mDisplayType) { case STREQUENT: case STARRED_ONLY: emptyText = getString(R.string.listTotalAllContactsZeroStarred); break; case FREQUENT_ONLY: case GROUP_MEMBERS: emptyText = getString(R.string.noContacts); break; default: throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType); } return emptyText; } public void setListener(Listener listener) { mListener = listener; } private ContactTileView.Listener mAdapterListener = new ContactTileView.Listener() { @Override public void onContactSelected(Uri contactUri, Rect targetRect) { if (mListener != null) { mListener.onContactSelected(contactUri, targetRect); } } @Override public void onCallNumberDirectly(String phoneNumber) { if (mListener != null) { mListener.onCallNumberDirectly(phoneNumber); } } @Override public int getApproximateTileWidth() { return getView().getWidth() / mAdapter.getColumnCount(); } }; }