SpeedDialFragment.java revision 4911300ae3fa7ab186ee271f8bc431b65a819a3c
16b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee/*
2dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Copyright (C) 2013 The Android Open Source Project
36b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee *
46b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
56b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * you may not use this file except in compliance with the License.
66b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * You may obtain a copy of the License at
76b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee *
86b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
96b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee *
106b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * Unless required by applicable law or agreed to in writing, software
116b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
126b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * See the License for the specific language governing permissions and
146b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * limitations under the License.
156b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee */
166b049128c51b90e17ae14856d98130a22d3a5433Yorke Leepackage com.android.dialer.list;
176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
186b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.Activity;
196b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.Fragment;
206b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.LoaderManager;
216b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.content.CursorLoader;
226b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.content.Loader;
236b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.database.Cursor;
246b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.graphics.Rect;
256b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.net.Uri;
266b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.os.Bundle;
276b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.util.Log;
286b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.LayoutInflater;
296b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.View;
30c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport android.view.ViewTreeObserver;
316b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.View.OnClickListener;
326b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.ViewGroup;
336b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AbsListView;
346b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AdapterView;
356b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AdapterView.OnItemClickListener;
364911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wangimport android.widget.ImageView;
376b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.ListView;
386b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.TextView;
396b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
406b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.ContactPhotoManager;
416b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.ContactTileLoaderFactory;
42dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.GeoUtil;
43c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport com.android.contacts.common.list.ContactEntry;
446b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.list.ContactTileView;
456b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.dialer.R;
46dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.dialer.calllog.ContactInfoHelper;
47fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Leeimport com.android.dialer.calllog.CallLogAdapter;
48dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.dialer.calllog.CallLogQueryHandler;
49c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow;
50704acc087ce359295475a46695c2821c55778344Chiao Chengimport com.android.dialerbind.ObjectFactory;
51c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
52c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport java.util.ArrayList;
53c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport java.util.HashMap;
546b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
556b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee/**
566b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * Fragment for Phone UI's favorite screen.
576b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee *
586b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * This fragment contains three kinds of contacts in one screen: "starred", "frequent", and "all"
596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * contacts. To show them at once, this merges results from {@link com.android.contacts.common.list.ContactTileAdapter} and
606b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * {@link com.android.contacts.common.list.PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}.
616b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * A contact filter header is also inserted between those adapters' results.
626b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee */
638898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Leepublic class PhoneFavoriteFragment extends Fragment implements OnItemClickListener,
64c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher,
65c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener {
66c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
678898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Lee    private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
68c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private static final boolean DEBUG = true;
69c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
704911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang    private int mAnimationDuration;
716b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
726b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
736b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * Used with LoaderManager.
746b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
756b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private static int LOADER_ID_CONTACT_TILE = 1;
766b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
778dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee    public interface OnShowAllContactsListener {
788dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        public void onShowAllContacts();
798dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee    }
808dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee
816b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public interface Listener {
826b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onContactSelected(Uri contactUri);
836b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onCallNumberDirectly(String phoneNumber);
846b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
856b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
866b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
876b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
886b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public CursorLoader onCreateLoader(int id, Bundle args) {
896b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onCreateLoader.");
906b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
916b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
926b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
936b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
956b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoadFinished");
966b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            mContactTileAdapter.setContactCursor(data);
976b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
986b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
996b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1006b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onLoaderReset(Loader<Cursor> loader) {
1016b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoaderReset. ");
1026b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1036b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1046b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1056b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ContactTileAdapterListener implements ContactTileView.Listener {
1066b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1076b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onContactSelected(Uri contactUri, Rect targetRect) {
1086b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (mListener != null) {
1096b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                mListener.onContactSelected(contactUri);
1106b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            }
1116b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1126b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1146b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onCallNumberDirectly(String phoneNumber) {
1156b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (mListener != null) {
1166b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                mListener.onCallNumberDirectly(phoneNumber);
1176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            }
1186b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1196b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1206b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1216b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public int getApproximateTileWidth() {
1226b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            return getView().getWidth() / mContactTileAdapter.getColumnCount();
1236b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1246b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1256b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1266b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ScrollListener implements ListView.OnScrollListener {
1276b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1286b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onScroll(AbsListView view,
1296b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                int firstVisibleItem, int visibleItemCount, int totalItemCount) {
1306b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1316b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1326b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1336b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onScrollStateChanged(AbsListView view, int scrollState) {
134dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
1356b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1366b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1376b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1386b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private Listener mListener;
139dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
140dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private OnListFragmentScrolledListener mActivityScrollListener;
1418dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee    private OnShowAllContactsListener mShowAllContactsListener;
1428898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Lee    private PhoneFavoriteMergedAdapter mAdapter;
143dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private PhoneFavoritesTileAdapter mContactTileAdapter;
1446b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
145fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    private CallLogAdapter mCallLogAdapter;
146dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private CallLogQueryHandler mCallLogQueryHandler;
147dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
148bf5b298b1a5752a56315131a22434185198370a8Hongwei Wang    private PhoneFavoriteListView mListView;
14918e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee
1506091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen    private View mShowAllContactsButton;
1516b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
152c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private final HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
153c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private final HashMap<Long, Integer> mItemIdLeftMap = new HashMap<Long, Integer>();
154c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
1556b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
15618e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee     * Layout used when there are no favorites.
1576b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
15818e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee    private View mEmptyView;
1596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1606b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final ContactTileView.Listener mContactTileAdapterListener =
1616b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            new ContactTileAdapterListener();
1626b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
1636b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            new ContactTileLoaderListener();
1646b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final ScrollListener mScrollListener = new ScrollListener();
1656b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1666b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
1676b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onAttach(Activity activity) {
1686b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (DEBUG) Log.d(TAG, "onAttach()");
1696b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onAttach(activity);
1706b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1716b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // Construct two base adapters which will become part of PhoneFavoriteMergedAdapter.
1726b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // We don't construct the resultant adapter at this moment since it requires LayoutInflater
1736b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // that will be available on onCreateView().
174dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mContactTileAdapter = new PhoneFavoritesTileAdapter(activity, mContactTileAdapterListener,
175c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                this,
176dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                getResources().getInteger(R.integer.contact_tile_column_count_in_favorites_new),
177dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                1);
1786b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
1796b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1806b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1816b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
1826b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onCreate(Bundle savedState) {
1836b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (DEBUG) Log.d(TAG, "onCreate()");
1846b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onCreate(savedState);
1856b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1864911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        mAnimationDuration = getResources().getInteger(R.integer.fade_duration);
187dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
188dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                this, 1);
189dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
190704acc087ce359295475a46695c2821c55778344Chiao Cheng        mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
191704acc087ce359295475a46695c2821c55778344Chiao Cheng                new ContactInfoHelper(getActivity(), currentCountryIso), true, false);
1926b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        setHasOptionsMenu(true);
1936b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1956b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
196dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onResume() {
197dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        super.onResume();
1984dc32bdf10bff18acbc1964d289354556950d2ebYorke Lee        fetchCalls();
199dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogAdapter.setLoading(true);
20011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad();
2016b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2026b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2036b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2046b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public View onCreateView(LayoutInflater inflater, ViewGroup container,
2056b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            Bundle savedInstanceState) {
2066b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        final View listLayout = inflater.inflate(
2078898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Lee                R.layout.phone_favorites_fragment, container, false);
2086b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
209bf5b298b1a5752a56315131a22434185198370a8Hongwei Wang        mListView = (PhoneFavoriteListView) listLayout.findViewById(R.id.contact_tile_list);
2106b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setItemsCanFocus(true);
2116b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setOnItemClickListener(this);
2126b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setVerticalScrollBarEnabled(false);
2136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
2146b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
21511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        mListView.setOnItemSwipeListener(mContactTileAdapter);
2167639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang        mListView.setOnDragDropListener(mContactTileAdapter);
2176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2184911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        final ImageView dragShadowOverlay =
2194911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                (ImageView) listLayout.findViewById(R.id.contact_tile_drag_shadow_overlay);
2204911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        mListView.setDragShadowOverlay(dragShadowOverlay);
2214911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang
22218e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee        mEmptyView = inflater.inflate(R.layout.phone_no_favorites, mListView, false);
22318e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee
2246091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        mShowAllContactsButton = inflater.inflate(R.layout.show_all_contact_button, mListView,
2256091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen                false);
2266091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        mShowAllContactsButton.setOnClickListener(new OnClickListener() {
2276091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen            @Override
2286091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen            public void onClick(View view) {
2296091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen                showAllContacts();
2306091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen            }
2316091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        });
2326b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
23318e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee        mContactTileAdapter.setEmptyView(mEmptyView);
2348898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Lee        mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), mContactTileAdapter,
23518e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee                mCallLogAdapter, mShowAllContactsButton);
2366b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2376b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setAdapter(mAdapter);
2386b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2396b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setOnScrollListener(mScrollListener);
2406b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setFastScrollEnabled(false);
2416b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setFastScrollAlwaysVisible(false);
2426b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2436b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        return listLayout;
2446b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2456b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
246f420a5344995b2c450379159f679809690bc9880Yorke Lee    public boolean hasFrequents() {
247f420a5344995b2c450379159f679809690bc9880Yorke Lee        if (mContactTileAdapter == null) return false;
2486b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        return mContactTileAdapter.getNumFrequents() > 0;
2496b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2506b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2516b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2526b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onStart() {
2536b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onStart();
2546b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
255dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final Activity activity = getActivity();
256dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
257dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        try {
258dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
259dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } catch (ClassCastException e) {
260dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            throw new ClassCastException(activity.toString()
261dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    + " must implement OnListFragmentScrolledListener");
262dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
2636b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2648dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        try {
2658dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee            mShowAllContactsListener = (OnShowAllContactsListener) activity;
2668dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        } catch (ClassCastException e) {
2678dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee            throw new ClassCastException(activity.toString()
2688dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee                    + " must implement OnShowAllContactsListener");
2698dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        }
2708dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee
2716b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // Use initLoader() instead of restartLoader() to refraining unnecessary reload.
2726b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
2736b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // be called, on which we'll check if "all" contacts should be reloaded again or not.
2746b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener);
2756b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2766b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2776b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
2786b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * {@inheritDoc}
2796b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     *
2806b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * This is only effective for elements provided by {@link #mContactTileAdapter}.
2816b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * {@link #mContactTileAdapter} has its own logic for click events.
2826b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
2836b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2846b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
2856b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        final int contactTileAdapterCount = mContactTileAdapter.getCount();
2866b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (position <= contactTileAdapterCount) {
2876b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            Log.e(TAG, "onItemClick() event for unexpected position. "
2886b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                    + "The position " + position + " is before \"all\" section. Ignored.");
2896b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
2906b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2916b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2926b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
2936091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen     * Gets called when user click on the show all contacts button.
2946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
2956091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen    private void showAllContacts() {
2968dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        mShowAllContactsListener.onShowAllContacts();
2976b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2986b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
299dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setListener(Listener listener) {
300dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mListener = listener;
3016b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3026b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
303dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
304dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onVoicemailStatusFetched(Cursor statusCursor) {
3054dc32bdf10bff18acbc1964d289354556950d2ebYorke Lee        // no-op
3066b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3076b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
308dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
309dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onCallsFetched(Cursor cursor) {
310dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogAdapter.setLoading(false);
311dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogAdapter.changeCursor(cursor);
312dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mAdapter.notifyDataSetChanged();
3136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3146b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
315dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
316dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void fetchCalls() {
3174dc32bdf10bff18acbc1964d289354556950d2ebYorke Lee        mCallLogQueryHandler.fetchNewCalls(CallLogQueryHandler.CALL_TYPE_ALL);
3186b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
31911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee
32011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee    @Override
32111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee    public void onPause() {
32211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        // If there are any pending contact entries that are to be removed, remove them
32311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        mContactTileAdapter.removePendingContactEntry();
32411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        super.onPause();
32511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee    }
326c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
327c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /**
328c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * Saves the current view offsets into memory
329c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
330c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @SuppressWarnings("unchecked")
331c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void saveOffsets(long... idsInPlace) {
332c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        final int firstVisiblePosition = mListView.getFirstVisiblePosition();
333c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        if (DEBUG) {
334c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            Log.d(TAG, "Child count : " + mListView.getChildCount());
335c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
336c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < mListView.getChildCount(); i++) {
337c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = mListView.getChildAt(i);
338c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final int position = firstVisiblePosition + i;
339c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final long itemId = mAdapter.getItemId(position);
340c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final int itemViewType = mAdapter.getItemViewType(position);
341c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (itemViewType == PhoneFavoritesTileAdapter.ViewTypes.TOP) {
342c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                // This is a tiled row, so save horizontal offsets instead
343c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                saveHorizontalOffsets((ContactTileRow) child, (ArrayList<ContactEntry>)
344c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        mAdapter.getItem(position), idsInPlace);
345c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
346c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (DEBUG) {
347c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                Log.d(TAG, "Saving itemId: " + itemId + " for listview child " + i + " Top: "
348c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        + child.getTop());
349c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
350c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            mItemIdTopMap.put(itemId, child.getTop());
351c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
352c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
353c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
354c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void saveHorizontalOffsets(ContactTileRow row, ArrayList<ContactEntry> list,
355c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            long... idsInPlace) {
356c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < list.size(); i++) {
357c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = row.getChildAt(i);
358c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final ContactEntry entry = list.get(i);
359c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final long itemId = mContactTileAdapter.getAdjustedItemId(entry.id);
360c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (DEBUG) {
361c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                Log.d(TAG, "Saving itemId: " + itemId + " for tileview child " + i + " Left: "
362c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        + child.getTop());
363c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
364c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            mItemIdLeftMap.put(itemId, child.getLeft());
365c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
366c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
367c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
368c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /*
369c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * Performs a animations for a row of tiles
370c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
371c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void performHorizontalAnimations(ContactTileRow row, ArrayList<ContactEntry> list,
372c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            long[] idsInPlace) {
373c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        if (mItemIdLeftMap.isEmpty()) {
374c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            return;
375c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
376c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < list.size(); i++) {
377c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = row.getChildAt(i);
378c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final ContactEntry entry = list.get(i);
379c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final long itemId = mContactTileAdapter.getAdjustedItemId(entry.id);
380c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
3814911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang            if (containsId(idsInPlace, itemId)) {
3824911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                child.setAlpha(0.0f);
3834911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                child.animate().alpha(1.0f)
3844911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                        .setDuration(mAnimationDuration)
3854911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                        .start();
3864911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                break;
387c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
388c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
389c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
390c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
391c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /*
392c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * Performs animations for the list view. If the list item is a row of tiles, horizontal
393c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * animations will be performed instead.
394c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
395c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void animateListView(final long... idsInPlace) {
396c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        if (mItemIdTopMap.isEmpty()) {
397c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // Don't do animations if the database is being queried for the first time and
398c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // the previous item offsets have not been cached, or the user hasn't done anything
399c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // (dragging, swiping etc) that requires an animation.
400c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            return;
401c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
402c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        final ViewTreeObserver observer = mListView.getViewTreeObserver();
403c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
404c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            @SuppressWarnings("unchecked")
405c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            @Override
406c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            public boolean onPreDraw() {
407c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                observer.removeOnPreDrawListener(this);
408c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                final int firstVisiblePosition = mListView.getFirstVisiblePosition();
409c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                for (int i = 0; i < mListView.getChildCount(); i++) {
410c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final View child = mListView.getChildAt(i);
411c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    int position = firstVisiblePosition + i;
412c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final int itemViewType = mAdapter.getItemViewType(position);
413c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    if (itemViewType == PhoneFavoritesTileAdapter.ViewTypes.TOP) {
414c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        // This is a tiled row, so perform horizontal animations instead
415c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        performHorizontalAnimations((ContactTileRow) child, (
416c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                                ArrayList<ContactEntry>) mAdapter.getItem(position), idsInPlace);
417c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    }
418c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
419c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final long itemId = mAdapter.getItemId(position);
420c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
4214911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                    if (containsId(idsInPlace, itemId)) {
4224911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                        child.setAlpha(0.0f);
4234911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                        child.animate().alpha(1.0f)
4244911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                                .setDuration(mAnimationDuration)
4254911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                                .start();
4264911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                        break;
427c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    }
428c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                }
429c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                mItemIdTopMap.clear();
430c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                mItemIdLeftMap.clear();
431c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                return true;
432c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
433c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        });
434c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
435c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
436c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private boolean containsId(long[] ids, long target) {
437c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        // Linear search on array is fine because this is typically only 0-1 elements long
438c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < ids.length; i++) {
439c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (ids[i] == target) {
440c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                return true;
441c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
442c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
443c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        return false;
444c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
445c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
446c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @Override
447c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    public void onDataSetChangedForAnimation(long... idsInPlace) {
448c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        animateListView(idsInPlace);
449c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
450c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
451c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @Override
452c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    public void cacheOffsetsForDatasetChange() {
453c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        saveOffsets();
454c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
4556b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee}
456