SpeedDialFragment.java revision 575ae388961252a771488c357e425fca191594b2
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
1838019af70eb1ca084d36291390bbc54dc81027deYorke Leeimport static android.Manifest.permission.READ_CONTACTS;
1938019af70eb1ca084d36291390bbc54dc81027deYorke Lee
205b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wangimport android.animation.Animator;
215b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wangimport android.animation.AnimatorSet;
225b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wangimport android.animation.ObjectAnimator;
236b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.Activity;
24beab3bbc2c977a48e3affc3e61cc2fdbb22c4ae2Brian Attwellimport android.app.Fragment;
256b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.app.LoaderManager;
266b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.content.CursorLoader;
276b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.content.Loader;
286b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.database.Cursor;
296b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.graphics.Rect;
306b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.net.Uri;
316b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.os.Bundle;
32f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Leeimport android.os.Trace;
336b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.util.Log;
346b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.LayoutInflater;
356b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.View;
366b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.view.ViewGroup;
37765734c1d602c9a6d166d653b3684e6408b771c4Yorke Leeimport android.view.ViewTreeObserver;
389b08f53ac993cffa249b73d3a2cc9ed5a9e71158Yorke Leeimport android.view.animation.AnimationUtils;
399b08f53ac993cffa249b73d3a2cc9ed5a9e71158Yorke Leeimport android.view.animation.LayoutAnimationController;
406b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AbsListView;
416b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AdapterView;
426b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.AdapterView.OnItemClickListener;
43ae6302b51b1f03ddd4865539b071ba2a661b977fYorke Leeimport android.widget.FrameLayout;
44ae6302b51b1f03ddd4865539b071ba2a661b977fYorke Leeimport android.widget.FrameLayout.LayoutParams;
454911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wangimport android.widget.ImageView;
466b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport android.widget.ListView;
476b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
486b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.ContactPhotoManager;
496b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.ContactTileLoaderFactory;
506b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.contacts.common.list.ContactTileView;
51e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Leeimport com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
52c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Leeimport com.android.contacts.common.util.PermissionsUtil;
536b049128c51b90e17ae14856d98130a22d3a5433Yorke Leeimport com.android.dialer.R;
540a4327e6bfeedc23ddefb4df9f6e8041ebc87b59Andrew Leeimport com.android.dialer.util.DialerUtils;
5538019af70eb1ca084d36291390bbc54dc81027deYorke Leeimport com.android.dialer.widget.EmptyContentView;
56c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
57c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport java.util.ArrayList;
58c36684277aa45085999284bfe71cb8be71b3a464Yorke Leeimport java.util.HashMap;
596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
606b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee/**
61d999b71452baebec789f6f58f1955d30e834826dYorke Lee * This fragment displays the user's favorite/frequent contacts in a grid.
626b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee */
63beab3bbc2c977a48e3affc3e61cc2fdbb22c4ae2Brian Attwellpublic class SpeedDialFragment extends Fragment implements OnItemClickListener,
6438019af70eb1ca084d36291390bbc54dc81027deYorke Lee        PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener,
6538019af70eb1ca084d36291390bbc54dc81027deYorke Lee        EmptyContentView.OnEmptyViewActionButtonClickedListener {
66c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
674ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee    /**
684ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee     * By default, the animation code assumes that all items in a list view are of the same height
694ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee     * when animating new list items into view (e.g. from the bottom of the screen into view).
704ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee     * This can cause incorrect translation offsets when a item that is larger or smaller than
714ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee     * other list item is removed from the list. This key is used to provide the actual height
724ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee     * of the removed object so that the actual translation appears correct to the user.
734ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee     */
744ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee    private static final long KEY_REMOVED_ITEM_HEIGHT = Long.MAX_VALUE;
754ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee
76f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee    private static final String TAG = "SpeedDialFragment";
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;
8521299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
863cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee    public interface HostInterface {
873cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee        public void setDragDropController(DragDropController controller);
8838019af70eb1ca084d36291390bbc54dc81027deYorke Lee        public void showAllContactsTab();
893cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee    }
903cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee
916b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
926b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
936b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public CursorLoader onCreateLoader(int id, Bundle args) {
946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onCreateLoader.");
956b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
966b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
976b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
986b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
996b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1006b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoadFinished");
1016b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            mContactTileAdapter.setContactCursor(data);
1024fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen            setEmptyViewVisibility(mContactTileAdapter.getCount() == 0);
1036b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1046b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1056b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1066b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onLoaderReset(Loader<Cursor> loader) {
1076b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoaderReset. ");
1086b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1096b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1106b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1116b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ContactTileAdapterListener implements ContactTileView.Listener {
1126b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onContactSelected(Uri contactUri, Rect targetRect) {
114e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee            if (mPhoneNumberPickerActionListener != null) {
115e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee                mPhoneNumberPickerActionListener.onPickPhoneNumberAction(contactUri);
1166b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            }
1176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1186b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1196b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1206b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onCallNumberDirectly(String phoneNumber) {
121e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee            if (mPhoneNumberPickerActionListener != null) {
122e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee                mPhoneNumberPickerActionListener.onCallNumberDirectly(phoneNumber);
1236b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            }
1246b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1256b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1266b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1276b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public int getApproximateTileWidth() {
128efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee            return getView().getWidth();
1296b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1306b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1316b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1326b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private class ScrollListener implements ListView.OnScrollListener {
1336b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1346b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onScroll(AbsListView view,
1356b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                int firstVisibleItem, int visibleItemCount, int totalItemCount) {
13686e21f733049560e77b92f17a58474312d72ec3eYorke Lee            if (mActivityScrollListener != null) {
13786e21f733049560e77b92f17a58474312d72ec3eYorke Lee                mActivityScrollListener.onListFragmentScroll(firstVisibleItem, visibleItemCount,
13886e21f733049560e77b92f17a58474312d72ec3eYorke Lee                    totalItemCount);
13986e21f733049560e77b92f17a58474312d72ec3eYorke Lee            }
1406b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1416b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1426b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        @Override
1436b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        public void onScrollStateChanged(AbsListView view, int scrollState) {
144dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
1456b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
1466b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1476b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
148e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee    private OnPhoneNumberPickerActionListener mPhoneNumberPickerActionListener;
149dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
150dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private OnListFragmentScrolledListener mActivityScrollListener;
151dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private PhoneFavoritesTileAdapter mContactTileAdapter;
1526b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1534fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    private View mParentView;
1544fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
155bf5b298b1a5752a56315131a22434185198370a8Hongwei Wang    private PhoneFavoriteListView mListView;
15618e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee
1573eb8ab2ab09a9e742cde17e36381a6dde058c4beYorke Lee    private View mContactTileFrame;
1586b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
159c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private final HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
160c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private final HashMap<Long, Integer> mItemIdLeftMap = new HashMap<Long, Integer>();
161c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
1626b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
16318e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee     * Layout used when there are no favorites.
1646b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
16538019af70eb1ca084d36291390bbc54dc81027deYorke Lee    private EmptyContentView mEmptyView;
1666b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1676b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final ContactTileView.Listener mContactTileAdapterListener =
1686b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            new ContactTileAdapterListener();
1696b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
1706b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            new ContactTileLoaderListener();
1716b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    private final ScrollListener mScrollListener = new ScrollListener();
1726b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1736b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
1746b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onAttach(Activity activity) {
1756b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (DEBUG) Log.d(TAG, "onAttach()");
1766b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onAttach(activity);
1776b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1786b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // Construct two base adapters which will become part of PhoneFavoriteMergedAdapter.
1796b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // We don't construct the resultant adapter at this moment since it requires LayoutInflater
1806b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // that will be available on onCreateView().
181dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mContactTileAdapter = new PhoneFavoritesTileAdapter(activity, mContactTileAdapterListener,
182efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                this);
1836b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
1846b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1856b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1866b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
1876b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onCreate(Bundle savedState) {
1886b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (DEBUG) Log.d(TAG, "onCreate()");
189f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee        Trace.beginSection(TAG + " onCreate");
1906b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onCreate(savedState);
1916b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1924911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        mAnimationDuration = getResources().getInteger(R.integer.fade_duration);
193f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee        Trace.endSection();
1946b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
1956b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
1966b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
197dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void onResume() {
198f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee        Trace.beginSection(TAG + " onResume");
199dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        super.onResume();
20021299c354c4178dd8f89eef42872cbd62cd4aaf0Yorke Lee
201c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        if (PermissionsUtil.hasContactsPermissions(getActivity())) {
2022a613022dbb278f0f7dd94cf49885cde9d36100cYorke Lee            if (getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE) == null) {
2032a613022dbb278f0f7dd94cf49885cde9d36100cYorke Lee                getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null,
2042a613022dbb278f0f7dd94cf49885cde9d36100cYorke Lee                        mContactTileLoaderListener);
20538019af70eb1ca084d36291390bbc54dc81027deYorke Lee
2062a613022dbb278f0f7dd94cf49885cde9d36100cYorke Lee            } else {
2072a613022dbb278f0f7dd94cf49885cde9d36100cYorke Lee                getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad();
2082a613022dbb278f0f7dd94cf49885cde9d36100cYorke Lee            }
20938019af70eb1ca084d36291390bbc54dc81027deYorke Lee
21038019af70eb1ca084d36291390bbc54dc81027deYorke Lee            mEmptyView.setDescription(R.string.speed_dial_empty);
21138019af70eb1ca084d36291390bbc54dc81027deYorke Lee            mEmptyView.setActionLabel(R.string.speed_dial_empty_add_favorite_action);
21238019af70eb1ca084d36291390bbc54dc81027deYorke Lee        } else {
21338019af70eb1ca084d36291390bbc54dc81027deYorke Lee            mEmptyView.setDescription(R.string.permission_no_speeddial);
21438019af70eb1ca084d36291390bbc54dc81027deYorke Lee            mEmptyView.setActionLabel(R.string.permission_single_turn_on);
215c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        }
216f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee        Trace.endSection();
2176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2186b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2196b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2206b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public View onCreateView(LayoutInflater inflater, ViewGroup container,
2216b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            Bundle savedInstanceState) {
222f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee        Trace.beginSection(TAG + " onCreateView");
22339f773e8a64ec1b770b2679871b7c44cac7243d2Andrew Lee        mParentView = inflater.inflate(R.layout.speed_dial_fragment, container, false);
2246b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2254fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        mListView = (PhoneFavoriteListView) mParentView.findViewById(R.id.contact_tile_list);
2266b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setOnItemClickListener(this);
2276b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setVerticalScrollBarEnabled(false);
2286b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
2296b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
2303cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee        mListView.getDragDropController().addOnDragDropListener(mContactTileAdapter);
2316b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2324911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        final ImageView dragShadowOverlay =
233f66cc0403faab0a31ccdb2c78e0dad5be11218f5Yorke Lee                (ImageView) getActivity().findViewById(R.id.contact_tile_drag_shadow_overlay);
2344911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang        mListView.setDragShadowOverlay(dragShadowOverlay);
2354911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang
23638019af70eb1ca084d36291390bbc54dc81027deYorke Lee        mEmptyView = (EmptyContentView) mParentView.findViewById(R.id.empty_list_view);
23738019af70eb1ca084d36291390bbc54dc81027deYorke Lee        mEmptyView.setImage(R.drawable.empty_speed_dial);
23838019af70eb1ca084d36291390bbc54dc81027deYorke Lee        mEmptyView.setActionClickedListener(this);
2394fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
2403eb8ab2ab09a9e742cde17e36381a6dde058c4beYorke Lee        mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame);
2413eb8ab2ab09a9e742cde17e36381a6dde058c4beYorke Lee
2429b08f53ac993cffa249b73d3a2cc9ed5a9e71158Yorke Lee        final LayoutAnimationController controller = new LayoutAnimationController(
2439b08f53ac993cffa249b73d3a2cc9ed5a9e71158Yorke Lee                AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));
2449b08f53ac993cffa249b73d3a2cc9ed5a9e71158Yorke Lee        controller.setDelay(0);
2459b08f53ac993cffa249b73d3a2cc9ed5a9e71158Yorke Lee        mListView.setLayoutAnimation(controller);
246efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee        mListView.setAdapter(mContactTileAdapter);
2476b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2486b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setOnScrollListener(mScrollListener);
2496b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setFastScrollEnabled(false);
2506b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        mListView.setFastScrollAlwaysVisible(false);
251f5554ceb3c152949b4b6278b7f5e1522148a574cYorke Lee        Trace.endSection();
2524fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        return mParentView;
2536b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2546b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
255f420a5344995b2c450379159f679809690bc9880Yorke Lee    public boolean hasFrequents() {
256f420a5344995b2c450379159f679809690bc9880Yorke Lee        if (mContactTileAdapter == null) return false;
2576b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        return mContactTileAdapter.getNumFrequents() > 0;
2586b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
2596b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2604fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    /* package */ void setEmptyViewVisibility(final boolean visible) {
2614fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        final int previousVisibility = mEmptyView.getVisibility();
2620bbd606a3d1da11a38fdc127f4067b06f71174f8Ihab Awad        final int emptyViewVisibility = visible ? View.VISIBLE : View.GONE;
2630bbd606a3d1da11a38fdc127f4067b06f71174f8Ihab Awad        final int listViewVisibility = visible ? View.GONE : View.VISIBLE;
2644fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
2650bbd606a3d1da11a38fdc127f4067b06f71174f8Ihab Awad        if (previousVisibility != emptyViewVisibility) {
266ae6302b51b1f03ddd4865539b071ba2a661b977fYorke Lee            final FrameLayout.LayoutParams params = (LayoutParams) mContactTileFrame
2673eb8ab2ab09a9e742cde17e36381a6dde058c4beYorke Lee                    .getLayoutParams();
2683eb8ab2ab09a9e742cde17e36381a6dde058c4beYorke Lee            params.height = visible ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT;
2693eb8ab2ab09a9e742cde17e36381a6dde058c4beYorke Lee            mContactTileFrame.setLayoutParams(params);
2700bbd606a3d1da11a38fdc127f4067b06f71174f8Ihab Awad            mEmptyView.setVisibility(emptyViewVisibility);
2710bbd606a3d1da11a38fdc127f4067b06f71174f8Ihab Awad            mListView.setVisibility(listViewVisibility);
2724fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen        }
2734fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen    }
2744fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen
2756b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
2766b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onStart() {
2776b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        super.onStart();
2786b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
279dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final Activity activity = getActivity();
280dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
281dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        try {
282dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
283dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } catch (ClassCastException e) {
284dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            throw new ClassCastException(activity.toString()
285dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    + " must implement OnListFragmentScrolledListener");
286dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
2876b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
2888dd6200bef2eb07486f4c7e288941cfcfed35e79Yorke Lee        try {
2893cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee            OnDragDropListener listener = (OnDragDropListener) activity;
2903cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee            mListView.getDragDropController().addOnDragDropListener(listener);
2913cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee            ((HostInterface) activity).setDragDropController(mListView.getDragDropController());
2923cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee        } catch (ClassCastException e) {
2933cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee            throw new ClassCastException(activity.toString()
2943cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee                    + " must implement OnDragDropListener and HostInterface");
2953cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee        }
2963cefcc69c10ab12bd782a0b53779dbd1cc0e2aa1Yorke Lee
297e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee        try {
298e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee            mPhoneNumberPickerActionListener = (OnPhoneNumberPickerActionListener) activity;
299e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee        } catch (ClassCastException e) {
300e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee            throw new ClassCastException(activity.toString()
301e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee                    + " must implement PhoneFavoritesFragment.listener");
302e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee        }
303e00c9fe163d19ee380b922e3fcbe736216d78cccYorke Lee
3046b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // Use initLoader() instead of restartLoader() to refraining unnecessary reload.
3056b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
3066b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        // be called, on which we'll check if "all" contacts should be reloaded again or not.
307c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        if (PermissionsUtil.hasContactsPermissions(activity)) {
308c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee            getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener);
309c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        } else {
310c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee            setEmptyViewVisibility(true);
311c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        }
3126b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3136b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
3146b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    /**
3156b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * {@inheritDoc}
3166b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     *
3176b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * This is only effective for elements provided by {@link #mContactTileAdapter}.
3186b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     * {@link #mContactTileAdapter} has its own logic for click events.
3196b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee     */
3206b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    @Override
3216b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
3226b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        final int contactTileAdapterCount = mContactTileAdapter.getCount();
3236b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        if (position <= contactTileAdapterCount) {
3246b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee            Log.e(TAG, "onItemClick() event for unexpected position. "
3256b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee                    + "The position " + position + " is before \"all\" section. Ignored.");
3266b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee        }
3276b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee    }
3286b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee
329c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /**
330765734c1d602c9a6d166d653b3684e6408b771c4Yorke Lee     * Cache the current view offsets into memory. Once a relayout of views in the ListView
331765734c1d602c9a6d166d653b3684e6408b771c4Yorke Lee     * has happened due to a dataset change, the cached offsets are used to create animations
332765734c1d602c9a6d166d653b3684e6408b771c4Yorke Lee     * that slide views from their previous positions to their new ones, to give the appearance
333765734c1d602c9a6d166d653b3684e6408b771c4Yorke Lee     * that the views are sliding into their new positions.
334c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
3354ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee    private void saveOffsets(int removedItemHeight) {
336c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        final int firstVisiblePosition = mListView.getFirstVisiblePosition();
337c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        if (DEBUG) {
338c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            Log.d(TAG, "Child count : " + mListView.getChildCount());
339c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
340c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < mListView.getChildCount(); i++) {
341c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final View child = mListView.getChildAt(i);
342c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            final int position = firstVisiblePosition + i;
343e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee            // Since we are getting the position from mListView and then querying
344e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee            // mContactTileAdapter, its very possible that things are out of sync
345e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee            // and we might index out of bounds.  Let's make sure that this doesn't happen.
346e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee            if (!mContactTileAdapter.isIndexInBound(position)) {
347e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                continue;
348e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee            }
349efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee            final long itemId = mContactTileAdapter.getItemId(position);
350c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (DEBUG) {
351c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                Log.d(TAG, "Saving itemId: " + itemId + " for listview child " + i + " Top: "
352c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                        + child.getTop());
353c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
354c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            mItemIdTopMap.put(itemId, child.getTop());
355c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            mItemIdLeftMap.put(itemId, child.getLeft());
356c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
357efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee        mItemIdTopMap.put(KEY_REMOVED_ITEM_HEIGHT, removedItemHeight);
358c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
359c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
360c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    /*
361efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee     * Performs animations for the gridView
362c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee     */
363efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee    private void animateGridView(final long... idsInPlace) {
36420d682f9a586da495f180bfb6a445520d027c74dHongwei Wang        if (mItemIdTopMap.isEmpty()) {
365c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // Don't do animations if the database is being queried for the first time and
366c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // the previous item offsets have not been cached, or the user hasn't done anything
367c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            // (dragging, swiping etc) that requires an animation.
368c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            return;
369c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
3704ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee
371c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        final ViewTreeObserver observer = mListView.getViewTreeObserver();
372c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
373c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            @SuppressWarnings("unchecked")
374c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            @Override
375c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            public boolean onPreDraw() {
376c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                observer.removeOnPreDrawListener(this);
377c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                final int firstVisiblePosition = mListView.getFirstVisiblePosition();
3785b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                final AnimatorSet animSet = new AnimatorSet();
3795b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                final ArrayList<Animator> animators = new ArrayList<Animator>();
380c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                for (int i = 0; i < mListView.getChildCount(); i++) {
381c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    final View child = mListView.getChildAt(i);
382c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    int position = firstVisiblePosition + i;
383c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
384e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                    // Since we are getting the position from mListView and then querying
385e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                    // mContactTileAdapter, its very possible that things are out of sync
386e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                    // and we might index out of bounds.  Let's make sure that this doesn't happen.
387e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                    if (!mContactTileAdapter.isIndexInBound(position)) {
388e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                        continue;
389e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee                    }
390e48124fa2d295c68cdb95f962ef8bd6d35a7c145Anthony Lee
391efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                    final long itemId = mContactTileAdapter.getItemId(position);
392c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
3934911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang                    if (containsId(idsInPlace, itemId)) {
3945b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        animators.add(ObjectAnimator.ofFloat(
3955b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                child, "alpha", 0.0f, 1.0f));
3965b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        break;
397f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                    } else {
398f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        Integer startTop = mItemIdTopMap.get(itemId);
399efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                        Integer startLeft = mItemIdLeftMap.get(itemId);
400f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        final int top = child.getTop();
401efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                        final int left = child.getLeft();
402efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                        int deltaX = 0;
403efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                        int deltaY = 0;
404efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee
405efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                        if (startLeft != null) {
406efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                            if (startLeft != left) {
407efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                deltaX = startLeft - left;
408efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                animators.add(ObjectAnimator.ofFloat(
409efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                        child, "translationX", deltaX, 0.0f));
410efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                            }
411efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                        }
412efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee
413f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        if (startTop != null) {
414f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                            if (startTop != top) {
415efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                deltaY = startTop - top;
416efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                animators.add(ObjectAnimator.ofFloat(
417efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                        child, "translationY", deltaY, 0.0f));
4184ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee                            }
4195b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        }
420efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee
4215b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                        if (DEBUG) {
4225b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                            Log.d(TAG, "Found itemId: " + itemId + " for listview child " + i +
4235b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                                    " Top: " + top +
424efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee                                    " Delta: " + deltaY);
425f59250951cf47d81fda125e9bab324d66ed75214Mindy Pereira                        }
426c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                    }
427c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                }
4285b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang
4295b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                if (animators.size() > 0) {
4305b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    animSet.setDuration(mAnimationDuration).playTogether(animators);
4315b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                    animSet.start();
4325b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang                }
4335b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang
434c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                mItemIdTopMap.clear();
435c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                mItemIdLeftMap.clear();
436c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                return true;
437c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
438c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        });
439c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
440c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
441c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    private boolean containsId(long[] ids, long target) {
442c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        // Linear search on array is fine because this is typically only 0-1 elements long
443c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        for (int i = 0; i < ids.length; i++) {
444c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            if (ids[i] == target) {
445c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee                return true;
446c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee            }
447c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        }
448c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee        return false;
449c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
450c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
451c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @Override
452c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    public void onDataSetChangedForAnimation(long... idsInPlace) {
453efb2d9c2e32ca4ed434ff785c4b3d18c9e08db6dYorke Lee        animateGridView(idsInPlace);
454c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
455c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee
456c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    @Override
457c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    public void cacheOffsetsForDatasetChange() {
4584ed7db87e6c0e71b2f656e77de938f3579bc36bfYorke Lee        saveOffsets(0);
459c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee    }
460764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
461764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    public AbsListView getListView() {
462764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        return mListView;
463764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    }
46438019af70eb1ca084d36291390bbc54dc81027deYorke Lee
46538019af70eb1ca084d36291390bbc54dc81027deYorke Lee    @Override
466575ae388961252a771488c357e425fca191594b2Yorke Lee    public void onEmptyViewActionButtonClicked() {
46738019af70eb1ca084d36291390bbc54dc81027deYorke Lee        final Activity activity = getActivity();
46838019af70eb1ca084d36291390bbc54dc81027deYorke Lee        if (activity == null) {
46938019af70eb1ca084d36291390bbc54dc81027deYorke Lee            return;
47038019af70eb1ca084d36291390bbc54dc81027deYorke Lee        }
47138019af70eb1ca084d36291390bbc54dc81027deYorke Lee
47238019af70eb1ca084d36291390bbc54dc81027deYorke Lee        if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) {
47338019af70eb1ca084d36291390bbc54dc81027deYorke Lee            requestPermissions(new String[] {READ_CONTACTS}, 0);
47438019af70eb1ca084d36291390bbc54dc81027deYorke Lee        } else {
47538019af70eb1ca084d36291390bbc54dc81027deYorke Lee            // Switch tabs
47638019af70eb1ca084d36291390bbc54dc81027deYorke Lee            ((HostInterface) activity).showAllContactsTab();
47738019af70eb1ca084d36291390bbc54dc81027deYorke Lee        }
47838019af70eb1ca084d36291390bbc54dc81027deYorke Lee    }
4796b049128c51b90e17ae14856d98130a22d3a5433Yorke Lee}
480