SpeedDialFragment.java revision 3ed80a357d780310777178ad589d7771d4f7bf2d
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
185b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wangimport android.animation.Animator;
195b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wangimport android.animation.AnimatorSet;
204fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chenimport android.animation.ArgbEvaluator;
215b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wangimport android.animation.ObjectAnimator;
224fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chenimport android.animation.ValueAnimator;
236b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.Activity;
246b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.Fragment;
256b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.LoaderManager;
2621299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Leeimport android.content.Context;
276b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.content.CursorLoader;
286b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.content.Loader;
2921299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Leeimport android.content.SharedPreferences;
306b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.database.Cursor;
316b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.graphics.Rect;
326b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.net.Uri;
336b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.os.Bundle;
34c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.provider.CallLog;
356b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.util.Log;
366b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.LayoutInflater;
376b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.View;
38c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport android.view.ViewTreeObserver;
396b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.View.OnClickListener;
406b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.ViewGroup;
416b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AbsListView;
426b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AdapterView;
436b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AdapterView.OnItemClickListener;
444911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wangimport android.widget.ImageView;
456b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.ListView;
466b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
476b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.ContactPhotoManager;
486b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.ContactTileLoaderFactory;
49dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.GeoUtil;
50c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport com.android.contacts.common.list.ContactEntry;
516b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.list.ContactTileView;
5221299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Leeimport com.android.dialer.DialtactsActivity;
536b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.dialer.R;
5421299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Leeimport com.android.dialer.calllog.CallLogQuery;
55dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.dialer.calllog.ContactInfoHelper;
56fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Leeimport com.android.dialer.calllog.CallLogAdapter;
57dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.dialer.calllog.CallLogQueryHandler;
58c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow;
59704acc087ce359295475a46695c2821c55778344Chiao Chengimport com.android.dialerbind.ObjectFactory;
60c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
61c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport java.util.ArrayList;
62c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport java.util.HashMap;
636b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
646b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee/**
656b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * Fragment for Phone UI's favorite screen.
666b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee *
676b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * This fragment contains three kinds of contacts in one screen: "starred", "frequent", and "all"
686b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * contacts. To show them at once, this merges results from {@link com.android.contacts.common.list.ContactTileAdapter} and
696b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * {@link com.android.contacts.common.list.PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}.
706b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee * A contact filter header is also inserted between those adapters' results.
716b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee */
728898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Leepublic class PhoneFavoriteFragment extends Fragment implements OnItemClickListener,
73c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher,
74c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener {
75c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
768898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Lee    private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
773ed80a357d780310777178ad589d7771d4f7bf2dYorke Lee    private static final boolean DEBUG = false;
78c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
794911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang    private int mAnimationDuration;
806b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
816b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
826b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * Used with LoaderManager.
836b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
846b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private static int LOADER_ID_CONTACT_TILE = 1;
85c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private static int MISSED_CALL_LOADER = 2;
866b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
8721299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    private static final String KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE =
8821299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee            "key_last_dismissed_call_shortcut_date";
8921299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
908dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee    public interface OnShowAllContactsListener {
918dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        public void onShowAllContacts();
928dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee    }
938dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee
946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public interface Listener {
956b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onContactSelected(Uri contactUri);
966b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onCallNumberDirectly(String phoneNumber);
976b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
986b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
99c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private class MissedCallLogLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
100c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
101c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        @Override
102c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
103c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            final Uri uri = CallLog.Calls.CONTENT_URI;
104c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            final String[] projection = new String[] {CallLog.Calls.TYPE};
105c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            final String selection = CallLog.Calls.TYPE + " = " + CallLog.Calls.MISSED_TYPE +
106c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    " AND " + CallLog.Calls.IS_READ + " = 0";
107c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            return new CursorLoader(getActivity(), uri, projection, selection, null, null);
108c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
109c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
110c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        @Override
111c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
112c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            mCallLogAdapter.setMissedCalls(data);
113c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
114c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
115c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        @Override
116c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        public void onLoaderReset(Loader<Cursor> cursorLoader) {
117c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
118c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
119c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1206b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
1216b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1226b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public CursorLoader onCreateLoader(int id, Bundle args) {
1236b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onCreateLoader.");
1246b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
1256b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1266b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1276b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1286b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1296b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoadFinished");
1306b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            mContactTileAdapter.setContactCursor(data);
1314fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen            setEmptyViewVisibility(mContactTileAdapter.getCount() == 0);
1326b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1336b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1346b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1356b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onLoaderReset(Loader<Cursor> loader) {
1366b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoaderReset. ");
1376b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1386b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1396b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1406b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ContactTileAdapterListener implements ContactTileView.Listener {
1416b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1426b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onContactSelected(Uri contactUri, Rect targetRect) {
1436b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (mListener != null) {
1446b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                mListener.onContactSelected(contactUri);
1456b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            }
1466b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1476b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1486b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1496b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onCallNumberDirectly(String phoneNumber) {
1506b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (mListener != null) {
1516b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                mListener.onCallNumberDirectly(phoneNumber);
1526b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            }
1536b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1546b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1556b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1566b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public int getApproximateTileWidth() {
1576b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            return getView().getWidth() / mContactTileAdapter.getColumnCount();
1586b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1606b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1616b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ScrollListener implements ListView.OnScrollListener {
1626b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1636b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onScroll(AbsListView view,
1646b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                int firstVisibleItem, int visibleItemCount, int totalItemCount) {
1656b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1666b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1676b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1686b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onScrollStateChanged(AbsListView view, int scrollState) {
169dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
1706b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1716b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1726b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1736b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private Listener mListener;
174dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
175dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private OnListFragmentScrolledListener mActivityScrollListener;
1768dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee    private OnShowAllContactsListener mShowAllContactsListener;
1778898cd0577d41cfa4e6acf785c9e904bd71fbdfdYorke Lee    private PhoneFavoriteMergedAdapter mAdapter;
178dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private PhoneFavoritesTileAdapter mContactTileAdapter;
1796b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
180fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    private CallLogAdapter mCallLogAdapter;
181dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private CallLogQueryHandler mCallLogQueryHandler;
182dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
1834fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    private View mParentView;
1844fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
185bf5b298b1a5752a56315131a22434185198370a8Hongwei Wang    private PhoneFavoriteListView mListView;
18618e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee
1876091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen    private View mShowAllContactsButton;
1884fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    private View mShowAllContactsInEmptyViewButton;
1896b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
190c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private final HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
191c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private final HashMap<Long, Integer> mItemIdLeftMap = new HashMap<Long, Integer>();
192c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
1936b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
19418e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee     * Layout used when there are no favorites.
1956b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
19618e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee    private View mEmptyView;
1976b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
19821299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    /**
19921299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee     * Call shortcuts older than this date (persisted in shared preferences) will not show up in
20021299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee     * at the top of the screen
20121299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee     */
20221299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    private long mLastCallShortcutDate = 0;
20321299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
20421299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    /**
20521299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee     * The date of the current call shortcut that is showing on screen.
20621299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee     */
20721299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    private long mCurrentCallShortcutDate = 0;
20821299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
2096b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final ContactTileView.Listener mContactTileAdapterListener =
2106b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            new ContactTileAdapterListener();
2116b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
2126b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            new ContactTileLoaderListener();
2136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final ScrollListener mScrollListener = new ScrollListener();
2146b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2156b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2166b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onAttach(Activity activity) {
2176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (DEBUG) Log.d(TAG, "onAttach()");
2186b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onAttach(activity);
2196b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2206b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // Construct two base adapters which will become part of PhoneFavoriteMergedAdapter.
2216b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // We don't construct the resultant adapter at this moment since it requires LayoutInflater
2226b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // that will be available on onCreateView().
223dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mContactTileAdapter = new PhoneFavoritesTileAdapter(activity, mContactTileAdapterListener,
224c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                this,
225dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                getResources().getInteger(R.integer.contact_tile_column_count_in_favorites_new),
226dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                1);
2276b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
2286b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2296b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2306b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2316b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onCreate(Bundle savedState) {
2326b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (DEBUG) Log.d(TAG, "onCreate()");
2336b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onCreate(savedState);
2346b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2354911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        mAnimationDuration = getResources().getInteger(R.integer.fade_duration);
236dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
237dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                this, 1);
238dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
239704acc087ce359295475a46695c2821c55778344Chiao Cheng        mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
240704acc087ce359295475a46695c2821c55778344Chiao Cheng                new ContactInfoHelper(getActivity(), currentCountryIso), true, false);
2416b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        setHasOptionsMenu(true);
2426b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2436b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2446b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
245dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onResume() {
246dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        super.onResume();
24721299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        final SharedPreferences prefs = getActivity().getSharedPreferences(
24821299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
24921299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
25021299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        mLastCallShortcutDate = prefs.getLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, 0);
25121299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
2524dc32bdf10bff18acbc1964d289354556950d2ebYorke Lee        fetchCalls();
253dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogAdapter.setLoading(true);
25411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad();
2556b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2566b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2576b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2586b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public View onCreateView(LayoutInflater inflater, ViewGroup container,
2596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            Bundle savedInstanceState) {
2604fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        mParentView = inflater.inflate(R.layout.phone_favorites_fragment, container, false);
2616b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2624fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        mListView = (PhoneFavoriteListView) mParentView.findViewById(R.id.contact_tile_list);
2636b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setItemsCanFocus(true);
2646b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setOnItemClickListener(this);
2656b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setVerticalScrollBarEnabled(false);
2666b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
2676b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
26811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        mListView.setOnItemSwipeListener(mContactTileAdapter);
2697639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang        mListView.setOnDragDropListener(mContactTileAdapter);
2706b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2714911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        final ImageView dragShadowOverlay =
2724fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen                (ImageView) mParentView.findViewById(R.id.contact_tile_drag_shadow_overlay);
2734911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        mListView.setDragShadowOverlay(dragShadowOverlay);
2744911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang
2754fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        mEmptyView = mParentView.findViewById(R.id.phone_no_favorites_view);
2764fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
2774fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        mShowAllContactsInEmptyViewButton = mParentView.findViewById(
2784fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen                R.id.show_all_contact_button_in_nofav);
2794fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        mShowAllContactsInEmptyViewButton.setOnClickListener(new OnClickListener() {
2804fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen            @Override
2814fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen            public void onClick(View view) {
2824fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen                showAllContacts();
2834fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen            }
2844fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        });
28518e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee
2866091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        mShowAllContactsButton = inflater.inflate(R.layout.show_all_contact_button, mListView,
2876091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen                false);
2886091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        mShowAllContactsButton.setOnClickListener(new OnClickListener() {
2896091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen            @Override
2906091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen            public void onClick(View view) {
2916091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen                showAllContacts();
2926091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen            }
2936091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        });
2946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
29521299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, mContactTileAdapter,
29618e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee                mCallLogAdapter, mShowAllContactsButton);
2976b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2986b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setAdapter(mAdapter);
2996b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3006b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setOnScrollListener(mScrollListener);
3016b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setFastScrollEnabled(false);
3026b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setFastScrollAlwaysVisible(false);
3036b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3044fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        return mParentView;
3056b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3066b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
307f420a5344995b2c450379159f679809690bc9880Yorke Lee    public boolean hasFrequents() {
308f420a5344995b2c450379159f679809690bc9880Yorke Lee        if (mContactTileAdapter == null) return false;
3096b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        return mContactTileAdapter.getNumFrequents() > 0;
3106b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3116b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3124fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    /* package */ void setEmptyViewVisibility(final boolean visible) {
3134fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        final int previousVisibility = mEmptyView.getVisibility();
3144fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        final int newVisibility = visible ? View.VISIBLE : View.GONE;
3154fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
3164fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        if (previousVisibility != newVisibility) {
317fe3fbd24097c51290b189f2788059c4083dd90a1Christine Chen            mEmptyView.setVisibility(newVisibility);
3184fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        }
3194fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    }
3204fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
3216b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
3226b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onStart() {
3236b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onStart();
3246b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
325dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final Activity activity = getActivity();
326dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
327dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        try {
328dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
329dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } catch (ClassCastException e) {
330dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            throw new ClassCastException(activity.toString()
331dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    + " must implement OnListFragmentScrolledListener");
332dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
3336b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3348dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        try {
3358dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee            mShowAllContactsListener = (OnShowAllContactsListener) activity;
3368dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        } catch (ClassCastException e) {
3378dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee            throw new ClassCastException(activity.toString()
3388dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee                    + " must implement OnShowAllContactsListener");
3398dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        }
3408dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee
3416b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // Use initLoader() instead of restartLoader() to refraining unnecessary reload.
3426b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
3436b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // be called, on which we'll check if "all" contacts should be reloaded again or not.
3446b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener);
345c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        getLoaderManager().initLoader(MISSED_CALL_LOADER, null, new MissedCallLogLoaderListener());
3466b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3476b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3486b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
3496b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * {@inheritDoc}
3506b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     *
3516b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * This is only effective for elements provided by {@link #mContactTileAdapter}.
3526b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * {@link #mContactTileAdapter} has its own logic for click events.
3536b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
3546b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
3556b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
3566b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        final int contactTileAdapterCount = mContactTileAdapter.getCount();
3576b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (position <= contactTileAdapterCount) {
3586b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            Log.e(TAG, "onItemClick() event for unexpected position. "
3596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                    + "The position " + position + " is before \"all\" section. Ignored.");
3606b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
3616b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3626b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3636b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
3646091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen     * Gets called when user click on the show all contacts button.
3656b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
3666091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen    private void showAllContacts() {
3678dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        mShowAllContactsListener.onShowAllContacts();
3686b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3696b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
370dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setListener(Listener listener) {
371dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mListener = listener;
3726b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3736b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
374dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
375dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onVoicemailStatusFetched(Cursor statusCursor) {
3764dc32bdf10bff18acbc1964d289354556950d2ebYorke Lee        // no-op
3776b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3786b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
379dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
380dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onCallsFetched(Cursor cursor) {
381dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogAdapter.setLoading(false);
38221299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
38321299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        // Save the date of the most recent call log item
38421299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        if (cursor != null && cursor.moveToFirst()) {
38521299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee            mCurrentCallShortcutDate = cursor.getLong(CallLogQuery.DATE);
38621299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        }
38721299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
388dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mCallLogAdapter.changeCursor(cursor);
38921299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
390dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mAdapter.notifyDataSetChanged();
3916b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3926b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
393dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
394dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void fetchCalls() {
39521299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL, mLastCallShortcutDate);
3966b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
39711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee
39811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee    @Override
39911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee    public void onPause() {
40011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        // If there are any pending contact entries that are to be removed, remove them
40111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        mContactTileAdapter.removePendingContactEntry();
4023b9d09c50b6ed52cbfe6d87cee06ecef5116d799Yorke Lee        // Wipe the cache to refresh the call shortcut item. This is not that expensive because
4033b9d09c50b6ed52cbfe6d87cee06ecef5116d799Yorke Lee        // it only contains one item.
4043b9d09c50b6ed52cbfe6d87cee06ecef5116d799Yorke Lee        mCallLogAdapter.invalidateCache();
40511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee        super.onPause();
40611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee    }
407c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
408c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /**
409c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * Saves the current view offsets into memory
410c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
411c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @SuppressWarnings("unchecked")
412c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void saveOffsets(long... idsInPlace) {
413c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        final int firstVisiblePosition = mListView.getFirstVisiblePosition();
414c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        if (DEBUG) {
415c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            Log.d(TAG, "Child count : " + mListView.getChildCount());
416c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
417c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < mListView.getChildCount(); i++) {
418c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = mListView.getChildAt(i);
419c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final int position = firstVisiblePosition + i;
420c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final long itemId = mAdapter.getItemId(position);
421c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final int itemViewType = mAdapter.getItemViewType(position);
422c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (itemViewType == PhoneFavoritesTileAdapter.ViewTypes.TOP) {
423c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                // This is a tiled row, so save horizontal offsets instead
424c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                saveHorizontalOffsets((ContactTileRow) child, (ArrayList<ContactEntry>)
425c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        mAdapter.getItem(position), idsInPlace);
426c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
427c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (DEBUG) {
428c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                Log.d(TAG, "Saving itemId: " + itemId + " for listview child " + i + " Top: "
429c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        + child.getTop());
430c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
431c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            mItemIdTopMap.put(itemId, child.getTop());
432c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
433c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
434c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
435c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void saveHorizontalOffsets(ContactTileRow row, ArrayList<ContactEntry> list,
436c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            long... idsInPlace) {
437c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < list.size(); i++) {
438c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = row.getChildAt(i);
439c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final ContactEntry entry = list.get(i);
440c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final long itemId = mContactTileAdapter.getAdjustedItemId(entry.id);
441c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (DEBUG) {
442c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                Log.d(TAG, "Saving itemId: " + itemId + " for tileview child " + i + " Left: "
443c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        + child.getTop());
444c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
445c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            mItemIdLeftMap.put(itemId, child.getLeft());
446c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
447c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
448c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
449c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /*
450c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * Performs a animations for a row of tiles
451c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
452c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void performHorizontalAnimations(ContactTileRow row, ArrayList<ContactEntry> list,
453c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            long[] idsInPlace) {
454c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        if (mItemIdLeftMap.isEmpty()) {
455c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            return;
456c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
4575b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang        final AnimatorSet animSet = new AnimatorSet();
4585b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang        final ArrayList<Animator> animators = new ArrayList<Animator>();
459c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < list.size(); i++) {
460c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = row.getChildAt(i);
461c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final ContactEntry entry = list.get(i);
462c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final long itemId = mContactTileAdapter.getAdjustedItemId(entry.id);
463c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
4644911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang            if (containsId(idsInPlace, itemId)) {
4655b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                animators.add(ObjectAnimator.ofFloat(
4665b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        child, "alpha", 0.0f, 1.0f));
4674911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                break;
4685b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang            } else {
4695b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                Integer startLeft = mItemIdLeftMap.get(itemId);
4705b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                int left = child.getLeft();
4715b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                if (startLeft != null) {
4725b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    if (startLeft != left) {
4735b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        int delta = startLeft - left;
4745b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        if (DEBUG) {
4755b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            Log.d(TAG, "Found itemId: " + itemId + " for tileview child " + i +
4765b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                    " Left: " + left +
4775b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                    " Delta: " + delta);
4785b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        }
4795b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        animators.add(ObjectAnimator.ofFloat(
4805b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                child, "translationX", delta, 0.0f));
4815b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    }
4825b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                } else {
4835b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    // In case the last square row is pushed up from the non-square section.
4845b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    animators.add(ObjectAnimator.ofFloat(
4855b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            child, "translationX", left, 0.0f));
4865b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                }
487c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
488c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
4895b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang        if (animators.size() > 0) {
4905b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang            animSet.setDuration(mAnimationDuration).playTogether(animators);
4915b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang            animSet.start();
4925b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang        }
493c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
494c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
495c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /*
496c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * Performs animations for the list view. If the list item is a row of tiles, horizontal
497c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     * animations will be performed instead.
498c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
499c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private void animateListView(final long... idsInPlace) {
50020d682f9a586da495f180bfb6a445520d027c74dHongwei Wang        if (mItemIdTopMap.isEmpty()) {
501c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // Don't do animations if the database is being queried for the first time and
502c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // the previous item offsets have not been cached, or the user hasn't done anything
503c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // (dragging, swiping etc) that requires an animation.
504c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            return;
505c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
506c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        final ViewTreeObserver observer = mListView.getViewTreeObserver();
507c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
508c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            @SuppressWarnings("unchecked")
509c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            @Override
510c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            public boolean onPreDraw() {
511c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                observer.removeOnPreDrawListener(this);
512c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                final int firstVisiblePosition = mListView.getFirstVisiblePosition();
5135b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                final AnimatorSet animSet = new AnimatorSet();
5145b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                final ArrayList<Animator> animators = new ArrayList<Animator>();
515c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                for (int i = 0; i < mListView.getChildCount(); i++) {
516c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final View child = mListView.getChildAt(i);
517c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    int position = firstVisiblePosition + i;
518c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final int itemViewType = mAdapter.getItemViewType(position);
519c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    if (itemViewType == PhoneFavoritesTileAdapter.ViewTypes.TOP) {
520c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        // This is a tiled row, so perform horizontal animations instead
521c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        performHorizontalAnimations((ContactTileRow) child, (
522c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                                ArrayList<ContactEntry>) mAdapter.getItem(position), idsInPlace);
523c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    }
524c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
525c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final long itemId = mAdapter.getItemId(position);
526c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
5274911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                    if (containsId(idsInPlace, itemId)) {
5285b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        animators.add(ObjectAnimator.ofFloat(
5295b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                child, "alpha", 0.0f, 1.0f));
5305b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        break;
531f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                    } else {
532f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        Integer startTop = mItemIdTopMap.get(itemId);
533f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        final int top = child.getTop();
534f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        int delta = 0;
535f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        if (startTop != null) {
536f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            if (startTop != top) {
537f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                                delta = startTop - top;
538f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            }
539f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        } else if (!mItemIdLeftMap.containsKey(itemId)) {
540f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            // Animate new views along with the others. The catch is that they did
541f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            // not exist in the start state, so we must calculate their starting
542f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            // position based on neighboring views.
543f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            int childHeight = child.getHeight() + mListView.getDividerHeight();
544f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            startTop = top + (i > 0 ? childHeight : -childHeight);
545f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            delta = startTop - top;
5465b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        } else {
54720d682f9a586da495f180bfb6a445520d027c74dHongwei Wang                            // In case the first non-square row is pushed down
5485b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            // from the square section.
5495b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            animators.add(ObjectAnimator.ofFloat(
55020d682f9a586da495f180bfb6a445520d027c74dHongwei Wang                                    child, "alpha", 0.0f, 1.0f));
5515b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        }
5525b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        if (DEBUG) {
5535b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            Log.d(TAG, "Found itemId: " + itemId + " for listview child " + i +
5545b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                    " Top: " + top +
5555b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                    " Delta: " + delta);
556f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        }
557f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira
558f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        if (delta != 0) {
5595b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            animators.add(ObjectAnimator.ofFloat(
5605b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                    child, "translationY", delta, 0.0f));
561f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        }
562c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    }
563c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                }
5645b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang
5655b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                if (animators.size() > 0) {
5665b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    animSet.setDuration(mAnimationDuration).playTogether(animators);
5675b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    animSet.start();
5685b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                }
5695b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang
570c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                mItemIdTopMap.clear();
571c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                mItemIdLeftMap.clear();
572c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                return true;
573c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
574c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        });
575c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
576c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
577c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private boolean containsId(long[] ids, long target) {
578c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        // Linear search on array is fine because this is typically only 0-1 elements long
579c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < ids.length; i++) {
580c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (ids[i] == target) {
581c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                return true;
582c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
583c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
584c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        return false;
585c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
586c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
587c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @Override
588c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    public void onDataSetChangedForAnimation(long... idsInPlace) {
589c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        animateListView(idsInPlace);
590c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
591c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
592c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @Override
593c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    public void cacheOffsetsForDatasetChange() {
594c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        saveOffsets();
595c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
59621299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
59721299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    public void dismissShortcut() {
59821299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        mLastCallShortcutDate = mCurrentCallShortcutDate;
59921299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        final SharedPreferences prefs = getActivity().getSharedPreferences(
60021299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
60121299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        prefs.edit().putLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, mLastCallShortcutDate)
60221299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee                .apply();
60321299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee        fetchCalls();
60421299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee    }
6056b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee}
606