1 /* 2 * Copyright (C) 2024 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.launcher3.folder 18 19 import android.content.Context 20 import android.graphics.Point 21 import android.view.KeyEvent 22 import android.view.View 23 import android.view.inputmethod.EditorInfo 24 import android.widget.TextView 25 import androidx.core.view.isVisible 26 import androidx.test.core.app.ApplicationProvider 27 import androidx.test.ext.junit.runners.AndroidJUnit4 28 import androidx.test.filters.SmallTest 29 import com.android.launcher3.Alarm 30 import com.android.launcher3.DragSource 31 import com.android.launcher3.DropTarget.DragObject 32 import com.android.launcher3.LauncherAppState 33 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION 34 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET 35 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR 36 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT 37 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER 38 import com.android.launcher3.OnAlarmListener 39 import com.android.launcher3.R 40 import com.android.launcher3.celllayout.board.FolderPoint 41 import com.android.launcher3.celllayout.board.TestWorkspaceBuilder 42 import com.android.launcher3.dragndrop.DragController 43 import com.android.launcher3.dragndrop.DragOptions 44 import com.android.launcher3.dragndrop.DragView 45 import com.android.launcher3.folder.Folder.MIN_CONTENT_DIMEN 46 import com.android.launcher3.folder.Folder.ON_EXIT_CLOSE_DELAY 47 import com.android.launcher3.folder.Folder.SCROLL_LEFT 48 import com.android.launcher3.folder.Folder.SCROLL_NONE 49 import com.android.launcher3.folder.Folder.STATE_ANIMATING 50 import com.android.launcher3.folder.Folder.STATE_CLOSED 51 import com.android.launcher3.model.data.FolderInfo 52 import com.android.launcher3.model.data.ItemInfo 53 import com.android.launcher3.util.ActivityContextWrapper 54 import com.android.launcher3.util.ModelTestExtensions.clearModelDb 55 import java.util.ArrayList 56 import junit.framework.TestCase.assertEquals 57 import junit.framework.TestCase.assertFalse 58 import junit.framework.TestCase.assertNull 59 import junit.framework.TestCase.assertTrue 60 import org.junit.After 61 import org.junit.Before 62 import org.junit.Test 63 import org.junit.runner.RunWith 64 import org.mockito.Mockito 65 import org.mockito.Mockito.spy 66 import org.mockito.Mockito.times 67 import org.mockito.Mockito.verify 68 import org.mockito.Mockito.`when` 69 import org.mockito.kotlin.doNothing 70 import org.mockito.kotlin.doReturn 71 import org.mockito.kotlin.whenever 72 73 /** Tests for [Folder] */ 74 @SmallTest 75 @RunWith(AndroidJUnit4::class) 76 class FolderTest { 77 78 private lateinit var context: Context 79 private lateinit var workspaceBuilder: TestWorkspaceBuilder 80 private lateinit var folder: Folder 81 82 @Before setUpnull83 fun setUp() { 84 context = ActivityContextWrapper(ApplicationProvider.getApplicationContext()) 85 workspaceBuilder = TestWorkspaceBuilder(context) 86 folder = spy(Folder(context, null)) 87 } 88 89 @After tearDownnull90 fun tearDown() { 91 LauncherAppState.getInstance(context).model.clearModelDb() 92 } 93 94 @Test Undo a folder with 1 icon when onDropCompleted is callednull95 fun `Undo a folder with 1 icon when onDropCompleted is called`() { 96 val folderInfo = 97 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 98 folder.mInfo = folderInfo 99 folder.mInfo.getContents().removeAt(0) 100 folder.mContent = Mockito.mock(FolderPagedView::class.java) 101 val dragLayout = Mockito.mock(View::class.java) 102 val dragObject = Mockito.mock(DragObject::class.java) 103 folder.deleteFolderOnDropCompleted = false 104 105 folder.onDropCompleted(dragLayout, dragObject, true) 106 107 verify(folder, times(1)).replaceFolderWithFinalItem() 108 assertEquals(folder.deleteFolderOnDropCompleted, false) 109 } 110 111 @Test Do not undo a folder with 2 icons when onDropCompleted is callednull112 fun `Do not undo a folder with 2 icons when onDropCompleted is called`() { 113 val folderInfo = 114 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 115 folder.mInfo = folderInfo 116 folder.mContent = Mockito.mock(FolderPagedView::class.java) 117 val dragLayout = Mockito.mock(View::class.java) 118 val dragObject = Mockito.mock(DragObject::class.java) 119 folder.deleteFolderOnDropCompleted = false 120 121 folder.onDropCompleted(dragLayout, dragObject, true) 122 123 verify(folder, times(0)).replaceFolderWithFinalItem() 124 assertEquals(folder.deleteFolderOnDropCompleted, false) 125 } 126 127 @Test Test that we accept valid item type ITEM_TYPE_APPLICATIONnull128 fun `Test that we accept valid item type ITEM_TYPE_APPLICATION`() { 129 val itemInfo = Mockito.mock(ItemInfo::class.java) 130 itemInfo.itemType = ITEM_TYPE_APPLICATION 131 132 val willAcceptResult = Folder.willAccept(itemInfo) 133 134 assertTrue(willAcceptResult) 135 } 136 137 @Test Test that we accept valid item type ITEM_TYPE_DEEP_SHORTCUTnull138 fun `Test that we accept valid item type ITEM_TYPE_DEEP_SHORTCUT`() { 139 val itemInfo = Mockito.mock(ItemInfo::class.java) 140 itemInfo.itemType = ITEM_TYPE_DEEP_SHORTCUT 141 142 val willAcceptResult = Folder.willAccept(itemInfo) 143 144 assertTrue(willAcceptResult) 145 } 146 147 @Test Test that we accept valid item type ITEM_TYPE_APP_PAIRnull148 fun `Test that we accept valid item type ITEM_TYPE_APP_PAIR`() { 149 val itemInfo = Mockito.mock(ItemInfo::class.java) 150 itemInfo.itemType = ITEM_TYPE_APP_PAIR 151 152 val willAcceptResult = Folder.willAccept(itemInfo) 153 154 assertTrue(willAcceptResult) 155 } 156 157 @Test Test that we do not accept invalid item type ITEM_TYPE_APPWIDGETnull158 fun `Test that we do not accept invalid item type ITEM_TYPE_APPWIDGET`() { 159 val itemInfo = Mockito.mock(ItemInfo::class.java) 160 itemInfo.itemType = ITEM_TYPE_APPWIDGET 161 162 val willAcceptResult = Folder.willAccept(itemInfo) 163 164 assertFalse(willAcceptResult) 165 } 166 167 @Test Test that we do not accept invalid item type ITEM_TYPE_FOLDERnull168 fun `Test that we do not accept invalid item type ITEM_TYPE_FOLDER`() { 169 val itemInfo = Mockito.mock(ItemInfo::class.java) 170 itemInfo.itemType = ITEM_TYPE_FOLDER 171 172 val willAcceptResult = Folder.willAccept(itemInfo) 173 174 assertFalse(willAcceptResult) 175 } 176 177 @Test We should not animate open if items is null or less than or equal to 1null178 fun `We should not animate open if items is null or less than or equal to 1`() { 179 folder.mInfo = Mockito.mock(FolderInfo::class.java) 180 val shouldAnimateOpenResult = folder.shouldAnimateOpen(null) 181 182 assertFalse(shouldAnimateOpenResult) 183 assertFalse( 184 folder.shouldAnimateOpen(arrayListOf<ItemInfo>(Mockito.mock(ItemInfo::class.java))) 185 ) 186 } 187 188 @Test We should animate open if items greater than 1null189 fun `We should animate open if items greater than 1`() { 190 val folderInfo = 191 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 192 folder.mInfo = folderInfo 193 194 val shouldAnimateOpenResult = folder.shouldAnimateOpen(folder.mInfo.getContents()) 195 196 assertTrue(shouldAnimateOpenResult) 197 } 198 199 @Test Should be true if there is an open foldernull200 fun `Should be true if there is an open folder`() { 201 val closeOpenFolderResult = folder.closeOpenFolder(Mockito.mock(Folder::class.java)) 202 203 assertTrue(closeOpenFolderResult) 204 } 205 206 @Test Should be false if the open folder is this foldernull207 fun `Should be false if the open folder is this folder`() { 208 val closeOpenFolderResult = folder.closeOpenFolder(folder) 209 210 assertFalse(closeOpenFolderResult) 211 } 212 213 @Test Should be false if there is not an open foldernull214 fun `Should be false if there is not an open folder`() { 215 val closeOpenFolderResult = folder.closeOpenFolder(null) 216 217 assertFalse(closeOpenFolderResult) 218 } 219 220 @Test If drag is in progress we should set mItemAddedBackToSelfViaIcon to truenull221 fun `If drag is in progress we should set mItemAddedBackToSelfViaIcon to true`() { 222 folder.itemAddedBackToSelfViaIcon = false 223 folder.isDragInProgress = true 224 225 folder.notifyDrop() 226 227 assertTrue(folder.itemAddedBackToSelfViaIcon) 228 } 229 230 @Test If drag is not in progress we should not set mItemAddedBackToSelfViaIcon to truenull231 fun `If drag is not in progress we should not set mItemAddedBackToSelfViaIcon to true`() { 232 folder.itemAddedBackToSelfViaIcon = false 233 folder.isDragInProgress = false 234 235 folder.notifyDrop() 236 237 assertFalse(folder.itemAddedBackToSelfViaIcon) 238 } 239 240 @Test If launcher dragging is not enabled onLongClick should return truenull241 fun `If launcher dragging is not enabled onLongClick should return true`() { 242 `when`(folder.isLauncherDraggingEnabled).thenReturn(false) 243 244 val onLongClickResult = folder.onLongClick(Mockito.mock(View::class.java)) 245 246 assertTrue(onLongClickResult) 247 } 248 249 @Test If launcher dragging is enabled we should return startDrag resultnull250 fun `If launcher dragging is enabled we should return startDrag result`() { 251 `when`(folder.isLauncherDraggingEnabled).thenReturn(true) 252 val viewMock = Mockito.mock(View::class.java) 253 val dragOptions = Mockito.mock(DragOptions::class.java) 254 255 val onLongClickResult = folder.onLongClick(viewMock) 256 257 assertEquals(onLongClickResult, folder.startDrag(viewMock, dragOptions)) 258 verify(folder, times(1)).startDrag(viewMock, dragOptions) 259 } 260 261 @Test Verify start drag works as intended when view is instanceof ItemInfonull262 fun `Verify start drag works as intended when view is instanceof ItemInfo`() { 263 val itemInfo = ItemInfo() 264 itemInfo.rank = 5 265 val viewMock = Mockito.mock(View::class.java) 266 val dragOptions = DragOptions() 267 `when`(viewMock.tag).thenReturn(itemInfo) 268 folder.dragController = Mockito.mock(DragController::class.java) 269 270 folder.startDrag(viewMock, dragOptions) 271 272 assertEquals(folder.mEmptyCellRank, 5) 273 assertEquals(folder.currentDragView, viewMock) 274 verify(folder, times(1)).addDragListener(dragOptions) 275 verify(folder, times(1)).callBeginDragShared(viewMock, dragOptions) 276 } 277 278 @Test Verify start drag works as intended when view is not instanceof ItemInfonull279 fun `Verify start drag works as intended when view is not instanceof ItemInfo`() { 280 val viewMock = Mockito.mock(View::class.java) 281 val dragOptions = DragOptions() 282 283 folder.startDrag(viewMock, dragOptions) 284 285 verify(folder, times(0)).addDragListener(dragOptions) 286 verify(folder, times(0)).callBeginDragShared(viewMock, dragOptions) 287 } 288 289 @Test Verify that onDragStart has an effect if dragSource is this foldernull290 fun `Verify that onDragStart has an effect if dragSource is this folder`() { 291 folder.itemsInvalidated = false 292 folder.isDragInProgress = false 293 folder.itemAddedBackToSelfViaIcon = true 294 folder.currentDragView = Mockito.mock(View::class.java) 295 val folderInfo = 296 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 297 folder.mInfo = spy(folderInfo) 298 val dragObject = DragObject(context) 299 dragObject.dragInfo = Mockito.mock(ItemInfo::class.java) 300 folder.mContent = Mockito.mock(FolderPagedView::class.java) 301 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 302 dragObject.dragSource = folder 303 304 folder.onDragStart(dragObject, DragOptions()) 305 306 verify(folder.mContent, times(1)).removeItem(folder.currentDragView) 307 verify(folder, times(1)).removeFolderContent(true, dragObject.dragInfo) 308 assertTrue(folder.itemsInvalidated) 309 assertTrue(folder.isDragInProgress) 310 assertFalse(folder.itemAddedBackToSelfViaIcon) 311 } 312 313 @Test Verify that onDragStart has no effects if dragSource is not this foldernull314 fun `Verify that onDragStart has no effects if dragSource is not this folder`() { 315 folder.itemsInvalidated = false 316 folder.isDragInProgress = false 317 folder.itemAddedBackToSelfViaIcon = true 318 folder.mContent = Mockito.mock(FolderPagedView::class.java) 319 val dragObject = DragObject(context) 320 dragObject.dragSource = Mockito.mock(DragSource::class.java) 321 322 folder.onDragStart(dragObject, DragOptions()) 323 324 verify(folder.mContent, times(0)).removeItem(folder.currentDragView) 325 assertFalse(folder.itemsInvalidated) 326 assertFalse(folder.isDragInProgress) 327 assertTrue(folder.itemAddedBackToSelfViaIcon) 328 } 329 330 @Test Verify onDragEnd that we call completeDragExit and set drag in progress falsenull331 fun `Verify onDragEnd that we call completeDragExit and set drag in progress false`() { 332 doNothing().`when`(folder).completeDragExit() 333 folder.isExternalDrag = true 334 folder.isDragInProgress = true 335 folder.dragController = Mockito.mock(DragController::class.java) 336 337 folder.onDragEnd() 338 339 verify(folder, times(1)).completeDragExit() 340 verify(folder.dragController, times(1)).removeDragListener(folder) 341 assertFalse(folder.isDragInProgress) 342 } 343 344 @Test Verify onDragEnd that we do not call completeDragExit and set drag in progress falsenull345 fun `Verify onDragEnd that we do not call completeDragExit and set drag in progress false`() { 346 folder.isExternalDrag = false 347 folder.isDragInProgress = true 348 folder.dragController = Mockito.mock(DragController::class.java) 349 350 folder.onDragEnd() 351 352 verify(folder, times(0)).completeDragExit() 353 verify(folder.dragController, times(1)).removeDragListener(folder) 354 assertFalse(folder.isDragInProgress) 355 } 356 357 @Test startEditingFolderName should set hint to empty and showLabelSuggestionsnull358 fun `startEditingFolderName should set hint to empty and showLabelSuggestions`() { 359 doNothing().`when`(folder).showLabelSuggestions() 360 folder.isEditingName = false 361 folder.folderName = FolderNameEditText(context) 362 folder.folderName.hint = "hello" 363 364 folder.startEditingFolderName() 365 366 verify(folder, times(1)).showLabelSuggestions() 367 assertEquals("", folder.folderName.hint) 368 assertTrue(folder.isEditingName) 369 } 370 371 @Test Ensure we set the title and hint correctly onBackKey when we have a new titlenull372 fun `Ensure we set the title and hint correctly onBackKey when we have a new title`() { 373 val expectedHint = null 374 val expectedTitle = "hello" 375 folder.isEditingName = true 376 folder.folderName = spy(FolderNameEditText(context)) 377 folder.folderName.setText(expectedTitle) 378 val folderInfo = 379 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 380 folder.mInfo = spy(folderInfo) 381 folder.mInfo.title = "world" 382 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 383 384 folder.onBackKey() 385 386 assertEquals(expectedTitle, folder.mInfo.title) 387 verify(folder.mFolderIcon, times(1)).onTitleChanged(expectedTitle) 388 assertEquals(expectedHint, folder.folderName.hint) 389 assertFalse(folder.isEditingName) 390 verify(folder.folderName, times(1)).clearFocus() 391 } 392 393 @Test Ensure we set the title and hint correctly onBackKey when we do not have a new titlenull394 fun `Ensure we set the title and hint correctly onBackKey when we do not have a new title`() { 395 val expectedHint = context.getString(R.string.folder_hint_text) 396 val expectedTitle = "" 397 folder.isEditingName = true 398 folder.folderName = spy(FolderNameEditText(context)) 399 folder.folderName.setText(expectedTitle) 400 val folderInfo = 401 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 402 folder.mInfo = spy(folderInfo) 403 folder.mInfo.title = "world" 404 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 405 406 folder.onBackKey() 407 408 assertEquals(expectedTitle, folder.mInfo.title) 409 verify(folder.mFolderIcon, times(1)).onTitleChanged(expectedTitle) 410 assertEquals(expectedHint, folder.folderName.hint) 411 assertFalse(folder.isEditingName) 412 verify(folder.folderName, times(1)).clearFocus() 413 } 414 415 @Test ensure onEditorAction calls dispatchBackKey when actionId is IME_ACTION_DONEnull416 fun `ensure onEditorAction calls dispatchBackKey when actionId is IME_ACTION_DONE`() { 417 folder.folderName = Mockito.mock(FolderNameEditText::class.java) 418 419 val result = 420 folder.onEditorAction( 421 Mockito.mock(TextView::class.java), 422 EditorInfo.IME_ACTION_DONE, 423 Mockito.mock(KeyEvent::class.java), 424 ) 425 426 assertTrue(result) 427 verify(folder.folderName, times(1)).dispatchBackKey() 428 } 429 430 @Test ensure onEditorAction does not call dispatchBackKey when actionId is not IME_ACTION_DONEnull431 fun `ensure onEditorAction does not call dispatchBackKey when actionId is not IME_ACTION_DONE`() { 432 folder.folderName = Mockito.mock(FolderNameEditText::class.java) 433 434 val result = 435 folder.onEditorAction( 436 Mockito.mock(TextView::class.java), 437 EditorInfo.IME_ACTION_NONE, 438 Mockito.mock(KeyEvent::class.java), 439 ) 440 441 assertFalse(result) 442 verify(folder.folderName, times(0)).dispatchBackKey() 443 } 444 445 @Test in completeDragExit we close the folder when mIsOpennull446 fun `in completeDragExit we close the folder when mIsOpen`() { 447 doNothing().`when`(folder).close(true) 448 folder.setIsOpen(true) 449 folder.rearrangeOnClose = false 450 451 folder.completeDragExit() 452 453 verify(folder, times(1)).close(true) 454 assertTrue(folder.rearrangeOnClose) 455 } 456 457 @Test in completeDragExit we want to rearrange on close when it is animatingnull458 fun `in completeDragExit we want to rearrange on close when it is animating`() { 459 folder.setIsOpen(false) 460 folder.rearrangeOnClose = false 461 folder.state = STATE_ANIMATING 462 463 folder.completeDragExit() 464 465 verify(folder, times(0)).close(true) 466 assertTrue(folder.rearrangeOnClose) 467 } 468 469 @Test in completeDragExit we want to call rearrangeChildren and clearDragInfo when not open and not animatingnull470 fun `in completeDragExit we want to call rearrangeChildren and clearDragInfo when not open and not animating`() { 471 doNothing().`when`(folder).rearrangeChildren() 472 doNothing().`when`(folder).clearDragInfo() 473 folder.setIsOpen(false) 474 folder.rearrangeOnClose = false 475 folder.state = STATE_CLOSED 476 477 folder.completeDragExit() 478 479 verify(folder, times(0)).close(true) 480 assertFalse(folder.rearrangeOnClose) 481 verify(folder, times(1)).rearrangeChildren() 482 verify(folder, times(1)).clearDragInfo() 483 } 484 485 @Test clearDragInfo should set current drag view to null and isExternalDrag to falsenull486 fun `clearDragInfo should set current drag view to null and isExternalDrag to false`() { 487 folder.currentDragView = Mockito.mock(DragView::class.java) 488 folder.isExternalDrag = true 489 490 folder.clearDragInfo() 491 492 assertNull(folder.currentDragView) 493 assertFalse(folder.isExternalDrag) 494 } 495 496 @Test onDragExit should set alarm if drag is not completenull497 fun `onDragExit should set alarm if drag is not complete`() { 498 folder.onExitAlarm = Mockito.mock(Alarm::class.java) 499 val dragObject = Mockito.mock(DragObject::class.java) 500 dragObject.dragComplete = false 501 502 folder.onDragExit(dragObject) 503 504 verify(folder.onExitAlarm, times(1)).setOnAlarmListener(folder.mOnExitAlarmListener) 505 verify(folder.onExitAlarm, times(1)).setAlarm(ON_EXIT_CLOSE_DELAY.toLong()) 506 } 507 508 @Test onDragExit should not set alarm if drag is completenull509 fun `onDragExit should not set alarm if drag is complete`() { 510 folder.onExitAlarm = Mockito.mock(Alarm::class.java) 511 val dragObject = Mockito.mock(DragObject::class.java) 512 dragObject.dragComplete = true 513 514 folder.onDragExit(dragObject) 515 516 verify(folder.onExitAlarm, times(0)).setOnAlarmListener(folder.mOnExitAlarmListener) 517 verify(folder.onExitAlarm, times(0)).setAlarm(ON_EXIT_CLOSE_DELAY.toLong()) 518 } 519 520 @Test onDragExit should not clear scroll hint if already SCROLL_NONEnull521 fun `onDragExit should not clear scroll hint if already SCROLL_NONE`() { 522 folder.onExitAlarm = Mockito.mock(Alarm::class.java) 523 val dragObject = Mockito.mock(DragObject::class.java) 524 folder.scrollHintDir = SCROLL_NONE 525 folder.mContent = Mockito.mock(FolderPagedView::class.java) 526 527 folder.onDragExit(dragObject) 528 529 verify(folder.mContent, times(0)).clearScrollHint() 530 } 531 532 @Test onDragExit should clear scroll hint if not SCROLL_NONE and then set scroll hint to scroll nonenull533 fun `onDragExit should clear scroll hint if not SCROLL_NONE and then set scroll hint to scroll none`() { 534 folder.onExitAlarm = Mockito.mock(Alarm::class.java) 535 val dragObject = Mockito.mock(DragObject::class.java) 536 folder.scrollHintDir = SCROLL_LEFT 537 folder.mContent = Mockito.mock(FolderPagedView::class.java) 538 539 folder.onDragExit(dragObject) 540 541 verify(folder.mContent, times(1)).clearScrollHint() 542 assertEquals(folder.scrollHintDir, SCROLL_NONE) 543 } 544 545 @Test onDragExit we should cancel reorder pause and hint alarmsnull546 fun `onDragExit we should cancel reorder pause and hint alarms`() { 547 folder.onExitAlarm = Mockito.mock(Alarm::class.java) 548 val dragObject = Mockito.mock(DragObject::class.java) 549 folder.scrollHintDir = SCROLL_NONE 550 folder.mContent = Mockito.mock(FolderPagedView::class.java) 551 folder.reorderAlarm = Mockito.mock(Alarm::class.java) 552 folder.onScrollHintAlarm = Mockito.mock(Alarm::class.java) 553 folder.scrollPauseAlarm = Mockito.mock(Alarm::class.java) 554 555 folder.onDragExit(dragObject) 556 557 verify(folder.reorderAlarm, times(1)).cancelAlarm() 558 verify(folder.onScrollHintAlarm, times(1)).cancelAlarm() 559 verify(folder.scrollPauseAlarm, times(1)).cancelAlarm() 560 assertEquals(folder.scrollHintDir, SCROLL_NONE) 561 } 562 563 @Test when calling prepareAccessibilityDrop we should cancel pending reorder alarm and call onAlarmnull564 fun `when calling prepareAccessibilityDrop we should cancel pending reorder alarm and call onAlarm`() { 565 folder.reorderAlarm = Mockito.mock(Alarm::class.java) 566 folder.mReorderAlarmListener = Mockito.mock(OnAlarmListener::class.java) 567 `when`(folder.reorderAlarm.alarmPending()).thenReturn(true) 568 569 folder.prepareAccessibilityDrop() 570 571 verify(folder.reorderAlarm, times(1)).cancelAlarm() 572 verify(folder.mReorderAlarmListener, times(1)).onAlarm(folder.reorderAlarm) 573 } 574 575 @Test when calling prepareAccessibilityDrop we should not do anything if there is no pending alarmnull576 fun `when calling prepareAccessibilityDrop we should not do anything if there is no pending alarm`() { 577 folder.reorderAlarm = Mockito.mock(Alarm::class.java) 578 folder.mReorderAlarmListener = Mockito.mock(OnAlarmListener::class.java) 579 `when`(folder.reorderAlarm.alarmPending()).thenReturn(false) 580 581 folder.prepareAccessibilityDrop() 582 583 verify(folder.reorderAlarm, times(0)).cancelAlarm() 584 verify(folder.mReorderAlarmListener, times(0)).onAlarm(folder.reorderAlarm) 585 } 586 587 @Test isDropEnabled should be true as long as state is not STATE_ANIMATINGnull588 fun `isDropEnabled should be true as long as state is not STATE_ANIMATING`() { 589 folder.state = STATE_CLOSED 590 591 val isDropEnabled = folder.isDropEnabled 592 593 assertTrue(isDropEnabled) 594 } 595 596 @Test isDropEnabled should be false if state is STATE_ANIMATINGnull597 fun `isDropEnabled should be false if state is STATE_ANIMATING`() { 598 folder.state = STATE_ANIMATING 599 600 val isDropEnabled = folder.isDropEnabled 601 602 assertFalse(isDropEnabled) 603 } 604 605 @Test getItemCount should return the number of items in the foldernull606 fun `getItemCount should return the number of items in the folder`() { 607 val folderInfo = 608 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 609 folder.mInfo = folderInfo 610 611 val itemCount = folder.itemCount 612 613 assertEquals(itemCount, 2) 614 } 615 616 @Test hideItem should set the visibility of the corresponding ItemInfo to invisiblenull617 fun `hideItem should set the visibility of the corresponding ItemInfo to invisible`() { 618 val itemInfo = ItemInfo() 619 val view = View(context) 620 view.isVisible = true 621 doReturn(view).whenever(folder).getViewForInfo(itemInfo) 622 623 folder.hideItem(itemInfo) 624 625 assertFalse(view.isVisible) 626 } 627 628 @Test showItem should set the visibility of the corresponding ItemInfo to visiblenull629 fun `showItem should set the visibility of the corresponding ItemInfo to visible`() { 630 val itemInfo = ItemInfo() 631 val view = View(context) 632 view.isVisible = false 633 doReturn(view).whenever(folder).getViewForInfo(itemInfo) 634 635 folder.showItem(itemInfo) 636 637 assertTrue(view.isVisible) 638 } 639 640 @Test onDragEnter should cancel exit alarm and set the scroll area offset to dragRegionWidth divided by two minus xOffsetnull641 fun `onDragEnter should cancel exit alarm and set the scroll area offset to dragRegionWidth divided by two minus xOffset`() { 642 folder.mPrevTargetRank = 1 643 val dragObject = Mockito.mock(DragObject::class.java) 644 val dragView = Mockito.mock(DragView::class.java) 645 dragObject.dragView = dragView 646 folder.onExitAlarm = Mockito.mock(Alarm::class.java) 647 `when`(dragObject.dragView.getDragRegionWidth()).thenReturn(100) 648 dragObject.xOffset = 20 649 650 folder.onDragEnter(dragObject) 651 652 verify(folder.onExitAlarm, times(1)).cancelAlarm() 653 assertEquals(-1, folder.mPrevTargetRank) 654 assertEquals(30, folder.scrollAreaOffset) 655 } 656 657 @Test acceptDrop should return true with the correct item type as a parameternull658 fun `acceptDrop should return true with the correct item type as a parameter`() { 659 val dragObject = Mockito.mock(DragObject::class.java) 660 val itemInfo = Mockito.mock(ItemInfo::class.java) 661 itemInfo.itemType = ITEM_TYPE_APP_PAIR 662 dragObject.dragInfo = itemInfo 663 664 val result = folder.acceptDrop(dragObject) 665 666 assertTrue(result) 667 } 668 669 @Test acceptDrop should return false with the incorrect item type as a parameternull670 fun `acceptDrop should return false with the incorrect item type as a parameter`() { 671 val dragObject = Mockito.mock(DragObject::class.java) 672 val itemInfo = Mockito.mock(ItemInfo::class.java) 673 itemInfo.itemType = ITEM_TYPE_APPWIDGET 674 dragObject.dragInfo = itemInfo 675 676 val result = folder.acceptDrop(dragObject) 677 678 assertFalse(result) 679 } 680 681 @Test rearrangeChildren should return early if content view are not boundnull682 fun `rearrangeChildren should return early if content view are not bound`() { 683 folder.mContent = Mockito.mock(FolderPagedView::class.java) 684 folder.itemsInvalidated = false 685 doReturn(false).whenever(folder.mContent).areViewsBound() 686 687 folder.rearrangeChildren() 688 689 verify(folder.mContent, times(0)).arrangeChildren(folder.iconsInReadingOrder) 690 assertFalse(folder.itemsInvalidated) 691 } 692 693 @Test rearrangeChildren should call arrange children and invalidate itemsnull694 fun `rearrangeChildren should call arrange children and invalidate items`() { 695 folder.mContent = Mockito.mock(FolderPagedView::class.java) 696 folder.itemsInvalidated = false 697 doReturn(true).whenever(folder.mContent).areViewsBound() 698 val iconsInReadingOrderList = ArrayList<View>() 699 `when`(folder.iconsInReadingOrder).thenReturn(iconsInReadingOrderList) 700 doNothing().`when`(folder.mContent).arrangeChildren(iconsInReadingOrderList) 701 702 folder.rearrangeChildren() 703 704 verify(folder.mContent, times(1)).arrangeChildren(folder.iconsInReadingOrder) 705 assertTrue(folder.itemsInvalidated) 706 } 707 708 @Test getItemCount should return the size of info getContents sizenull709 fun `getItemCount should return the size of info getContents size`() { 710 val folderInfo = 711 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 712 folder.mInfo = folderInfo 713 714 val itemCount = folder.itemCount 715 716 assertEquals(2, itemCount) 717 } 718 719 @Test replaceFolderWithFinalItem should set mDestroyed to true if we replace folder with final itemnull720 fun `replaceFolderWithFinalItem should set mDestroyed to true if we replace folder with final item`() { 721 val launcherDelegate = Mockito.mock(LauncherDelegate::class.java) 722 folder.mLauncherDelegate = launcherDelegate 723 `when`(folder.mLauncherDelegate.replaceFolderWithFinalItem(folder)).thenReturn(true) 724 725 folder.replaceFolderWithFinalItem() 726 727 assertTrue(folder.isDestroyed) 728 } 729 730 @Test replaceFolderWithFinalItem should set mDestroyed to false if we do not replace folder with final itemnull731 fun `replaceFolderWithFinalItem should set mDestroyed to false if we do not replace folder with final item`() { 732 val launcherDelegate = Mockito.mock(LauncherDelegate::class.java) 733 folder.mLauncherDelegate = launcherDelegate 734 `when`(folder.mLauncherDelegate.replaceFolderWithFinalItem(folder)).thenReturn(false) 735 736 folder.replaceFolderWithFinalItem() 737 738 assertFalse(folder.isDestroyed) 739 } 740 741 @Test getContentAreaHeight should return maxContentAreaHeightnull742 fun `getContentAreaHeight should return maxContentAreaHeight`() { 743 folder.mContent = Mockito.mock(FolderPagedView::class.java) 744 `when`(folder.mContent.desiredHeight).thenReturn(100) 745 `when`(folder.maxContentAreaHeight).thenReturn(50) 746 747 val height = folder.contentAreaHeight 748 749 assertEquals(50, height) 750 } 751 752 @Test getContentAreaHeight should return desiredHeightnull753 fun `getContentAreaHeight should return desiredHeight`() { 754 folder.mContent = Mockito.mock(FolderPagedView::class.java) 755 `when`(folder.mContent.desiredHeight).thenReturn(50) 756 `when`(folder.maxContentAreaHeight).thenReturn(100) 757 758 val height = folder.contentAreaHeight 759 760 assertEquals(50, height) 761 } 762 763 @Test getContentAreaHeight should return MIN_CONTENT_DIMENnull764 fun `getContentAreaHeight should return MIN_CONTENT_DIMEN`() { 765 folder.mContent = Mockito.mock(FolderPagedView::class.java) 766 `when`(folder.mContent.desiredHeight).thenReturn(1) 767 `when`(folder.maxContentAreaHeight).thenReturn(2) 768 769 val height = folder.contentAreaHeight 770 771 assertEquals(MIN_CONTENT_DIMEN, height) 772 } 773 774 @Test getContentAreaWidth should return desired widthnull775 fun `getContentAreaWidth should return desired width`() { 776 folder.mContent = Mockito.mock(FolderPagedView::class.java) 777 `when`(folder.mContent.desiredWidth).thenReturn(50) 778 779 val width = folder.contentAreaWidth 780 781 assertEquals(50, width) 782 } 783 784 @Test getContentAreaWidth should return MIN_CONTENT_DIMENnull785 fun `getContentAreaWidth should return MIN_CONTENT_DIMEN`() { 786 folder.mContent = Mockito.mock(FolderPagedView::class.java) 787 `when`(folder.mContent.desiredWidth).thenReturn(1) 788 789 val width = folder.contentAreaWidth 790 791 assertEquals(MIN_CONTENT_DIMEN, width) 792 } 793 794 @Test getFolderWidth should return padding left plus padding right plus desired widthnull795 fun `getFolderWidth should return padding left plus padding right plus desired width`() { 796 folder.mContent = Mockito.mock(FolderPagedView::class.java) 797 `when`(folder.mContent.desiredWidth).thenReturn(1) 798 `when`(folder.paddingLeft).thenReturn(10) 799 `when`(folder.paddingRight).thenReturn(10) 800 801 val width = folder.folderWidth 802 803 assertEquals(21, width) 804 } 805 806 @Test getFolderHeight with no params should return getFolderHeightnull807 fun `getFolderHeight with no params should return getFolderHeight`() { 808 folder.mContent = Mockito.mock(FolderPagedView::class.java) 809 `when`(folder.contentAreaHeight).thenReturn(100) 810 `when`(folder.getFolderHeight(folder.contentAreaHeight)).thenReturn(120) 811 812 val height = folder.folderHeight 813 814 assertEquals(120, height) 815 } 816 817 @Test getFolderWidth with contentAreaHeight should return padding top plus padding bottom plus contentAreaHeight plus footer heightnull818 fun `getFolderWidth with contentAreaHeight should return padding top plus padding bottom plus contentAreaHeight plus footer height`() { 819 folder.mContent = Mockito.mock(FolderPagedView::class.java) 820 `when`(folder.footerHeight).thenReturn(100) 821 `when`(folder.paddingTop).thenReturn(10) 822 `when`(folder.paddingBottom).thenReturn(10) 823 824 val height = folder.getFolderHeight(100) 825 826 assertEquals(220, height) 827 } 828 829 @Test onRemove should call removeItem with the correct viewsnull830 fun `onRemove should call removeItem with the correct views`() { 831 val folderInfo = 832 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 833 val items = folderInfo.getContents().toTypedArray() 834 folder.mInfo = folderInfo 835 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 836 folder.mContent = Mockito.mock(FolderPagedView::class.java) 837 val view1 = Mockito.mock(View::class.java) 838 val view2 = Mockito.mock(View::class.java) 839 doReturn(view1).whenever(folder).getViewForInfo(items[0]) 840 doReturn(view2).whenever(folder).getViewForInfo(items[1]) 841 doReturn(2).whenever(folder).itemCount 842 843 folder.removeFolderContent(false, *items) 844 845 verify(folder.mContent, times(1)).removeItem(view1) 846 verify(folder.mContent, times(1)).removeItem(view2) 847 } 848 849 @Test onRemove should set mRearrangeOnClose to true and not call rearrangeChildren if animatingnull850 fun `onRemove should set mRearrangeOnClose to true and not call rearrangeChildren if animating`() { 851 val folderInfo = 852 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 853 val items = folderInfo.getContents().toTypedArray() 854 folder.mInfo = folderInfo 855 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 856 folder.mContent = Mockito.mock(FolderPagedView::class.java) 857 folder.state = STATE_ANIMATING 858 val view1 = Mockito.mock(View::class.java) 859 val view2 = Mockito.mock(View::class.java) 860 doReturn(view1).whenever(folder).getViewForInfo(items[0]) 861 doReturn(view2).whenever(folder).getViewForInfo(items[1]) 862 doReturn(2).whenever(folder).itemCount 863 864 folder.removeFolderContent(true, *items) 865 866 assertTrue(folder.rearrangeOnClose) 867 verify(folder, times(0)).rearrangeChildren() 868 } 869 870 @Test onRemove should set not change mRearrangeOnClose and not call rearrangeChildren if not animatingnull871 fun `onRemove should set not change mRearrangeOnClose and not call rearrangeChildren if not animating`() { 872 val folderInfo = 873 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 874 val items = folderInfo.getContents().toTypedArray() 875 folder.mInfo = folderInfo 876 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 877 folder.mContent = Mockito.mock(FolderPagedView::class.java) 878 folder.state = STATE_CLOSED 879 folder.rearrangeOnClose = false 880 val view1 = Mockito.mock(View::class.java) 881 val view2 = Mockito.mock(View::class.java) 882 doReturn(view1).whenever(folder).getViewForInfo(items[0]) 883 doReturn(view2).whenever(folder).getViewForInfo(items[1]) 884 doReturn(2).whenever(folder).itemCount 885 886 folder.removeFolderContent(false, *items) 887 888 assertFalse(folder.rearrangeOnClose) 889 verify(folder, times(1)).rearrangeChildren() 890 } 891 892 @Test onRemove should call close if mIsOpen is true and item count is less than or equal to onenull893 fun `onRemove should call close if mIsOpen is true and item count is less than or equal to one`() { 894 val folderInfo = 895 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 896 val items = folderInfo.getContents().toTypedArray() 897 folder.mInfo = folderInfo 898 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 899 folder.mContent = Mockito.mock(FolderPagedView::class.java) 900 val view1 = Mockito.mock(View::class.java) 901 val view2 = Mockito.mock(View::class.java) 902 doReturn(view1).whenever(folder).getViewForInfo(items[0]) 903 doReturn(view2).whenever(folder).getViewForInfo(items[1]) 904 doReturn(1).whenever(folder).itemCount 905 folder.setIsOpen(true) 906 doNothing().`when`(folder).close(true) 907 908 folder.removeFolderContent(false, *items) 909 910 verify(folder, times(1)).close(true) 911 } 912 913 @Test onRemove should call replaceFolderWithFinalItem if mIsOpen is false and item count is less than or equal to onenull914 fun `onRemove should call replaceFolderWithFinalItem if mIsOpen is false and item count is less than or equal to one`() { 915 val folderInfo = 916 workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0) 917 val items = folderInfo.getContents().toTypedArray() 918 folder.mInfo = folderInfo 919 folder.mFolderIcon = Mockito.mock(FolderIcon::class.java) 920 folder.mContent = Mockito.mock(FolderPagedView::class.java) 921 val view1 = Mockito.mock(View::class.java) 922 val view2 = Mockito.mock(View::class.java) 923 doReturn(view1).whenever(folder).getViewForInfo(items[0]) 924 doReturn(view2).whenever(folder).getViewForInfo(items[1]) 925 doReturn(1).whenever(folder).itemCount 926 folder.setIsOpen(false) 927 928 folder.removeFolderContent(false, *items) 929 930 verify(folder, times(1)).replaceFolderWithFinalItem() 931 } 932 933 companion object { 934 const val TWO_ICON_FOLDER_TYPE = 'A' 935 } 936 } 937