PhoneFavoritesTileAdapter.java revision d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672
1dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee/* 2dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Copyright (C) 2013 The Android Open Source Project 3dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 4dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Licensed under the Apache License, Version 2.0 (the "License"); 5dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * you may not use this file except in compliance with the License. 6dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * You may obtain a copy of the License at 7dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 8dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * http://www.apache.org/licenses/LICENSE-2.0 9dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 10dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Unless required by applicable law or agreed to in writing, software 11dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * distributed under the License is distributed on an "AS IS" BASIS, 12dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * See the License for the specific language governing permissions and 14dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * limitations under the License. 15dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 16dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leepackage com.android.dialer.list; 17dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 183ce60186f646b461635b16d7d9a806ddc0b61bacYorke Leeimport com.google.common.annotations.VisibleForTesting; 193ce60186f646b461635b16d7d9a806ddc0b61bacYorke Leeimport com.google.common.collect.ComparisonChain; 203ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee 21dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.ContentUris; 2255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport android.content.ContentValues; 23dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.Context; 24dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.res.Resources; 25dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.database.Cursor; 26dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.net.Uri; 27dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone; 28dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.provider.ContactsContract.Contacts; 2955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport android.provider.ContactsContract.PinnedPositions; 304e741192ec40278d9189b46cf2ae6bc547d9071dYorke Leeimport android.text.TextUtils; 31dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.util.Log; 324e741192ec40278d9189b46cf2ae6bc547d9071dYorke Leeimport android.util.LongSparseArray; 3311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Leeimport android.view.MotionEvent; 34dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.view.View; 3511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Leeimport android.view.ViewConfiguration; 36dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.view.ViewGroup; 37dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.widget.BaseAdapter; 38dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.widget.FrameLayout; 39dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 40dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.ContactPhotoManager; 41dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.ContactTileLoaderFactory; 42dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.R; 43dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactEntry; 4455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport com.android.contacts.common.list.ContactTileAdapter.DisplayType; 45dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactTileView; 4611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Leeimport com.android.dialer.list.SwipeHelper.OnItemGestureListener; 4711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Leeimport com.android.dialer.list.SwipeHelper.SwipeHelperCallback; 4855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 49dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport java.util.ArrayList; 5055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport java.util.Comparator; 5155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport java.util.LinkedList; 5255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport java.util.List; 5355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Leeimport java.util.PriorityQueue; 54dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 55dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee/** 56dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Also allows for a configurable number of columns as well as a maximum row of tiled contacts. 57dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 58dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * This adapter has been rewritten to only support a maximum of one row for favorites. 59dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 60dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 6111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Leepublic class PhoneFavoritesTileAdapter extends BaseAdapter implements 62d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee SwipeHelper.OnItemGestureListener, OnDragDropListener { 63316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private static final String TAG = PhoneFavoritesTileAdapter.class.getSimpleName(); 64316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private static final boolean DEBUG = false; 65dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 663ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee public static final int NO_ROW_LIMIT = -1; 673ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee 683ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee public static final int ROW_LIMIT_DEFAULT = NO_ROW_LIMIT; 69dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 70dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private ContactTileView.Listener mListener; 71c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee private OnDataSetChangedForAnimationListener mDataSetChangedListener; 72c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee 73dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private Context mContext; 74dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private Resources mResources; 75316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 76316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** Contact data stored in cache. This is used to populate the associated view. */ 77316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen protected ArrayList<ContactEntry> mContactEntries = null; 78316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** Back up of the temporarily removed Contact during dragging. */ 79316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private ContactEntry mDraggedEntry = null; 80316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** Position of the temporarily removed contact in the cache. */ 81316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private int mDraggedEntryIndex = -1; 82316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** New position of the temporarily removed contact in the cache. */ 83316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private int mDropEntryIndex = -1; 8472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang /** New position of the temporarily entered contact in the cache. */ 8572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang private int mDragEnteredEntryIndex = -1; 86316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** Position of the contact pending removal. */ 87316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private int mPotentialRemoveEntryIndex = -1; 88c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee private long mIdToKeepInPlace = -1; 89316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 905a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee private boolean mAwaitingRemove = false; 9161fe032af12ad13bba18eb7a807112a59e1e4776Yorke Lee private boolean mDelayCursorUpdates = false; 925a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee 93dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private ContactPhotoManager mPhotoManager; 94dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mNumFrequents; 956a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee protected int mNumStarred; 96dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 97dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mColumnCount; 986a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee private int mMaxTiledRows = ROW_LIMIT_DEFAULT; 99dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int mStarredIndex; 100dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 101dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mIdIndex; 102dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mLookupIndex; 103dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mPhotoUriIndex; 104dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mNameIndex; 105dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mPresenceIndex; 106dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int mStatusIndex; 107dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 108dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int mPhoneNumberIndex; 109dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int mPhoneNumberTypeIndex; 110dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int mPhoneNumberLabelIndex; 11143f543900efac8edc10159851184da8cfca3d81aYorke Lee private int mIsDefaultNumberIndex; 11255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee protected int mPinnedIndex; 113791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee protected int mContactIdIndex; 114dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 115dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private final int mPaddingInPixels; 116dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 117316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** Indicates whether a drag is in process. */ 118316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private boolean mInDragging = false; 119316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 12072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang public static final int PIN_LIMIT = 20; 12155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 122d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang /** 123d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang * The soft limit on how many contact tiles to show. 124d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang * NOTE This soft limit would not restrict the number of starred contacts to show, rather 125d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang * 1. If the count of starred contacts is less than this limit, show 20 tiles total. 126d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang * 2. If the count of starred contacts is more than or equal to this limit, 127d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang * show all starred tiles and no frequents. 128d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang */ 129d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang private static final int TILES_SOFT_LIMIT = 20; 130d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang 13155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final Comparator<ContactEntry> mContactEntryComparator = new Comparator<ContactEntry>() { 13255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee @Override 13355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee public int compare(ContactEntry lhs, ContactEntry rhs) { 13455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee return ComparisonChain.start() 13555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee .compare(lhs.pinned, rhs.pinned) 13655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee .compare(lhs.name, rhs.name) 13755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee .result(); 13855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 13955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee }; 14055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 141c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee public interface OnDataSetChangedForAnimationListener { 142c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee public void onDataSetChangedForAnimation(long... idsInPlace); 143c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee public void cacheOffsetsForDatasetChange(); 144c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee }; 145dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 146316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener, 147c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee OnDataSetChangedForAnimationListener dataSetChangedListener, 148316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen int numCols, int maxTiledRows) { 149c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mDataSetChangedListener = dataSetChangedListener; 150dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mListener = listener; 151dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mContext = context; 152dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mResources = context.getResources(); 153dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mColumnCount = numCols; 154dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mNumFrequents = 0; 155dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mMaxTiledRows = maxTiledRows; 156316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mContactEntries = new ArrayList<ContactEntry>(); 157dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Converting padding in dips to padding in pixels 158dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPaddingInPixels = mContext.getResources() 1593ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee .getDimensionPixelSize(R.dimen.contact_tile_divider_width); 160316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 161dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee bindColumnIndices(); 162dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 163dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 164dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public void setPhotoLoader(ContactPhotoManager photoLoader) { 165dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPhotoManager = photoLoader; 166dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 167dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 168dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public void setMaxRowCount(int maxRows) { 169dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mMaxTiledRows = maxRows; 170dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 171dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 172dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public void setColumnCount(int columnCount) { 173dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mColumnCount = columnCount; 174dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 175dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 176dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 177316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Indicates whether a drag is in process. 178316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 179316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param inDragging Boolean variable indicating whether there is a drag in process. 180316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 181316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void setInDragging(boolean inDragging) { 18261fe032af12ad13bba18eb7a807112a59e1e4776Yorke Lee mDelayCursorUpdates = inDragging; 183316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mInDragging = inDragging; 184316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 185316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 186316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** Gets whether the drag is in process. */ 187316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public boolean getInDragging() { 188316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return mInDragging; 189316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 190316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 191316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 192dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Sets the column indices for expected {@link Cursor} 193dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * based on {@link DisplayType}. 194dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 195dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected void bindColumnIndices() { 196dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mIdIndex = ContactTileLoaderFactory.CONTACT_ID; 197dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mLookupIndex = ContactTileLoaderFactory.LOOKUP_KEY; 198dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPhotoUriIndex = ContactTileLoaderFactory.PHOTO_URI; 199dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mNameIndex = ContactTileLoaderFactory.DISPLAY_NAME; 200dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mStarredIndex = ContactTileLoaderFactory.STARRED; 201dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE; 202dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS; 203dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 204dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER; 205dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE; 206dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL; 20743f543900efac8edc10159851184da8cfca3d81aYorke Lee mIsDefaultNumberIndex = ContactTileLoaderFactory.IS_DEFAULT_NUMBER; 20855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee mPinnedIndex = ContactTileLoaderFactory.PINNED; 209791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee mContactIdIndex = ContactTileLoaderFactory.CONTACT_ID_FOR_DATA; 210dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 211dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 212dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 213dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Gets the number of frequents from the passed in cursor. 214dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 215dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * This methods is needed so the GroupMemberTileAdapter can override this. 216dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 217dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * @param cursor The cursor to get number of frequents from. 218dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 219dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected void saveNumFrequentsFromCursor(Cursor cursor) { 2206a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee mNumFrequents = cursor.getCount() - mNumStarred; 221dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 222dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 223dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 224dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Creates {@link ContactTileView}s for each item in {@link Cursor}. 225dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 226dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Else use {@link ContactTileLoaderFactory} 227dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 228dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public void setContactCursor(Cursor cursor) { 22961fe032af12ad13bba18eb7a807112a59e1e4776Yorke Lee if (!mDelayCursorUpdates && cursor != null && !cursor.isClosed()) { 230316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mNumStarred = getNumStarredContacts(cursor); 231c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee if (mAwaitingRemove) { 232c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mDataSetChangedListener.cacheOffsetsForDatasetChange(); 233c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 234c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee 235316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen saveNumFrequentsFromCursor(cursor); 236316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen saveCursorToCache(cursor); 237316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen // cause a refresh of any views that rely on this data 238316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen notifyDataSetChanged(); 239c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee // about to start redraw 240c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee if (mIdToKeepInPlace != -1) { 241c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mDataSetChangedListener.onDataSetChangedForAnimation(mIdToKeepInPlace); 242c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } else { 243c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mDataSetChangedListener.onDataSetChangedForAnimation(); 244c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 245c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mIdToKeepInPlace = -1; 246316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 247316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 248dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 249316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 250316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Saves the cursor data to the cache, to speed up UI changes. 251316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 252316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param cursor Returned cursor with data to populate the view. 253316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 254316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private void saveCursorToCache(Cursor cursor) { 255316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mContactEntries.clear(); 25655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 257443d758d53d1f7ebb12e8ed39fc6195c9d5ed18dYorke Lee cursor.moveToPosition(-1); 25855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 2594e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final LongSparseArray<Object> duplicates = new LongSparseArray<Object>(cursor.getCount()); 260443d758d53d1f7ebb12e8ed39fc6195c9d5ed18dYorke Lee 261d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang // Track the length of {@link #mContactEntries} and compare to {@link #TILES_SOFT_LIMIT}. 262d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang int counter = 0; 263d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang 2644e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee while (cursor.moveToNext()) { 2654e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee 2664e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final int starred = cursor.getInt(mStarredIndex); 2674e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final long id; 26855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 269791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee // We display a maximum of TILES_SOFT_LIMIT contacts, or the total number of starred 270791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee // whichever is greater. 271791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee if (starred < 1 && counter >= TILES_SOFT_LIMIT) { 272d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang break; 27355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } else { 274791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee id = cursor.getLong(mContactIdIndex); 27555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 2764e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee 27743f543900efac8edc10159851184da8cfca3d81aYorke Lee final ContactEntry existing = (ContactEntry) duplicates.get(id); 27843f543900efac8edc10159851184da8cfca3d81aYorke Lee if (existing != null) { 27943f543900efac8edc10159851184da8cfca3d81aYorke Lee // Check if the existing number is a default number. If not, clear the phone number 28043f543900efac8edc10159851184da8cfca3d81aYorke Lee // and label fields so that the disambiguation dialog will show up. 28143f543900efac8edc10159851184da8cfca3d81aYorke Lee if (!existing.isDefaultNumber) { 28243f543900efac8edc10159851184da8cfca3d81aYorke Lee existing.phoneLabel = null; 28343f543900efac8edc10159851184da8cfca3d81aYorke Lee existing.phoneNumber = null; 28443f543900efac8edc10159851184da8cfca3d81aYorke Lee } 2854e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee continue; 2864e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee } 2874e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee 2884e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final String photoUri = cursor.getString(mPhotoUriIndex); 2894e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final String lookupKey = cursor.getString(mLookupIndex); 2904e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final int pinned = cursor.getInt(mPinnedIndex); 2914e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final String name = cursor.getString(mNameIndex); 2929bead9c01ab09ebfbd1c2be8555d8c8d4e3cf6bdChristine Chen final boolean isStarred = cursor.getInt(mStarredIndex) > 0; 29343f543900efac8edc10159851184da8cfca3d81aYorke Lee final boolean isDefaultNumber = cursor.getInt(mIsDefaultNumberIndex) > 0; 2944e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee 2954e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee final ContactEntry contact = new ContactEntry(); 2964e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee 2974e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee contact.id = id; 2984e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee contact.name = (!TextUtils.isEmpty(name)) ? name : 2994e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee mResources.getString(R.string.missing_name); 300443d758d53d1f7ebb12e8ed39fc6195c9d5ed18dYorke Lee contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null); 301443d758d53d1f7ebb12e8ed39fc6195c9d5ed18dYorke Lee contact.lookupKey = ContentUris.withAppendedId( 302443d758d53d1f7ebb12e8ed39fc6195c9d5ed18dYorke Lee Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id); 3039bead9c01ab09ebfbd1c2be8555d8c8d4e3cf6bdChristine Chen contact.isFavorite = isStarred; 30443f543900efac8edc10159851184da8cfca3d81aYorke Lee contact.isDefaultNumber = isDefaultNumber; 3054e741192ec40278d9189b46cf2ae6bc547d9071dYorke Lee 30643f543900efac8edc10159851184da8cfca3d81aYorke Lee // Set phone number and label 307791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee final int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex); 308791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee final String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex); 309791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee contact.phoneLabel = (String) Phone.getTypeLabel(mResources, phoneNumberType, 310791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee phoneNumberCustomLabel); 311791082e22b50db98de6749bb5ef878d3ec483e28Yorke Lee contact.phoneNumber = cursor.getString(mPhoneNumberIndex); 31255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 31355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee contact.pinned = pinned; 314443d758d53d1f7ebb12e8ed39fc6195c9d5ed18dYorke Lee mContactEntries.add(contact); 315d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang 31643f543900efac8edc10159851184da8cfca3d81aYorke Lee duplicates.put(id, contact); 31743f543900efac8edc10159851184da8cfca3d81aYorke Lee 318d954cd76c610e8fafd91aec857f4232ab49ef2cdHongwei Wang counter++; 319316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 32055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 3215a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee mAwaitingRemove = false; 3225a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee 32355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee arrangeContactsByPinnedPosition(mContactEntries); 32455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 32555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee notifyDataSetChanged(); 326dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 327dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 328dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 329dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Iterates over the {@link Cursor} 330dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Returns position of the first NON Starred Contact 331dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Returns -1 if {@link DisplayType#STARRED_ONLY} 332dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Returns 0 if {@link DisplayType#FREQUENT_ONLY} 333dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 3346a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee protected int getNumStarredContacts(Cursor cursor) { 335dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee cursor.moveToPosition(-1); 336dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee while (cursor.moveToNext()) { 337dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee if (cursor.getInt(mStarredIndex) == 0) { 338dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return cursor.getPosition(); 339dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 340dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 341dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 342dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // There are not NON Starred contacts in cursor 343dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Set divider positon to end 344dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return cursor.getCount(); 345dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 346dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 347316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 348316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Loads a contact from the cached list. 349316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 350316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param position Position of the Contact. 351316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @return Contact at the requested position. 352316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 353316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen protected ContactEntry getContactEntryFromCache(int position) { 354316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen if (mContactEntries.size() <= position) return null; 355316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return mContactEntries.get(position); 356dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 357dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 358dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 359dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Returns the number of frequents that will be displayed in the list. 360dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 361dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public int getNumFrequents() { 362dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return mNumFrequents; 363dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 364dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 365dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 366dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public int getCount() { 367c1e769c16792a880ac803b912851d6d258ed4550Yorke Lee if (mContactEntries == null || mContactEntries.isEmpty()) { 3684fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen return 0; 369dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 370dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 37163b92b5f2cc4d4099aed4c6d10cd24e1389e7a44Yorke Lee int total = mContactEntries.size(); 372c1e769c16792a880ac803b912851d6d258ed4550Yorke Lee // The number of contacts that don't show up as tiles 373c1e769c16792a880ac803b912851d6d258ed4550Yorke Lee final int nonTiledRows = Math.max(0, total - getMaxContactsInTiles()); 374c1e769c16792a880ac803b912851d6d258ed4550Yorke Lee // The number of tiled rows 375c1e769c16792a880ac803b912851d6d258ed4550Yorke Lee final int tiledRows = getRowCount(total - nonTiledRows); 376c1e769c16792a880ac803b912851d6d258ed4550Yorke Lee return nonTiledRows + tiledRows; 377dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 378dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 3795fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee public int getMaxTiledRows() { 3805fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee return mMaxTiledRows; 3815fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee } 3825fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee 383dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 384dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Returns the number of rows required to show the provided number of entries 385dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * with the current number of columns. 386dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 387dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected int getRowCount(int entryCount) { 388dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee if (entryCount == 0) return 0; 389dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final int nonLimitedRows = ((entryCount - 1) / mColumnCount) + 1; 3903ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee if (mMaxTiledRows == NO_ROW_LIMIT) { 3913ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee return nonLimitedRows; 3923ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee } 3936a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee return Math.min(mMaxTiledRows, nonLimitedRows); 3946a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee } 3956a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee 3966a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee private int getMaxContactsInTiles() { 3973ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee if (mMaxTiledRows == NO_ROW_LIMIT) { 3983ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee return Integer.MAX_VALUE; 3993ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee } 4006a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee return mColumnCount * mMaxTiledRows; 401dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 402dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 4035b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang public int getRowIndex(int entryIndex) { 4043ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee if (entryIndex < getMaxContactsInTiles()) { 405316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return entryIndex / mColumnCount; 406316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } else { 4073ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee return entryIndex - mMaxTiledRows * (mColumnCount + 1); 408316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 409316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 410316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 411dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public int getColumnCount() { 412dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return mColumnCount; 413dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 414dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 415dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 416dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Returns an ArrayList of the {@link ContactEntry}s that are to appear 417dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * on the row for the given position. 418dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 419dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 420dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public ArrayList<ContactEntry> getItem(int position) { 421dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>(mColumnCount); 42211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 42311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final int entryIndex = getFirstContactEntryIndexForPosition(position); 42411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 42511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final int viewType = getItemViewType(position); 42611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 42711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final int columnCount; 42811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (viewType == ViewTypes.TOP) { 42911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee columnCount = mColumnCount; 43011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } else { 43111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee columnCount = 1; 43211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 43311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 43411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee for (int i = 0; i < columnCount; i++) { 43511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final ContactEntry entry = getContactEntryFromCache(entryIndex + i); 43611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (entry == null) break; // less than mColumnCount contacts 43711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee resultList.add(entry); 43811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 43911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 44011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return resultList; 44111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 44211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 44311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee /* 44411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee * Given a position in the adapter, returns the index of the first contact entry that is to be 44511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee * in that row. 44611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee */ 44711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee private int getFirstContactEntryIndexForPosition(int position) { 4486a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee final int maxContactsInTiles = getMaxContactsInTiles(); 4496a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee if (position < getRowCount(maxContactsInTiles)) { 4506a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee // Contacts that appear as tiles 45111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return position * mColumnCount; 452dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } else { 4536a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee // Contacts that appear as rows 4546a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee // The actual position of the contact in the cursor is simply total the number of 4556a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee // tiled contacts + the given position 4562a066fed83f99c26a0e64a7c25fd72385bbc6568Yorke Lee return maxContactsInTiles + position - mMaxTiledRows; 457dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 458dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 459dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 460c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee /** 461c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee * For the top row of tiled contacts, the item id is the position of the row of 462c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee * contacts. 463c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee * For frequent contacts, the item id is the maximum number of rows of tiled contacts + 464c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee * the actual contact id. Since contact ids are always greater than 0, this guarantees that 465c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee * all items within this adapter will always have unique ids. 466c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee */ 467dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 468dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public long getItemId(int position) { 469c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee if (getItemViewType(position) == ViewTypes.FREQUENT) { 470c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee return getAdjustedItemId(getItem(position).get(0).id); 471c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } else { 472c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee return position; 473c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 474c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 475c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee 476c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee /** 4773ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee * Calculates the stable itemId for a particular entry based on the entry's contact ID. This 4783ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee * stable itemId is used for animation purposes. 479c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee */ 480c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee public long getAdjustedItemId(long id) { 4813ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee if (mMaxTiledRows == NO_ROW_LIMIT) { 4823ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee return id; 4833ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee } 484c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee return mMaxTiledRows + id; 485c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 486c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee 487c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee @Override 488c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee public boolean hasStableIds() { 489c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee return true; 490dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 491dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 492dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 493dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public boolean areAllItemsEnabled() { 494dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // No dividers, so all items are enabled. 495dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return true; 496dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 497dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 498dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 499dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public boolean isEnabled(int position) { 5004fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen return getCount() > 0; 501dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 502dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 503dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 504316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void notifyDataSetChanged() { 505316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen if (DEBUG) { 50655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee Log.v(TAG, "notifyDataSetChanged"); 507316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 508316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen super.notifyDataSetChanged(); 509316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 510316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 511316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen @Override 512dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public View getView(int position, View convertView, ViewGroup parent) { 51355d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee if (DEBUG) { 51455d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee Log.v(TAG, "get view for " + String.valueOf(position)); 51555d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee } 51618e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee 517dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee int itemViewType = getItemViewType(position); 518dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 5191f06f0ad1229f3b4e00553c294e664ffa5234c90Christine Chen ContactTileRow contactTileRowView = null; 5201f06f0ad1229f3b4e00553c294e664ffa5234c90Christine Chen 5211f06f0ad1229f3b4e00553c294e664ffa5234c90Christine Chen if (convertView instanceof ContactTileRow) { 5221f06f0ad1229f3b4e00553c294e664ffa5234c90Christine Chen contactTileRowView = (ContactTileRow) convertView; 5231f06f0ad1229f3b4e00553c294e664ffa5234c90Christine Chen } 5246091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen 525dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee ArrayList<ContactEntry> contactList = getItem(position); 526dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 527dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee if (contactTileRowView == null) { 528dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Creating new row if needed 529316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen contactTileRowView = new ContactTileRow(mContext, itemViewType, position); 530dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 531dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 532316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen contactTileRowView.configureRow(contactList, position, position == getCount() - 1); 533316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 534dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return contactTileRowView; 535dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 536dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 537dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int getLayoutResourceId(int viewType) { 538dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee switch (viewType) { 539dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee case ViewTypes.FREQUENT: 540dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return R.layout.phone_favorite_regular_row_view; 541d99993213962df64c9d76005df86c2fb83fca074Yorke Lee case ViewTypes.TOP: 542dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return R.layout.phone_favorite_tile_view; 543dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee default: 544dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee throw new IllegalArgumentException("Unrecognized viewType " + viewType); 545dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 546dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 547dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 548dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public int getViewTypeCount() { 549dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return ViewTypes.COUNT; 550dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 551dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 552dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 553dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee public int getItemViewType(int position) { 5543ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee if (position < getMaxContactsInTiles()) { 555d99993213962df64c9d76005df86c2fb83fca074Yorke Lee return ViewTypes.TOP; 556dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } else { 557dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return ViewTypes.FREQUENT; 558dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 559dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 560dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 561dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 562316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Temporarily removes a contact from the list for UI refresh. Stores data for this contact 563316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * in the back-up variable. 564316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 565316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param index Position of the contact to be removed. 566316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 567316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void popContactEntry(int index) { 56872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang if (isIndexInBound(index)) { 569316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDraggedEntry = mContactEntries.get(index); 570316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDraggedEntryIndex = index; 57172418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mDragEnteredEntryIndex = index; 57272418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang markDropArea(mDragEnteredEntryIndex); 57372418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 57472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 57572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang 57672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang /** 57772418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * @param itemIndex Position of the contact in {@link #mContactEntries}. 57872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * @return True if the given index is valid for {@link #mContactEntries}. 57972418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang */ 58072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang private boolean isIndexInBound(int itemIndex) { 58172418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang return itemIndex >= 0 && itemIndex < mContactEntries.size(); 58272418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 58372418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang 58472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang /** 58572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * Mark the tile as drop area by given the item index in {@link #mContactEntries}. 58672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * 58772418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * @param itemIndex Position of the contact in {@link #mContactEntries}. 58872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang */ 58972418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang private void markDropArea(int itemIndex) { 59072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang if (isIndexInBound(mDragEnteredEntryIndex) && isIndexInBound(itemIndex)) { 5915b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang mDataSetChangedListener.cacheOffsetsForDatasetChange(); 59272418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang // Remove the old placeholder item and place the new placeholder item. 5935b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang final int oldIndex = mDragEnteredEntryIndex; 59472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.remove(mDragEnteredEntryIndex); 59572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mDragEnteredEntryIndex = itemIndex; 59672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.add(mDragEnteredEntryIndex, ContactEntry.BLANK_ENTRY); 59772418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang ContactEntry.BLANK_ENTRY.id = mDraggedEntry.id; 5985b2e21098d84e94fd629e5e07c3bbb66bf9b5d95Hongwei Wang mDataSetChangedListener.onDataSetChangedForAnimation(); 599316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen notifyDataSetChanged(); 600316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 601316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 602316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 603316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 604316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Drops the temporarily removed contact to the desired location in the list. 605316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 60672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang public void handleDrop() { 60755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee boolean changed = false; 608316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen if (mDraggedEntry != null) { 6094911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang if (isIndexInBound(mDragEnteredEntryIndex) && 6104911300ae3fa7ab186ee271f8bc431b65a819a3cHongwei Wang mDragEnteredEntryIndex != mDraggedEntryIndex) { 61155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // Don't add the ContactEntry here (to prevent a double animation from occuring). 61255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // When we receive a new cursor the list of contact entries will automatically be 61355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // populated with the dragged ContactEntry at the correct spot. 61472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mDropEntryIndex = mDragEnteredEntryIndex; 61572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.set(mDropEntryIndex, mDraggedEntry); 616c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mIdToKeepInPlace = getAdjustedItemId(mDraggedEntry.id); 617c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee mDataSetChangedListener.cacheOffsetsForDatasetChange(); 61855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee changed = true; 61972418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } else if (isIndexInBound(mDraggedEntryIndex)) { 62072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang // If {@link #mDragEnteredEntryIndex} is invalid, 62172418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang // falls back to the original position of the contact. 62272418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.remove(mDragEnteredEntryIndex); 62372418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.add(mDraggedEntryIndex, mDraggedEntry); 624316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDropEntryIndex = mDraggedEntryIndex; 62555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee notifyDataSetChanged(); 62655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 62755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 62855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee if (changed && mDropEntryIndex < PIN_LIMIT) { 62955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final ContentValues cv = getReflowedPinnedPositions(mContactEntries, mDraggedEntry, 63055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee mDraggedEntryIndex, mDropEntryIndex); 6319bead9c01ab09ebfbd1c2be8555d8c8d4e3cf6bdChristine Chen final Uri pinUri = PinnedPositions.UPDATE_URI.buildUpon().build(); 63255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // update the database here with the new pinned positions 63355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee mContext.getContentResolver().update(pinUri, cv, null, null); 634316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 635316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDraggedEntry = null; 636316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 637316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 638316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 639316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 64001f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen * Invoked when the dragged item is dropped to unsupported location. We will then move the 64101f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen * contact back to where it was dragged from. 64201f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen */ 64301f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen public void dropToUnsupportedView() { 64472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang if (isIndexInBound(mDragEnteredEntryIndex)) { 64572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.remove(mDragEnteredEntryIndex); 64672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mContactEntries.add(mDraggedEntryIndex, mDraggedEntry); 64772418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang notifyDataSetChanged(); 64872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 64901f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen } 65001f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen 65101f15ad65dfbc72d7c8f165bda8e602ba287b434Christine Chen /** 652316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Sets an item to for pending removal. If the user does not click the undo button, the item 653316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * will be removed at the next interaction. 654316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 655316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param index Index of the item to be removed. 656316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 657316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void setPotentialRemoveEntryIndex(int index) { 658316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mPotentialRemoveEntryIndex = index; 659316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 660316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 661316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 66255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * Removes a contact entry from the list. 663316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 664316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @return True is an item is removed. False is there is no item to be removed. 665316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 66611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public boolean removePendingContactEntry() { 66711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee boolean removed = false; 66872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang if (isIndexInBound(mPotentialRemoveEntryIndex)) { 669c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee final ContactEntry entry = mContactEntries.get(mPotentialRemoveEntryIndex); 67055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee unstarAndUnpinContact(entry.lookupKey); 67111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee removed = true; 6725a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee mAwaitingRemove = true; 673316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 67411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee cleanTempVariables(); 67511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return removed; 676316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 677316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 678316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 679316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Resets the item for pending removal. 680316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 681316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void undoPotentialRemoveEntryIndex() { 682316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mPotentialRemoveEntryIndex = -1; 683316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 684316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 68552112414bcc95394e537185316168dcdc943544fYorke Lee public boolean hasPotentialRemoveEntryIndex() { 68652112414bcc95394e537185316168dcdc943544fYorke Lee return isIndexInBound(mPotentialRemoveEntryIndex); 68752112414bcc95394e537185316168dcdc943544fYorke Lee } 68852112414bcc95394e537185316168dcdc943544fYorke Lee 689316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 690316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Clears all temporary variables at a new interaction. 691316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 692316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void cleanTempVariables() { 693316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDraggedEntryIndex = -1; 694316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDropEntryIndex = -1; 69572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mDragEnteredEntryIndex = -1; 696316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mDraggedEntry = null; 697316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mPotentialRemoveEntryIndex = -1; 698316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 699316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 700316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 701dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Acts as a row item composed of {@link ContactTileView} 702dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * 703dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 70411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public class ContactTileRow extends FrameLayout implements SwipeHelperCallback { 70511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public static final int CONTACT_ENTRY_INDEX_TAG = R.id.contact_entry_index_tag; 70611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 707dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int mItemViewType; 708dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private int mLayoutResId; 709d99993213962df64c9d76005df86c2fb83fca074Yorke Lee private final int mRowPaddingStart; 710d99993213962df64c9d76005df86c2fb83fca074Yorke Lee private final int mRowPaddingEnd; 711d99993213962df64c9d76005df86c2fb83fca074Yorke Lee private final int mRowPaddingTop; 712d99993213962df64c9d76005df86c2fb83fca074Yorke Lee private final int mRowPaddingBottom; 7133ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee private final float mHeightToWidthRatio; 714316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen private int mPosition; 71511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee private SwipeHelper mSwipeHelper; 71611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee private OnItemGestureListener mOnItemSwipeListener; 717dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 718316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public ContactTileRow(Context context, int itemViewType, int position) { 719dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee super(context); 720dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mItemViewType = itemViewType; 721dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee mLayoutResId = getLayoutResourceId(mItemViewType); 722316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mPosition = position; 723dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 724d99993213962df64c9d76005df86c2fb83fca074Yorke Lee final Resources resources = mContext.getResources(); 725ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee 7263ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee mHeightToWidthRatio = getResources().getFraction( 7273ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee R.dimen.contact_tile_height_to_width_ratio, 1, 1); 7283ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee 729ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee if (mItemViewType == ViewTypes.TOP) { 730ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee // For tiled views, we still want padding to be set on the ContactTileRow. 731ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee // Otherwise the padding would be set around each of the tiles, which we don't want 732ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingTop = resources.getDimensionPixelSize( 733ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee R.dimen.favorites_row_top_padding); 734ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingBottom = resources.getDimensionPixelSize( 735ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee R.dimen.favorites_row_bottom_padding); 736ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingStart = resources.getDimensionPixelSize( 737ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee R.dimen.favorites_row_start_padding); 738ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingEnd = resources.getDimensionPixelSize( 739ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee R.dimen.favorites_row_end_padding); 740ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee } else { 741ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee // For row views, padding is set on the view itself. 742ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingTop = 0; 743ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingBottom = 0; 744ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingStart = 0; 745ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee mRowPaddingEnd = 0; 746ba6b3366f21c47454b3ba5189e94bb6bf58fd11dYorke Lee } 747d99993213962df64c9d76005df86c2fb83fca074Yorke Lee 748d99993213962df64c9d76005df86c2fb83fca074Yorke Lee setPaddingRelative(mRowPaddingStart, mRowPaddingTop, mRowPaddingEnd, 749d99993213962df64c9d76005df86c2fb83fca074Yorke Lee mRowPaddingBottom); 750d99993213962df64c9d76005df86c2fb83fca074Yorke Lee 751dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Remove row (but not children) from accessibility node tree. 752dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); 75311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 75411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (mItemViewType == ViewTypes.FREQUENT) { 75511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // ListView handles swiping for this item 75611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee SwipeHelper.setSwipeable(this, true); 75711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } else if (mItemViewType == ViewTypes.TOP) { 75811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // The contact tile row has its own swipe helpers, that makes each individual 75911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // tile swipeable. 76011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final float densityScale = getResources().getDisplayMetrics().density; 76111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final float pagingTouchSlop = ViewConfiguration.get(context) 76211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee .getScaledPagingTouchSlop(); 76311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, 76411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee pagingTouchSlop); 765362c4441b65f63dfc3cf933d569aba6e00dc168aHongwei Wang // Increase swipe thresholds for square tiles since they are relatively small. 766362c4441b65f63dfc3cf933d569aba6e00dc168aHongwei Wang mSwipeHelper.setChildSwipedFarEnoughFactor(0.9f); 767362c4441b65f63dfc3cf933d569aba6e00dc168aHongwei Wang mSwipeHelper.setChildSwipedFastEnoughFactor(0.1f); 76811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee mOnItemSwipeListener = PhoneFavoritesTileAdapter.this; 76911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 770dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 771dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 772dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee /** 773dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Configures the row to add {@link ContactEntry}s information to the views 774dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */ 775316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public void configureRow(ArrayList<ContactEntry> list, int position, boolean isLastRow) { 776dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee int columnCount = mItemViewType == ViewTypes.FREQUENT ? 1 : mColumnCount; 777316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen mPosition = position; 778dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 779dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Adding tiles to row and filling in contact information 780dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) { 781dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee ContactEntry entry = 782dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee columnCounter < list.size() ? list.get(columnCounter) : null; 783dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee addTileFromEntry(entry, columnCounter, isLastRow); 784dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 785c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee if (columnCount == 1) { 786c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee if (list.get(0) == ContactEntry.BLANK_ENTRY) { 787c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee setVisibility(View.INVISIBLE); 788c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } else { 789c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee setVisibility(View.VISIBLE); 790c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 791c36684277aa45085999284bfe71cb8be71b3a464Yorke Lee } 792dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 793dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 794dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private void addTileFromEntry(ContactEntry entry, int childIndex, boolean isLastRow) { 795316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen final PhoneFavoriteTileView contactTile; 796dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 797dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee if (getChildCount() <= childIndex) { 798dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 799316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen contactTile = (PhoneFavoriteTileView) inflate(mContext, mLayoutResId, null); 800dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Note: the layoutparam set here is only actually used for FREQUENT. 801dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // We override onMeasure() for STARRED and we don't care the layout param there. 802d99993213962df64c9d76005df86c2fb83fca074Yorke Lee final Resources resources = mContext.getResources(); 803dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( 804dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee ViewGroup.LayoutParams.WRAP_CONTENT, 805dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee ViewGroup.LayoutParams.WRAP_CONTENT); 806dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 807dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee params.setMargins( 808316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen resources.getDimensionPixelSize(R.dimen.detail_item_side_margin), 0, 809316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen resources.getDimensionPixelSize(R.dimen.detail_item_side_margin), 0); 810dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee contactTile.setLayoutParams(params); 811dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee contactTile.setPhotoManager(mPhotoManager); 812dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee contactTile.setListener(mListener); 813dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee addView(contactTile); 814dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } else { 815316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen contactTile = (PhoneFavoriteTileView) getChildAt(childIndex); 816dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 817dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee contactTile.loadFromContact(entry); 81811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 81911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee int entryIndex = -1; 820dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee switch (mItemViewType) { 821d99993213962df64c9d76005df86c2fb83fca074Yorke Lee case ViewTypes.TOP: 822dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Setting divider visibilities 823dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee contactTile.setPaddingRelative(0, 0, 824d99993213962df64c9d76005df86c2fb83fca074Yorke Lee childIndex >= mColumnCount - 1 ? 0 : mPaddingInPixels, 0); 82511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee entryIndex = getFirstContactEntryIndexForPosition(mPosition) + childIndex; 8266c2b2ec252f2a9788bb967c069740f5a1bdc495eYorke Lee SwipeHelper.setSwipeable(contactTile, false); 827dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee break; 828dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee case ViewTypes.FREQUENT: 829dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee contactTile.setHorizontalDividerVisibility( 830dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee isLastRow ? View.GONE : View.VISIBLE); 83111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee entryIndex = getFirstContactEntryIndexForPosition(mPosition); 83211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee SwipeHelper.setSwipeable(this, true); 833dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee break; 834dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee default: 835dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee break; 836dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 83711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // tag the tile with the index of the contact entry it is associated with 83811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (entryIndex != -1) { 83911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee contactTile.setTag(CONTACT_ENTRY_INDEX_TAG, entryIndex); 84011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 841316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen contactTile.setupFavoriteContactCard(); 842dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 843dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 844dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 845dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 846dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee switch (mItemViewType) { 847d99993213962df64c9d76005df86c2fb83fca074Yorke Lee case ViewTypes.TOP: 848dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee onLayoutForTiles(); 849dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return; 850dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee default: 851dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee super.onLayout(changed, left, top, right, bottom); 852dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return; 853dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 854dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 855dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 856dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private void onLayoutForTiles() { 857dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final int count = getChildCount(); 858dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 859dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Just line up children horizontally. 860d99993213962df64c9d76005df86c2fb83fca074Yorke Lee int childLeft = getPaddingStart(); 861dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee for (int i = 0; i < count; i++) { 862dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final View child = getChildAt(i); 863dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 864dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Note MeasuredWidth includes the padding. 865dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final int childWidth = child.getMeasuredWidth(); 8662a066fed83f99c26a0e64a7c25fd72385bbc6568Yorke Lee child.layout(childLeft, getPaddingTop(), childLeft + childWidth, 8672a066fed83f99c26a0e64a7c25fd72385bbc6568Yorke Lee getPaddingTop() + child.getMeasuredHeight()); 868dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee childLeft += childWidth; 869dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 870dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 871dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 872dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee @Override 873dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 874dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee switch (mItemViewType) { 875d99993213962df64c9d76005df86c2fb83fca074Yorke Lee case ViewTypes.TOP: 876dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee onMeasureForTiles(widthMeasureSpec); 877dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return; 878dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee default: 879dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee super.onMeasure(widthMeasureSpec, heightMeasureSpec); 880dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return; 881dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 882dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 883dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 884dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee private void onMeasureForTiles(int widthMeasureSpec) { 885dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final int width = MeasureSpec.getSize(widthMeasureSpec); 886dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 887dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final int childCount = getChildCount(); 888dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee if (childCount == 0) { 889dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Just in case... 890dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee setMeasuredDimension(width, 0); 891dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee return; 892dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 893dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 894dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // 1. Calculate image size. 895dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // = ([total width] - [total padding]) / [child count] 896dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // 897dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // 2. Set it to width/height of each children. 898dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // If we have a remainder, some tiles will have 1 pixel larger width than its height. 899dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // 900dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // 3. Set the dimensions of itself. 901dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Let width = given width. 902dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Let height = image size + bottom paddding. 903dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 904d99993213962df64c9d76005df86c2fb83fca074Yorke Lee final int totalPaddingsInPixels = (mColumnCount - 1) * mPaddingInPixels 905d99993213962df64c9d76005df86c2fb83fca074Yorke Lee + mRowPaddingStart + mRowPaddingEnd; 906dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 907dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Preferred width / height for images (excluding the padding). 908dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // The actual width may be 1 pixel larger than this if we have a remainder. 9093ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee final int imageWidth = (width - totalPaddingsInPixels) / mColumnCount; 9103ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee final int remainder = width - (imageWidth * mColumnCount) - totalPaddingsInPixels; 9113ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee 9123ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee final int height = (int) (mHeightToWidthRatio * imageWidth); 913dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 914dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee for (int i = 0; i < childCount; i++) { 915dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee final View child = getChildAt(i); 9163ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee final int childWidth = imageWidth + child.getPaddingRight() 917dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee // Compensate for the remainder 918dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee + (i < remainder ? 1 : 0); 919dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee child.measure( 920dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), 9213ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) 922dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee ); 923dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 9243ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee setMeasuredDimension(width, height + getPaddingTop() + getPaddingBottom()); 925dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 926316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 927316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** 928316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * Gets the index of the item at the specified coordinates. 929316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * 930316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param itemX X-coordinate of the selected item. 931316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @param itemY Y-coordinate of the selected item. 932316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * @return Index of the selected item in the cached array. 933316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen */ 934316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public int getItemIndex(float itemX, float itemY) { 9353ce60186f646b461635b16d7d9a806ddc0b61bacYorke Lee if (mMaxTiledRows == NO_ROW_LIMIT || mPosition < mMaxTiledRows) { 936316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen if (DEBUG) { 937316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen Log.v(TAG, String.valueOf(itemX) + " " + String.valueOf(itemY)); 938316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 939316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen for (int i = 0; i < getChildCount(); ++i) { 940316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** If the row contains multiple tiles, checks each tile to see if the point 941316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * is contained in the tile. */ 942774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang final View child = getChildAt(i); 943774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang /** The coordinates passed in are based on the ListView, 944774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang * translate for each child first */ 945774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang final int xInListView = child.getLeft() + getLeft(); 946774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang final int yInListView = child.getTop() + getTop(); 947774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang final int distanceX = (int) itemX - xInListView; 948774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang final int distanceY = (int) itemY - yInListView; 949774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang if ((distanceX > 0 && distanceX < child.getWidth()) && 950774206bc2d92d542a2a064e0a0b1718418d3044fHongwei Wang (distanceY > 0 && distanceY < child.getHeight())) { 951316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** If the point is contained in the rectangle, computes the index of the 952316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen * item in the cached array. */ 953316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return i + (mPosition) * mColumnCount; 954316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 955316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 956316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } else { 957316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen /** If the selected item is one of the rows, compute the index. */ 95872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang return getRegularRowItemIndex(); 959316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 960316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return -1; 961316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 962316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 96372418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang /** 96472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * Gets the index of the regular row item. 96572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * 96672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang * @return Index of the selected item in the cached array. 96772418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang */ 96872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang public int getRegularRowItemIndex() { 96972418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang return (mPosition - mMaxTiledRows) + mColumnCount * mMaxTiledRows; 97072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 97172418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang 972316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public PhoneFavoritesTileAdapter getTileAdapter() { 973316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return PhoneFavoritesTileAdapter.this; 974316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 975316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen 976316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen public int getPosition() { 977316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen return mPosition; 978316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen } 97911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 980f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang /** 981f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang * Find the view under the pointer. 982f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang */ 983f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang public View getViewAtPosition(int x, int y) { 98411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // find the view under the pointer, accounting for GONE views 98511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final int count = getChildCount(); 986f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang View view; 98711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee for (int childIdx = 0; childIdx < count; childIdx++) { 988f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang view = getChildAt(childIdx); 989f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang if (x >= view.getLeft() && x <= view.getRight()) { 990f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang return view; 99111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 99211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 99311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return null; 99411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 99511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 99611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 997f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang public View getChildAtPosition(MotionEvent ev) { 998f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang final View view = getViewAtPosition((int) ev.getX(), (int) ev.getY()); 999f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang if (view != null && 1000f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang SwipeHelper.isSwipeable(view) && 1001f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang view.getVisibility() != GONE) { 1002f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang // If this view is swipable, then return it. If not, because the removal 1003f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang // dialog is currently showing, then return a null view, which will simply 1004f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang // be ignored by the swipe helper. 1005f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang return view; 1006f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang } 1007f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang return null; 1008f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang } 1009f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang 1010f796309c9492475cc1911d22fda5319d6d4c4853Hongwei Wang @Override 101111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public View getChildContentView(View v) { 101211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return v.findViewById(R.id.contact_favorite_card); 101311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 101411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 101511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 101611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void onScroll() {} 101711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 101811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 101911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public boolean canChildBeDismissed(View v) { 102011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return true; 102111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 102211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 102311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 102411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void onBeginDrag(View v) { 102511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee removePendingContactEntry(); 102611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final int index = indexOfChild(v); 1027a2bdac8d96eaed2dacea274c55036ca9c1a77b4dYorke Lee 1028a2bdac8d96eaed2dacea274c55036ca9c1a77b4dYorke Lee /* 102911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (index > 0) { 103011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee detachViewFromParent(index); 103111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee attachViewToParent(v, 0, v.getLayoutParams()); 1032a2bdac8d96eaed2dacea274c55036ca9c1a77b4dYorke Lee }*/ 103311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 103411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // We do this so the underlying ScrollView knows that it won't get 103511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // the chance to intercept events anymore 103611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee requestDisallowInterceptTouchEvent(true); 103711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 103811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 103911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 104011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void onChildDismissed(View v) { 104111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (v != null) { 104211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee if (mOnItemSwipeListener != null) { 104311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee mOnItemSwipeListener.onSwipe(v); 104411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 104511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 104611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 104711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 104811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 104911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void onDragCancelled(View v) {} 105011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 105111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 105211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public boolean onInterceptTouchEvent(MotionEvent ev) { 10535a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee if (mSwipeHelper != null && isSwipeEnabled()) { 105411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return mSwipeHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev); 105511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } else { 105611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return super.onInterceptTouchEvent(ev); 105711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 105811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 105911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 106011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 106111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public boolean onTouchEvent(MotionEvent ev) { 10625a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee if (mSwipeHelper != null && isSwipeEnabled()) { 106311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev); 106411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } else { 106511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return super.onTouchEvent(ev); 106611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 106711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 106811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 106911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public int getItemViewType() { 107011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee return mItemViewType; 107111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 107211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 107311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void setOnItemSwipeListener(OnItemGestureListener listener) { 107411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee mOnItemSwipeListener = listener; 107511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 1076dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 1077dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee 107855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee /** 107955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * Used when a contact is swiped away. This will both unstar and set pinned position of the 108055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * contact to PinnedPosition.DEMOTED so that it doesn't show up anymore in the favorites list. 108155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee */ 108255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee private void unstarAndUnpinContact(Uri contactUri) { 108355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final ContentValues values = new ContentValues(2); 108455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee values.put(Contacts.STARRED, false); 108555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee values.put(Contacts.PINNED, PinnedPositions.DEMOTED); 108655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee mContext.getContentResolver().update(contactUri, values, null, null); 108755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 108855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 108955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee /** 109055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * Given a list of contacts that each have pinned positions, rearrange the list (destructive) 109155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * such that all pinned contacts are in their defined pinned positions, and unpinned contacts 109255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * take the spaces between those pinned contacts. Demoted contacts should not appear in the 109355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * resulting list. 109455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * 109555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * This method also updates the pinned positions of pinned contacts so that they are all 109655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * unique positive integers within range from 0 to toArrange.size() - 1. This is because 109755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * when the contact entries are read from the database, it is possible for them to have 109855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * overlapping pin positions due to sync or modifications by third party apps. 109955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee */ 110055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee @VisibleForTesting 110155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee /* package */ void arrangeContactsByPinnedPosition(ArrayList<ContactEntry> toArrange) { 110255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final PriorityQueue<ContactEntry> pinnedQueue = 110355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee new PriorityQueue<ContactEntry>(PIN_LIMIT, mContactEntryComparator); 110455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 110555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final List<ContactEntry> unpinnedContacts = new LinkedList<ContactEntry>(); 110655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 110755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final int length = toArrange.size(); 110855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee for (int i = 0; i < length; i++) { 110955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final ContactEntry contact = toArrange.get(i); 111055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // Decide whether the contact is hidden(demoted), pinned, or unpinned 111155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee if (contact.pinned > PIN_LIMIT) { 111255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee unpinnedContacts.add(contact); 111355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } else if (contact.pinned > PinnedPositions.DEMOTED) { 111455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // Demoted or contacts with negative pinned positions are ignored. 111555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // Pinned contacts go into a priority queue where they are ranked by pinned 111655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // position. This is required because the contacts provider does not return 111755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // contacts ordered by pinned position. 111855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee pinnedQueue.add(contact); 111955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 112055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 112155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 112255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final int maxToPin = Math.min(PIN_LIMIT, pinnedQueue.size() + unpinnedContacts.size()); 112355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 112455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee toArrange.clear(); 112555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee for (int i = 0; i < maxToPin; i++) { 112655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee if (!pinnedQueue.isEmpty() && pinnedQueue.peek().pinned <= i) { 112755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final ContactEntry toPin = pinnedQueue.poll(); 112855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee toPin.pinned = i; 112955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee toArrange.add(toPin); 113055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } else if (!unpinnedContacts.isEmpty()) { 113155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee toArrange.add(unpinnedContacts.remove(0)); 113255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 113355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 113455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 113555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // If there are still contacts in pinnedContacts at this point, it means that the pinned 113655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // positions of these pinned contacts exceed the actual number of contacts in the list. 113755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // For example, the user had 10 frequents, starred and pinned one of them at the last spot, 113855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // and then cleared frequents. Contacts in this situation should become unpinned. 113955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee while (!pinnedQueue.isEmpty()) { 114055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final ContactEntry entry = pinnedQueue.poll(); 114155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee entry.pinned = PinnedPositions.UNPINNED; 114255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee toArrange.add(entry); 114355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 114455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 114555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // Any remaining unpinned contacts that weren't in the gaps between the pinned contacts 114655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee // now just get appended to the end of the list. 114755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee toArrange.addAll(unpinnedContacts); 114855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 114955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 115055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee /** 115155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * Given an existing list of contact entries and a single entry that is to be pinned at a 115255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * particular position, return a ContentValues object that contains new pinned positions for 115355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * all contacts that are forced to be pinned at new positions, trying as much as possible to 115455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * keep pinned contacts at their original location. 115555f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * 115655f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * At this point in time the pinned position of each contact in the list has already been 115755f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * updated by {@link #arrangeContactsByPinnedPosition}, so we can assume that all pinned 115855f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee * positions(within {@link #PIN_LIMIT} are unique positive integers. 115955f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee */ 116055f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee @VisibleForTesting 116155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee /* package */ ContentValues getReflowedPinnedPositions(ArrayList<ContactEntry> list, 116255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee ContactEntry entryToPin, int oldPos, int newPinPos) { 116355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 116455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee final ContentValues cv = new ContentValues(); 116572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang final int lowerBound = Math.min(oldPos, newPinPos); 116672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang final int upperBound = Math.max(oldPos, newPinPos); 116772418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang for (int i = lowerBound; i <= upperBound; i++) { 116872418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang final ContactEntry entry = list.get(i); 116972418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang if (entry.pinned == i) continue; 117072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang cv.put(String.valueOf(entry.id), i); 117155f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 117255f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee return cv; 117355f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee } 117455f3ec9f882b2389e498ea68f68ce8670c5d4c73Yorke Lee 1175dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee protected static class ViewTypes { 1176d99993213962df64c9d76005df86c2fb83fca074Yorke Lee public static final int FREQUENT = 0; 1177d99993213962df64c9d76005df86c2fb83fca074Yorke Lee public static final int TOP = 1; 11784fdf594962b3928c6497b471dbb1ee7be56e18efChristine Chen public static final int COUNT = 2; 1179dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee } 118011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 118111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 118211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void onSwipe(View view) { 118311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final PhoneFavoriteTileView tileView = (PhoneFavoriteTileView) view.findViewById( 118411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee R.id.contact_tile); 118511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee // When the view is in the removal dialog, it should no longer be swipeable 118611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee SwipeHelper.setSwipeable(view, false); 118711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee tileView.displayRemovalDialog(); 118811ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 118911ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee final Integer entryIndex = (Integer) tileView.getTag( 119011ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee ContactTileRow.CONTACT_ENTRY_INDEX_TAG); 119111ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 119211ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee setPotentialRemoveEntryIndex(entryIndex); 119311ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 119411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee 119511ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee @Override 119611ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee public void onTouch() { 119711ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee removePendingContactEntry(); 11985a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee return; 11995a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee } 12005a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee 12015a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee @Override 12025a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee public boolean isSwipeEnabled() { 12035a1db1cd6a8addc0401529454bde6e1d15f215a0Yorke Lee return !mAwaitingRemove; 120411ee58b1b8711c6d3b2ade6a71835b6c102a08a7Yorke Lee } 120518e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee 12067639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang @Override 1207d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee public void onDragStarted(int itemIndex, int x, int y, PhoneFavoriteTileView view) { 12087639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang setInDragging(true); 12097639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang popContactEntry(itemIndex); 121018e7fdd55f67e3636c161462cb54e7f5555a04deYorke Lee } 121172418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang 12127639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang @Override 1213d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee public void onDragHovered(int itemIndex, int x, int y) { 121472418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang if (mInDragging && 121572418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang mDragEnteredEntryIndex != itemIndex && 121672418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang isIndexInBound(itemIndex) && 1217d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee itemIndex < PIN_LIMIT && 1218d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee itemIndex >= 0) { 121972418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang markDropArea(itemIndex); 122072418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 122172418af9f84b7a97ff8cb08b99aa68b2db9ee1a9Hongwei Wang } 12227639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang 12237639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang @Override 1224d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee public void onDragFinished(int x, int y) { 12257639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang setInDragging(false); 1226d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee // A contact has been dragged to the RemoveView in order to be unstarred, so simply wait 1227d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee // for the new contact cursor which will cause the UI to be refreshed without the unstarred 1228d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee // contact. 1229d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee if (!mAwaitingRemove) { 1230d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee handleDrop(); 1231d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee } 1232d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee } 1233d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee 1234d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee @Override 1235d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee public void onDroppedOnRemove() { 1236d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee if (mDraggedEntry != null) { 1237d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee unstarAndUnpinContact(mDraggedEntry.lookupKey); 1238d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee mAwaitingRemove = true; 1239d5b5d0a35d0f0e7dfd75828976dc3c0f95cdd672Yorke Lee } 12407639fe9a3ecc9c197718a9f81d8a745d2f660cb3Hongwei Wang } 1241dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee} 1242