1 /* 2 * Copyright (C) 2015 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.documentsui.selection; 18 19 import android.support.test.filters.SmallTest; 20 import android.support.test.runner.AndroidJUnit4; 21 import android.util.SparseBooleanArray; 22 23 import com.android.documentsui.dirlist.TestDocumentsAdapter; 24 import com.android.documentsui.selection.SelectionManager; 25 import com.android.documentsui.dirlist.TestData; 26 import com.android.documentsui.selection.Selection; 27 import com.android.documentsui.testing.SelectionManagers; 28 29 import org.junit.Before; 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 33 import java.util.ArrayList; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.Set; 37 38 @RunWith(AndroidJUnit4.class) 39 @SmallTest 40 public class SelectionManagerTest { 41 42 private static final List<String> ITEMS = TestData.create(100); 43 44 private final Set<String> mIgnored = new HashSet<>(); 45 private TestDocumentsAdapter mAdapter; 46 private SelectionManager mManager; 47 private TestSelectionListener mCallback; 48 private TestItemSelectionListener mItemCallback; 49 private SelectionProbe mSelection; 50 51 @Before setUp()52 public void setUp() throws Exception { 53 mCallback = new TestSelectionListener(); 54 mItemCallback = new TestItemSelectionListener(); 55 mAdapter = new TestDocumentsAdapter(ITEMS); 56 mManager = SelectionManagers.createTestInstance( 57 mAdapter, 58 SelectionManager.MODE_MULTIPLE, 59 (String id, boolean nextState) -> (!nextState || !mIgnored.contains(id))); 60 mManager.addCallback(mCallback); 61 mManager.addItemCallback(mItemCallback); 62 63 mSelection = new SelectionProbe(mManager, mItemCallback); 64 65 mIgnored.clear(); 66 } 67 68 @Test testSelection()69 public void testSelection() { 70 // Check selection. 71 mManager.toggleSelection(ITEMS.get(7)); 72 mSelection.assertSelection(7); 73 // Check deselection. 74 mManager.toggleSelection(ITEMS.get(7)); 75 mSelection.assertNoSelection(); 76 } 77 78 @Test testSelection_DoNothingOnUnselectableItem()79 public void testSelection_DoNothingOnUnselectableItem() { 80 mIgnored.add(ITEMS.get(7)); 81 82 mManager.toggleSelection(ITEMS.get(7)); 83 mSelection.assertNoSelection(); 84 } 85 86 @Test testSelection_NotifiesSelectionChanged()87 public void testSelection_NotifiesSelectionChanged() { 88 // Selection should notify. 89 mManager.toggleSelection(ITEMS.get(7)); 90 mCallback.assertSelectionChanged(); 91 // Deselection should notify. 92 mManager.toggleSelection(ITEMS.get(7)); 93 mCallback.assertSelectionChanged(); 94 } 95 96 @Test testSelection_PersistsOnUpdate()97 public void testSelection_PersistsOnUpdate() { 98 mManager.toggleSelection(ITEMS.get(7)); 99 100 mAdapter.updateTestModelIds(ITEMS); 101 102 mSelection.assertSelection(7); 103 } 104 105 @Test testSelection_IntersectsWithNewDataSet()106 public void testSelection_IntersectsWithNewDataSet() { 107 mManager.toggleSelection(ITEMS.get(99)); 108 mManager.toggleSelection(ITEMS.get(7)); 109 110 mAdapter.updateTestModelIds(TestData.create(50)); 111 112 mSelection.assertSelection(7); 113 } 114 115 @Test testSetItemsSelected()116 public void testSetItemsSelected() { 117 mManager.setItemsSelected(getStringIds(6, 7, 8), true); 118 119 mSelection.assertRangeSelected(6, 8); 120 } 121 122 @Test testSetItemsSelected_SkipUnselectableItem()123 public void testSetItemsSelected_SkipUnselectableItem() { 124 mIgnored.add(ITEMS.get(7)); 125 126 mManager.setItemsSelected(getStringIds(6, 7, 8), true); 127 128 mSelection.assertSelected(6); 129 mSelection.assertNotSelected(7); 130 mSelection.assertSelected(8); 131 } 132 133 @Test testRangeSelection()134 public void testRangeSelection() { 135 mManager.startRangeSelection(15); 136 mManager.snapRangeSelection(19); 137 mSelection.assertRangeSelection(15, 19); 138 } 139 140 @Test testRangeSelection_SkipUnselectableItem()141 public void testRangeSelection_SkipUnselectableItem() { 142 mIgnored.add(ITEMS.get(17)); 143 144 mManager.startRangeSelection(15); 145 mManager.snapRangeSelection(19); 146 147 mSelection.assertRangeSelected(15, 16); 148 mSelection.assertNotSelected(17); 149 mSelection.assertRangeSelected(18, 19); 150 } 151 152 @Test testRangeSelection_snapExpand()153 public void testRangeSelection_snapExpand() { 154 mManager.startRangeSelection(15); 155 mManager.snapRangeSelection(19); 156 mManager.snapRangeSelection(27); 157 mSelection.assertRangeSelection(15, 27); 158 } 159 160 @Test testRangeSelection_snapContract()161 public void testRangeSelection_snapContract() { 162 mManager.startRangeSelection(15); 163 mManager.snapRangeSelection(27); 164 mManager.snapRangeSelection(19); 165 mSelection.assertRangeSelection(15, 19); 166 } 167 168 @Test testRangeSelection_snapInvert()169 public void testRangeSelection_snapInvert() { 170 mManager.startRangeSelection(15); 171 mManager.snapRangeSelection(27); 172 mManager.snapRangeSelection(3); 173 mSelection.assertRangeSelection(3, 15); 174 } 175 176 @Test testRangeSelection_multiple()177 public void testRangeSelection_multiple() { 178 mManager.startRangeSelection(15); 179 mManager.snapRangeSelection(27); 180 mManager.endRangeSelection(); 181 mManager.startRangeSelection(42); 182 mManager.snapRangeSelection(57); 183 mSelection.assertSelectionSize(29); 184 mSelection.assertRangeSelected(15, 27); 185 mSelection.assertRangeSelected(42, 57); 186 } 187 188 @Test testProvisionalRangeSelection()189 public void testProvisionalRangeSelection() { 190 mManager.startRangeSelection(13); 191 mManager.snapProvisionalRangeSelection(15); 192 mSelection.assertRangeSelection(13, 15); 193 mManager.getSelection().applyProvisionalSelection(); 194 mManager.endRangeSelection(); 195 mSelection.assertSelectionSize(3); 196 } 197 198 @Test testProvisionalRangeSelection_endEarly()199 public void testProvisionalRangeSelection_endEarly() { 200 mManager.startRangeSelection(13); 201 mManager.snapProvisionalRangeSelection(15); 202 mSelection.assertRangeSelection(13, 15); 203 204 mManager.endRangeSelection(); 205 // If we end range selection prematurely for provision selection, nothing should be selected 206 // except the first item 207 mSelection.assertSelectionSize(1); 208 } 209 210 @Test testProvisionalRangeSelection_snapExpand()211 public void testProvisionalRangeSelection_snapExpand() { 212 mManager.startRangeSelection(13); 213 mManager.snapProvisionalRangeSelection(15); 214 mSelection.assertRangeSelection(13, 15); 215 mManager.getSelection().applyProvisionalSelection(); 216 mManager.snapRangeSelection(18); 217 mSelection.assertRangeSelection(13, 18); 218 } 219 220 @Test testCombinationRangeSelection_IntersectsOldSelection()221 public void testCombinationRangeSelection_IntersectsOldSelection() { 222 mManager.startRangeSelection(13); 223 mManager.snapRangeSelection(15); 224 mSelection.assertRangeSelection(13, 15); 225 226 mManager.startRangeSelection(11); 227 mManager.snapProvisionalRangeSelection(18); 228 mSelection.assertRangeSelected(11, 18); 229 mManager.endRangeSelection(); 230 mSelection.assertRangeSelected(13, 15); 231 mSelection.assertRangeSelected(11, 11); 232 mSelection.assertSelectionSize(4); 233 } 234 235 @Test testProvisionalSelection()236 public void testProvisionalSelection() { 237 Selection s = mManager.getSelection(); 238 mSelection.assertNoSelection(); 239 240 // Mimicking band selection case -- BandController notifies item callback by itself. 241 mItemCallback.onItemStateChanged(ITEMS.get(1), true); 242 mItemCallback.onItemStateChanged(ITEMS.get(2), true); 243 244 SparseBooleanArray provisional = new SparseBooleanArray(); 245 provisional.append(1, true); 246 provisional.append(2, true); 247 s.setProvisionalSelection(getItemIds(provisional)); 248 mSelection.assertSelection(1, 2); 249 } 250 251 @Test testProvisionalSelection_Replace()252 public void testProvisionalSelection_Replace() { 253 Selection s = mManager.getSelection(); 254 255 // Mimicking band selection case -- BandController notifies item callback by itself. 256 mItemCallback.onItemStateChanged(ITEMS.get(1), true); 257 mItemCallback.onItemStateChanged(ITEMS.get(2), true); 258 SparseBooleanArray provisional = new SparseBooleanArray(); 259 provisional.append(1, true); 260 provisional.append(2, true); 261 s.setProvisionalSelection(getItemIds(provisional)); 262 263 mItemCallback.onItemStateChanged(ITEMS.get(1), false); 264 mItemCallback.onItemStateChanged(ITEMS.get(2), false); 265 provisional.clear(); 266 267 mItemCallback.onItemStateChanged(ITEMS.get(3), true); 268 mItemCallback.onItemStateChanged(ITEMS.get(4), true); 269 provisional.append(3, true); 270 provisional.append(4, true); 271 s.setProvisionalSelection(getItemIds(provisional)); 272 mSelection.assertSelection(3, 4); 273 } 274 275 @Test testProvisionalSelection_IntersectsExistingProvisionalSelection()276 public void testProvisionalSelection_IntersectsExistingProvisionalSelection() { 277 Selection s = mManager.getSelection(); 278 279 // Mimicking band selection case -- BandController notifies item callback by itself. 280 mItemCallback.onItemStateChanged(ITEMS.get(1), true); 281 mItemCallback.onItemStateChanged(ITEMS.get(2), true); 282 SparseBooleanArray provisional = new SparseBooleanArray(); 283 provisional.append(1, true); 284 provisional.append(2, true); 285 s.setProvisionalSelection(getItemIds(provisional)); 286 287 mItemCallback.onItemStateChanged(ITEMS.get(1), false); 288 mItemCallback.onItemStateChanged(ITEMS.get(2), false); 289 provisional.clear(); 290 291 mItemCallback.onItemStateChanged(ITEMS.get(1), true); 292 provisional.append(1, true); 293 s.setProvisionalSelection(getItemIds(provisional)); 294 mSelection.assertSelection(1); 295 } 296 297 @Test testProvisionalSelection_Apply()298 public void testProvisionalSelection_Apply() { 299 Selection s = mManager.getSelection(); 300 301 // Mimicking band selection case -- BandController notifies item callback by itself. 302 mItemCallback.onItemStateChanged(ITEMS.get(1), true); 303 mItemCallback.onItemStateChanged(ITEMS.get(2), true); 304 SparseBooleanArray provisional = new SparseBooleanArray(); 305 provisional.append(1, true); 306 provisional.append(2, true); 307 s.setProvisionalSelection(getItemIds(provisional)); 308 s.applyProvisionalSelection(); 309 310 mSelection.assertSelection(1, 2); 311 } 312 313 @Test testProvisionalSelection_Cancel()314 public void testProvisionalSelection_Cancel() { 315 mManager.toggleSelection(ITEMS.get(1)); 316 mManager.toggleSelection(ITEMS.get(2)); 317 Selection s = mManager.getSelection(); 318 319 SparseBooleanArray provisional = new SparseBooleanArray(); 320 provisional.append(3, true); 321 provisional.append(4, true); 322 s.setProvisionalSelection(getItemIds(provisional)); 323 s.cancelProvisionalSelection(); 324 325 // Original selection should remain. 326 mSelection.assertSelection(1, 2); 327 } 328 329 @Test testProvisionalSelection_IntersectsAppliedSelection()330 public void testProvisionalSelection_IntersectsAppliedSelection() { 331 mManager.toggleSelection(ITEMS.get(1)); 332 mManager.toggleSelection(ITEMS.get(2)); 333 Selection s = mManager.getSelection(); 334 335 // Mimicking band selection case -- BandController notifies item callback by itself. 336 mItemCallback.onItemStateChanged(ITEMS.get(3), true); 337 SparseBooleanArray provisional = new SparseBooleanArray(); 338 provisional.append(2, true); 339 provisional.append(3, true); 340 s.setProvisionalSelection(getItemIds(provisional)); 341 mSelection.assertSelection(1, 2, 3); 342 } 343 getItemIds(SparseBooleanArray selection)344 private static Set<String> getItemIds(SparseBooleanArray selection) { 345 Set<String> ids = new HashSet<>(); 346 347 int count = selection.size(); 348 for (int i = 0; i < count; ++i) { 349 ids.add(ITEMS.get(selection.keyAt(i))); 350 } 351 352 return ids; 353 } 354 getStringIds(int... ids)355 private static Iterable<String> getStringIds(int... ids) { 356 List<String> stringIds = new ArrayList<>(ids.length); 357 for (int id : ids) { 358 stringIds.add(ITEMS.get(id)); 359 } 360 return stringIds; 361 } 362 } 363