1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.contacts; 18 19 import android.content.Context; 20 import android.database.CharArrayBuffer; 21 import android.database.Cursor; 22 import android.database.MatrixCursor; 23 import android.provider.CallLog.Calls; 24 import android.test.AndroidTestCase; 25 import android.text.TextUtils; 26 import android.view.View; 27 import android.view.ViewGroup; 28 29 import static com.android.contacts.GroupingListAdapter.ITEM_TYPE_STANDALONE; 30 import static com.android.contacts.GroupingListAdapter.ITEM_TYPE_IN_GROUP; 31 import static com.android.contacts.GroupingListAdapter.ITEM_TYPE_GROUP_HEADER; 32 33 /** 34 * Tests for the contact call list adapter. 35 * 36 * Running all tests: 37 * 38 * runtest contacts 39 * or 40 * adb shell am instrument \ 41 * -w com.android.contacts.tests/android.test.InstrumentationTestRunner 42 */ 43 public class GroupingListAdapterTests extends AndroidTestCase { 44 45 static private final String[] CALL_LOG_PROJECTION = new String[] { 46 Calls._ID, 47 Calls.NUMBER, 48 Calls.DATE, 49 }; 50 51 private static final int CALLS_NUMBER_COLUMN_INDEX = 1; 52 53 private MatrixCursor mCursor; 54 private long mNextCall; 55 56 private GroupingListAdapter mAdapter = new GroupingListAdapter(null) { 57 58 @Override 59 protected void addGroups(Cursor cursor) { 60 int count = cursor.getCount(); 61 int groupItemCount = 1; 62 cursor.moveToFirst(); 63 String currentValue = cursor.getString(CALLS_NUMBER_COLUMN_INDEX); 64 for (int i = 1; i < count; i++) { 65 cursor.moveToNext(); 66 String value = cursor.getString(CALLS_NUMBER_COLUMN_INDEX); 67 if (TextUtils.equals(value, currentValue)) { 68 groupItemCount++; 69 } else { 70 if (groupItemCount > 1) { 71 addGroup(i - groupItemCount, groupItemCount, false); 72 } 73 74 groupItemCount = 1; 75 currentValue = value; 76 } 77 } 78 if (groupItemCount > 1) { 79 addGroup(count - groupItemCount, groupItemCount, false); 80 } 81 } 82 83 @Override 84 protected void bindChildView(View view, Context context, Cursor cursor) { 85 } 86 87 @Override 88 protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize, 89 boolean expanded) { 90 } 91 92 @Override 93 protected void bindStandAloneView(View view, Context context, Cursor cursor) { 94 } 95 96 @Override 97 protected View newChildView(Context context, ViewGroup parent) { 98 return null; 99 } 100 101 @Override 102 protected View newGroupView(Context context, ViewGroup parent) { 103 return null; 104 } 105 106 @Override 107 protected View newStandAloneView(Context context, ViewGroup parent) { 108 return null; 109 } 110 }; 111 112 private void buildCursor(String... numbers) { 113 mCursor = new MatrixCursor(CALL_LOG_PROJECTION); 114 mNextCall = 1; 115 for (String number : numbers) { 116 mCursor.addRow(new Object[]{mNextCall, number, 1000 - mNextCall}); 117 mNextCall++; 118 } 119 } 120 121 public void testGroupingWithoutGroups() { 122 buildCursor("1", "2", "3"); 123 mAdapter.changeCursor(mCursor); 124 125 assertEquals(3, mAdapter.getCount()); 126 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 127 assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1); 128 assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 2); 129 } 130 131 public void testGroupingWithCollapsedGroupAtTheBeginning() { 132 buildCursor("1", "1", "2"); 133 mAdapter.changeCursor(mCursor); 134 135 assertEquals(2, mAdapter.getCount()); 136 assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, false, 0); 137 assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 2); 138 } 139 140 public void testGroupingWithExpandedGroupAtTheBeginning() { 141 buildCursor("1", "1", "2"); 142 mAdapter.changeCursor(mCursor); 143 mAdapter.toggleGroup(0); 144 145 assertEquals(4, mAdapter.getCount()); 146 assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, true, 0); 147 assertPositionMetadata(1, ITEM_TYPE_IN_GROUP, false, 0); 148 assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1); 149 assertPositionMetadata(3, ITEM_TYPE_STANDALONE, false, 2); 150 } 151 152 public void testGroupingWithExpandCollapseCycleAtTheBeginning() { 153 buildCursor("1", "1", "2"); 154 mAdapter.changeCursor(mCursor); 155 mAdapter.toggleGroup(0); 156 mAdapter.toggleGroup(0); 157 158 assertEquals(2, mAdapter.getCount()); 159 assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, false, 0); 160 assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 2); 161 } 162 163 public void testGroupingWithCollapsedGroupInTheMiddle() { 164 buildCursor("1", "2", "2", "2", "3"); 165 mAdapter.changeCursor(mCursor); 166 167 assertEquals(3, mAdapter.getCount()); 168 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 169 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1); 170 assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 4); 171 } 172 173 public void testGroupingWithExpandedGroupInTheMiddle() { 174 buildCursor("1", "2", "2", "2", "3"); 175 mAdapter.changeCursor(mCursor); 176 mAdapter.toggleGroup(1); 177 178 assertEquals(6, mAdapter.getCount()); 179 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 180 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1); 181 assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1); 182 assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2); 183 assertPositionMetadata(4, ITEM_TYPE_IN_GROUP, false, 3); 184 assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 4); 185 } 186 187 public void testGroupingWithCollapsedGroupAtTheEnd() { 188 buildCursor("1", "2", "3", "3", "3"); 189 mAdapter.changeCursor(mCursor); 190 191 assertEquals(3, mAdapter.getCount()); 192 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 193 assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1); 194 assertPositionMetadata(2, ITEM_TYPE_GROUP_HEADER, false, 2); 195 } 196 197 public void testGroupingWithExpandedGroupAtTheEnd() { 198 buildCursor("1", "2", "3", "3", "3"); 199 mAdapter.changeCursor(mCursor); 200 mAdapter.toggleGroup(2); 201 202 assertEquals(6, mAdapter.getCount()); 203 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 204 assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1); 205 assertPositionMetadata(2, ITEM_TYPE_GROUP_HEADER, true, 2); 206 assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2); 207 assertPositionMetadata(4, ITEM_TYPE_IN_GROUP, false, 3); 208 assertPositionMetadata(5, ITEM_TYPE_IN_GROUP, false, 4); 209 } 210 211 public void testGroupingWithMultipleCollapsedGroups() { 212 buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6"); 213 mAdapter.changeCursor(mCursor); 214 215 assertEquals(6, mAdapter.getCount()); 216 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 217 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1); 218 assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3); 219 assertPositionMetadata(3, ITEM_TYPE_GROUP_HEADER, false, 4); 220 assertPositionMetadata(4, ITEM_TYPE_GROUP_HEADER, false, 6); 221 assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8); 222 } 223 224 public void testGroupingWithMultipleExpandedGroups() { 225 buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6"); 226 mAdapter.changeCursor(mCursor); 227 mAdapter.toggleGroup(1); 228 229 // Note that expanding the group of 2's shifted the group of 5's down from the 230 // 4th to the 6th position 231 mAdapter.toggleGroup(6); 232 233 assertEquals(10, mAdapter.getCount()); 234 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 235 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1); 236 assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1); 237 assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2); 238 assertPositionMetadata(4, ITEM_TYPE_STANDALONE, false, 3); 239 assertPositionMetadata(5, ITEM_TYPE_GROUP_HEADER, false, 4); 240 assertPositionMetadata(6, ITEM_TYPE_GROUP_HEADER, true, 6); 241 assertPositionMetadata(7, ITEM_TYPE_IN_GROUP, false, 6); 242 assertPositionMetadata(8, ITEM_TYPE_IN_GROUP, false, 7); 243 assertPositionMetadata(9, ITEM_TYPE_STANDALONE, false, 8); 244 } 245 246 public void testPositionCache() { 247 buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6"); 248 mAdapter.changeCursor(mCursor); 249 250 // First pass - building up cache 251 assertEquals(6, mAdapter.getCount()); 252 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 253 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1); 254 assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3); 255 assertPositionMetadata(3, ITEM_TYPE_GROUP_HEADER, false, 4); 256 assertPositionMetadata(4, ITEM_TYPE_GROUP_HEADER, false, 6); 257 assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8); 258 259 // Second pass - using cache 260 assertEquals(6, mAdapter.getCount()); 261 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 262 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1); 263 assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3); 264 assertPositionMetadata(3, ITEM_TYPE_GROUP_HEADER, false, 4); 265 assertPositionMetadata(4, ITEM_TYPE_GROUP_HEADER, false, 6); 266 assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8); 267 268 // Invalidate cache by expanding a group 269 mAdapter.toggleGroup(1); 270 271 // First pass - building up cache 272 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 273 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1); 274 assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1); 275 assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2); 276 assertPositionMetadata(4, ITEM_TYPE_STANDALONE, false, 3); 277 assertPositionMetadata(5, ITEM_TYPE_GROUP_HEADER, false, 4); 278 assertPositionMetadata(6, ITEM_TYPE_GROUP_HEADER, false, 6); 279 assertPositionMetadata(7, ITEM_TYPE_STANDALONE, false, 8); 280 281 // Second pass - using cache 282 assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0); 283 assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1); 284 assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1); 285 assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2); 286 assertPositionMetadata(4, ITEM_TYPE_STANDALONE, false, 3); 287 assertPositionMetadata(5, ITEM_TYPE_GROUP_HEADER, false, 4); 288 assertPositionMetadata(6, ITEM_TYPE_GROUP_HEADER, false, 6); 289 assertPositionMetadata(7, ITEM_TYPE_STANDALONE, false, 8); 290 } 291 292 public void testGroupDescriptorArrayGrowth() { 293 String[] numbers = new String[500]; 294 for (int i = 0; i < numbers.length; i++) { 295 296 // Make groups of 2 297 numbers[i] = String.valueOf((i / 2) * 2); 298 } 299 300 buildCursor(numbers); 301 mAdapter.changeCursor(mCursor); 302 303 assertEquals(250, mAdapter.getCount()); 304 } 305 306 private void assertPositionMetadata(int position, int itemType, boolean isExpanded, 307 int cursorPosition) { 308 GroupingListAdapter.PositionMetadata metadata = new GroupingListAdapter.PositionMetadata(); 309 mAdapter.obtainPositionMetadata(metadata, position); 310 assertEquals(itemType, metadata.itemType); 311 if (metadata.itemType == ITEM_TYPE_GROUP_HEADER) { 312 assertEquals(isExpanded, metadata.isExpanded); 313 } 314 assertEquals(cursorPosition, metadata.cursorPosition); 315 } 316 } 317