• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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