Test Week - Add more coverage for Folder.java
* Refactored Folder class
* 30 methods covered
* Adding more coverage for Folder.java
Bug: 353303621
Test: Not Applicable
Flag: TEST_ONLY
Change-Id: Ibd7ca8c2121ddc71c33f91262b46e593670eadfe
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index db693f0..8b1f42b 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -157,7 +157,8 @@
isOverFolderOrSearchBar = isEventOverView(topView, ev) ||
isEventOverAccessibleDropTargetBar(ev);
if (!isOverFolderOrSearchBar) {
- sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
+ sendTapOutsideFolderAccessibilityEvent(
+ currentFolder.getIsEditingName());
mHoverPointClosesFolder = true;
return true;
}
@@ -167,7 +168,8 @@
isOverFolderOrSearchBar = isEventOverView(topView, ev) ||
isEventOverAccessibleDropTargetBar(ev);
if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) {
- sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
+ sendTapOutsideFolderAccessibilityEvent(
+ currentFolder.getIsEditingName());
mHoverPointClosesFolder = true;
return true;
} else if (!isOverFolderOrSearchBar) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index d3c1a02..287e36d 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -135,7 +135,8 @@
* We avoid measuring {@link #mContent} with a 0 width or height, as this
* results in CellLayout being measured as UNSPECIFIED, which it does not support.
*/
- private static final int MIN_CONTENT_DIMEN = 5;
+ @VisibleForTesting
+ static final int MIN_CONTENT_DIMEN = 5;
public static final int STATE_CLOSED = 0;
public static final int STATE_ANIMATING = 1;
@@ -143,7 +144,8 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_CLOSED, STATE_ANIMATING, STATE_OPEN})
- public @interface FolderState {}
+ public @interface FolderState {
+ }
/**
* Time for which the scroll hint is shown before automatically changing page.
@@ -164,7 +166,7 @@
private static final int FOLDER_COLOR_ANIMATION_DURATION = 200;
private static final int REORDER_DELAY = 250;
- private static final int ON_EXIT_CLOSE_DELAY = 400;
+ static final int ON_EXIT_CLOSE_DELAY = 400;
private static final Rect sTempRect = new Rect();
private static final int MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION = 10;
@@ -184,10 +186,10 @@
|| itemType == ITEM_TYPE_APP_PAIR;
}
- private final Alarm mReorderAlarm = new Alarm(Looper.getMainLooper());
- private final Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper());
- private final Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper());
- final Alarm mScrollPauseAlarm = new Alarm(Looper.getMainLooper());
+ private Alarm mReorderAlarm = new Alarm(Looper.getMainLooper());
+ private Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper());
+ private Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper());
+ private Alarm mScrollPauseAlarm = new Alarm(Looper.getMainLooper());
final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
@@ -197,7 +199,7 @@
// Folder can be displayed in Launcher's activity or a separate window (e.g. Taskbar).
// Anything specific to Launcher should use mLauncherDelegate, otherwise should
// use mActivityContext.
- protected final LauncherDelegate mLauncherDelegate;
+ protected LauncherDelegate mLauncherDelegate;
protected final ActivityContext mActivityContext;
protected DragController mDragController;
@@ -210,7 +212,7 @@
@Thunk
FolderPagedView mContent;
- public FolderNameEditText mFolderName;
+ private FolderNameEditText mFolderName;
private PageIndicatorDots mPageIndicator;
protected View mFooter;
@@ -234,10 +236,10 @@
private OnFolderStateChangedListener mPriorityOnFolderStateChangedListener;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mRearrangeOnClose = false;
- boolean mItemsInvalidated = false;
+ private boolean mItemsInvalidated = false;
private View mCurrentDragView;
private boolean mIsExternalDrag;
- private boolean mDragInProgress = false;
+ private boolean mIsDragInProgress = false;
private boolean mDeleteFolderOnDropCompleted = false;
private boolean mSuppressFolderDeletion = false;
private boolean mItemAddedBackToSelfViaIcon = false;
@@ -250,7 +252,7 @@
private int mScrollAreaOffset;
@Thunk
- int mScrollHintDir = SCROLL_NONE;
+ private int mScrollHintDir = SCROLL_NONE;
@Thunk
int mCurrentScrollDir = SCROLL_NONE;
@@ -315,9 +317,9 @@
| InputType.TYPE_TEXT_FLAG_CAP_WORDS);
mFolderName.forceDisableSuggestions(true);
mFolderName.setPadding(mFolderName.getPaddingLeft(),
- (mFooterHeight - mFolderName.getLineHeight()) / 2,
+ (getFooterHeight() - mFolderName.getLineHeight()) / 2,
mFolderName.getPaddingRight(),
- (mFooterHeight - mFolderName.getLineHeight()) / 2);
+ (getFooterHeight() - mFolderName.getLineHeight()) / 2);
mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
@@ -325,42 +327,54 @@
public boolean onLongClick(View v) {
// Return if global dragging is not enabled
- if (!mLauncherDelegate.isDraggingEnabled()) return true;
+ if (!getIsLauncherDraggingEnabled()) return true;
return startDrag(v, new DragOptions());
}
+ @VisibleForTesting
+ boolean getIsLauncherDraggingEnabled() {
+ return mLauncherDelegate.isDraggingEnabled();
+ }
+
public boolean startDrag(View v, DragOptions options) {
Object tag = v.getTag();
if (tag instanceof ItemInfo item) {
mEmptyCellRank = item.rank;
mCurrentDragView = v;
- mDragController.addDragListener(this);
- if (options.isAccessibleDrag) {
- mDragController.addDragListener(new AccessibleDragListenerAdapter(
- mContent, FolderAccessibilityHelper::new) {
- @Override
- protected void enableAccessibleDrag(boolean enable,
- @Nullable DragObject dragObject) {
- super.enableAccessibleDrag(enable, dragObject);
- mFooter.setImportantForAccessibility(enable
- ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- }
- });
- }
-
- mLauncherDelegate.beginDragShared(v, this, options);
+ addDragListener(options);
+ callBeginDragShared(v, options);
}
return true;
}
+ void callBeginDragShared(View v, DragOptions options) {
+ mLauncherDelegate.beginDragShared(v, this, options);
+ }
+
+ void addDragListener(DragOptions options) {
+ getDragController().addDragListener(this);
+ if (!options.isAccessibleDrag) {
+ return;
+ }
+ getDragController().addDragListener(new AccessibleDragListenerAdapter(
+ mContent, FolderAccessibilityHelper::new) {
+ @Override
+ protected void enableAccessibleDrag(boolean enable,
+ @Nullable DragObject dragObject) {
+ super.enableAccessibleDrag(enable, dragObject);
+ mFooter.setImportantForAccessibility(enable
+ ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
+ });
+ }
+
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
if (dragObject.dragSource != this) {
return;
}
-
mContent.removeItem(mCurrentDragView);
mItemsInvalidated = true;
@@ -369,29 +383,23 @@
try (SuppressInfoChanges s = new SuppressInfoChanges()) {
mInfo.remove(dragObject.dragInfo, true);
}
- mDragInProgress = true;
+ mIsDragInProgress = true;
mItemAddedBackToSelfViaIcon = false;
}
@Override
public void onDragEnd() {
- if (mIsExternalDrag && mDragInProgress) {
+ if (mIsExternalDrag && mIsDragInProgress) {
completeDragExit();
}
- mDragInProgress = false;
- mDragController.removeDragListener(this);
- }
-
- public boolean isEditingName() {
- return mIsEditingName;
+ mIsDragInProgress = false;
+ getDragController().removeDragListener(this);
}
public void startEditingFolderName() {
- post(() -> {
- showLabelSuggestions();
- mFolderName.setHint("");
- mIsEditingName = true;
- });
+ showLabelSuggestions();
+ mFolderName.setHint("");
+ mIsEditingName = true;
}
@Override
@@ -459,7 +467,11 @@
return mFolderIcon;
}
- public void setDragController(DragController dragController) {
+ DragController getDragController() {
+ return mDragController;
+ }
+
+ void setDragController(DragController dragController) {
mDragController = dragController;
}
@@ -540,7 +552,7 @@
* Show suggested folder title in FolderEditText if the first suggestion is non-empty, push
* rest of the suggestions to InputMethodManager.
*/
- private void showLabelSuggestions() {
+ void showLabelSuggestions() {
if (mInfo.suggestedFolderNames == null) {
return;
}
@@ -634,11 +646,11 @@
*/
public void beginExternalDrag() {
mIsExternalDrag = true;
- mDragInProgress = true;
+ mIsDragInProgress = true;
// Since this folder opened by another controller, it might not get onDrop or
// onDropComplete. Perform cleanup once drag-n-drop ends.
- mDragController.addDragListener(this);
+ getDragController().addDragListener(this);
ArrayList<ItemInfo> items = new ArrayList<>(mInfo.getContents());
mEmptyCellRank = items.size();
@@ -662,16 +674,12 @@
* is played.
*/
private void animateOpen(List<ItemInfo> items, int pageNo) {
- if (items == null || items.size() <= 1) {
- Log.d(TAG, "Couldn't animate folder open because items is: " + items);
+ if (!shouldAnimateOpen(items)) {
return;
}
Folder openFolder = getOpen(mActivityContext);
- if (openFolder != null && openFolder != this) {
- // Close any open folder before opening a folder.
- openFolder.close(true);
- }
+ closeOpenFolder(openFolder);
mContent.bindItems(items);
centerAboutIcon();
@@ -685,7 +693,7 @@
// There was a one-off crash where the folder had a parent already.
if (getParent() == null) {
dragLayer.addView(this);
- mDragController.addDropTarget(this);
+ getDragController().addDropTarget(this);
} else {
if (FeatureFlags.IS_STUDIO_BUILD) {
Log.e(TAG, "Opening folder (" + this + ") which already has a parent:"
@@ -734,7 +742,7 @@
// Do not update the flag if we are in drag mode. The flag will be updated, when we
// actually drop the icon.
- final boolean updateAnimationFlag = !mDragInProgress;
+ final boolean updateAnimationFlag = !mIsDragInProgress;
anim.addListener(new AnimatorListenerAdapter() {
@SuppressLint("InlinedApi")
@@ -768,12 +776,36 @@
anim.start();
// Make sure the folder picks up the last drag move even if the finger doesn't move.
- if (mDragController.isDragging()) {
- mDragController.forceTouchMove();
+ if (getDragController().isDragging()) {
+ getDragController().forceTouchMove();
}
mContent.verifyVisibleHighResIcons(mContent.getNextPage());
}
+ /**
+ * Determines whether we should animate the folder opening.
+ */
+ boolean shouldAnimateOpen(List<ItemInfo> items) {
+ if (items == null || items.size() <= 1) {
+ Log.d(TAG, "Couldn't animate folder open because items is: " + items);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * If there's a folder already open, we want to close it before opening another one.
+ */
+ @VisibleForTesting
+ boolean closeOpenFolder(Folder openFolder) {
+ if (openFolder != null && openFolder != this) {
+ // Close any open folder before opening a folder.
+ openFolder.close(true);
+ return true;
+ }
+ return false;
+ }
+
@Override
protected boolean isOfType(int type) {
return (type & TYPE_FOLDER) != 0;
@@ -787,7 +819,7 @@
mCurrentAnimator.cancel();
}
- if (isEditingName()) {
+ if (mIsEditingName) {
mFolderName.dispatchBackKey();
}
@@ -871,7 +903,7 @@
if (parent != null) {
parent.removeView(this);
}
- mDragController.removeDropTarget(this);
+ getDragController().removeDropTarget(this);
clearFocus();
if (mFolderIcon != null) {
mFolderIcon.setVisibility(View.VISIBLE);
@@ -892,12 +924,12 @@
mRearrangeOnClose = false;
}
if (getItemCount() <= 1) {
- if (!mDragInProgress && !mSuppressFolderDeletion) {
+ if (!mIsDragInProgress && !mSuppressFolderDeletion) {
replaceFolderWithFinalItem();
- } else if (mDragInProgress) {
+ } else if (mIsDragInProgress) {
mDeleteFolderOnDropCompleted = true;
}
- } else if (!mDragInProgress) {
+ } else if (!mIsDragInProgress) {
mContent.unbindItems();
}
mSuppressFolderDeletion = false;
@@ -1017,7 +1049,8 @@
}
}
- private void clearDragInfo() {
+ @VisibleForTesting
+ void clearDragInfo() {
mCurrentDragView = null;
mIsExternalDrag = false;
}
@@ -1058,7 +1091,8 @@
if (getItemCount() <= 1) {
mDeleteFolderOnDropCompleted = true;
}
- if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon && target != this) {
+ if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon
+ && target != this) {
replaceFolderWithFinalItem();
}
} else {
@@ -1089,7 +1123,7 @@
}
mDeleteFolderOnDropCompleted = false;
- mDragInProgress = false;
+ mIsDragInProgress = false;
mItemAddedBackToSelfViaIcon = false;
mCurrentDragView = null;
@@ -1132,7 +1166,7 @@
}
public void notifyDrop() {
- if (mDragInProgress) {
+ if (mIsDragInProgress) {
mItemAddedBackToSelfViaIcon = true;
}
}
@@ -1175,28 +1209,41 @@
}
protected int getContentAreaHeight() {
- DeviceProfile grid = mActivityContext.getDeviceProfile();
- int maxContentAreaHeight = grid.availableHeightPx - grid.getTotalWorkspacePadding().y
- - mFooterHeight;
- int height = Math.min(maxContentAreaHeight,
+ int height = Math.min(getMaxContentAreaHeight(),
mContent.getDesiredHeight());
return Math.max(height, MIN_CONTENT_DIMEN);
}
- private int getContentAreaWidth() {
+ @VisibleForTesting
+ int getMaxContentAreaHeight() {
+ DeviceProfile grid = mActivityContext.getDeviceProfile();
+ return grid.availableHeightPx - grid.getTotalWorkspacePadding().y
+ - getFooterHeight();
+ }
+
+ @VisibleForTesting
+ int getContentAreaWidth() {
return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN);
}
- private int getFolderWidth() {
+ @VisibleForTesting
+ int getFolderWidth() {
return getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
}
- private int getFolderHeight() {
+ @VisibleForTesting
+ int getFolderHeight() {
return getFolderHeight(getContentAreaHeight());
}
- private int getFolderHeight(int contentAreaHeight) {
- return getPaddingTop() + getPaddingBottom() + contentAreaHeight + mFooterHeight;
+ @VisibleForTesting
+ int getFolderHeight(int contentAreaHeight) {
+ return getPaddingTop() + getPaddingBottom() + contentAreaHeight + getFooterHeight();
+ }
+
+ @VisibleForTesting
+ int getFooterHeight() {
+ return mFooterHeight;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -1366,7 +1413,7 @@
}
// Clear the drag info, as it is no longer being dragged.
- mDragInProgress = false;
+ mIsDragInProgress = false;
if (mContent.getPageCount() > 1) {
// The animation has already been shown while opening the folder.
@@ -1435,7 +1482,8 @@
}
}
- private View getViewForInfo(final ItemInfo item) {
+ @VisibleForTesting
+ View getViewForInfo(final ItemInfo item) {
return mContent.iterateOverItems((info, view) -> info == item);
}
@@ -1493,7 +1541,7 @@
if (hasFocus) {
mFromLabelState = mInfo.getFromLabelState();
mFromTitle = mInfo.title;
- startEditingFolderName();
+ post(this::startEditingFolderName);
} else {
StatsLogger statsLogger = mStatsLogManager.logger()
.withItemInfo(mInfo)
@@ -1626,7 +1674,7 @@
/** Navigation bar back key or hardware input back key has been issued. */
@Override
public void onBackInvoked() {
- if (isEditingName()) {
+ if (mIsEditingName) {
mFolderName.dispatchBackKey();
} else {
super.onBackInvoked();
@@ -1638,7 +1686,7 @@
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
BaseDragLayer dl = (BaseDragLayer) getParent();
- if (isEditingName()) {
+ if (mIsEditingName) {
if (!dl.isEventOverView(mFolderName, ev)) {
mFolderName.dispatchBackKey();
return true;
@@ -1685,6 +1733,95 @@
return mContent;
}
+ @VisibleForTesting
+ void setItemAddedBackToSelfViaIcon(boolean value) {
+ mItemAddedBackToSelfViaIcon = value;
+ }
+
+ @VisibleForTesting
+ boolean getItemAddedBackToSelfViaIcon() {
+ return mItemAddedBackToSelfViaIcon;
+ }
+
+ @VisibleForTesting
+ void setIsDragInProgress(boolean value) {
+ mIsDragInProgress = value;
+ }
+
+ @VisibleForTesting
+ boolean getIsDragInProgress() {
+ return mIsDragInProgress;
+ }
+
+ @VisibleForTesting
+ View getCurrentDragView() {
+ return mCurrentDragView;
+ }
+
+ @VisibleForTesting
+ void setCurrentDragView(View view) {
+ mCurrentDragView = view;
+ }
+
+ @VisibleForTesting
+ boolean getItemsInvalidated() {
+ return mItemsInvalidated;
+ }
+
+ @VisibleForTesting
+ void setItemsInvalidated(boolean value) {
+ mItemsInvalidated = value;
+ }
+
+ @VisibleForTesting
+ boolean getIsExternalDrag() {
+ return mIsExternalDrag;
+ }
+
+ @VisibleForTesting
+ void setIsExternalDrag(boolean value) {
+ mIsExternalDrag = value;
+ }
+
+ public boolean getIsEditingName() {
+ return mIsEditingName;
+ }
+
+ @VisibleForTesting
+ void setIsEditingName(boolean value) {
+ mIsEditingName = value;
+ }
+
+ @VisibleForTesting
+ void setFolderName(FolderNameEditText value) {
+ mFolderName = value;
+ }
+
+ @VisibleForTesting
+ FolderNameEditText getFolderName() {
+ return mFolderName;
+ }
+
+ @VisibleForTesting
+ boolean getIsOpen() {
+ return mIsOpen;
+ }
+
+ @VisibleForTesting
+ void setIsOpen(boolean value) {
+ mIsOpen = value;
+ }
+
+ @VisibleForTesting
+ boolean getRearrangeOnClose() {
+ return mRearrangeOnClose;
+ }
+
+ @VisibleForTesting
+ void setRearrangeOnClose(boolean value) {
+ mRearrangeOnClose = value;
+ }
+
/** Returns the height of the current folder's bottom edge from the bottom of the screen. */
private int getHeightFromBottom() {
BaseDragLayer.LayoutParams layoutParams = (BaseDragLayer.LayoutParams) getLayoutParams();
@@ -1695,10 +1832,15 @@
}
@VisibleForTesting
- public boolean getDeleteFolderOnDropCompleted() {
+ boolean getDeleteFolderOnDropCompleted() {
return mDeleteFolderOnDropCompleted;
}
+ @VisibleForTesting
+ void setDeleteFolderOnDropCompleted(boolean value) {
+ mDeleteFolderOnDropCompleted = value;
+ }
+
/**
* Save this listener for the special case of when we update the state and concurrently
* add another listener to {@link #mOnFolderStateChangedListeners} to avoid a
@@ -1708,7 +1850,13 @@
mPriorityOnFolderStateChangedListener = listener;
}
- private void setState(@FolderState int newState) {
+ @VisibleForTesting
+ int getState() {
+ return mState;
+ }
+
+ @VisibleForTesting
+ void setState(@FolderState int newState) {
mState = newState;
if (mPriorityOnFolderStateChangedListener != null) {
mPriorityOnFolderStateChangedListener.onFolderStateChanged(mState);
@@ -1720,6 +1868,60 @@
}
}
+ @VisibleForTesting
+ Alarm getOnExitAlarm() {
+ return mOnExitAlarm;
+ }
+
+ @VisibleForTesting
+ void setOnExitAlarm(Alarm value) {
+ mOnExitAlarm = value;
+ }
+
+ @VisibleForTesting
+ Alarm getReorderAlarm() {
+ return mReorderAlarm;
+ }
+
+ @VisibleForTesting
+ void setReorderAlarm(Alarm value) {
+ mReorderAlarm = value;
+ }
+
+ @VisibleForTesting
+ Alarm getOnScrollHintAlarm() {
+ return mOnScrollHintAlarm;
+ }
+
+ @VisibleForTesting
+ void setOnScrollHintAlarm(Alarm value) {
+ mOnScrollHintAlarm = value;
+ }
+
+ @VisibleForTesting
+ Alarm getScrollPauseAlarm() {
+ return mScrollPauseAlarm;
+ }
+
+ @VisibleForTesting
+ void setScrollPauseAlarm(Alarm value) {
+ mScrollPauseAlarm = value;
+ }
+
+ @VisibleForTesting
+ int getScrollHintDir() {
+ return mScrollHintDir;
+ }
+
+ @VisibleForTesting
+ void setScrollHintDir(int value) {
+ mScrollHintDir = value;
+ }
+
+ @VisibleForTesting
+ int getScrollAreaOffset() {
+ return mScrollAreaOffset;
+ }
/**
* Adds the provided listener to the running list of Folder listeners
* {@link #mOnFolderStateChangedListeners}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 37a8d9b..0fdb9d7 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -255,8 +255,8 @@
mFolder.getContent(), contentStart, contentEnd, finalRadius, !mIsOpening));
// Fade in the folder name, as the text can overlap the icons when grid size is small.
- mFolder.mFolderName.setAlpha(mIsOpening ? 0f : 1f);
- play(a, getAnimator(mFolder.mFolderName, View.ALPHA, 0, 1),
+ mFolder.getFolderName().setAlpha(mIsOpening ? 0f : 1f);
+ play(a, getAnimator(mFolder.getFolderName(), View.ALPHA, 0, 1),
mIsOpening ? FOLDER_NAME_ALPHA_DURATION : 0,
mIsOpening ? mDuration - FOLDER_NAME_ALPHA_DURATION : FOLDER_NAME_ALPHA_DURATION);
@@ -317,7 +317,7 @@
mFolder.mFooter.setScaleX(1f);
mFolder.mFooter.setScaleY(1f);
mFolder.mFooter.setTranslationX(0f);
- mFolder.mFolderName.setAlpha(1f);
+ mFolder.getFolderName().setAlpha(1f);
mFolder.setClipChildren(mFolderClipChildren);
mFolder.setClipToPadding(mFolderClipToPadding);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 00636a3..9b50a3f 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -458,7 +458,7 @@
mInfo.setTitle(newTitle, mFolder.mLauncherDelegate.getModelWriter());
onTitleChanged(mInfo.title);
- mFolder.mFolderName.setText(mInfo.title);
+ mFolder.getFolderName().setText(mInfo.title);
// Logging for folder creation flow
StatsLogManager.newInstance(getContext()).logger()
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 8eaa0dc..bb4c913 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -361,8 +361,8 @@
// Update footer
mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
// Set the gravity as LEFT or RIGHT instead of START, as START depends on the actual text.
- mFolder.mFolderName.setGravity(getPageCount() > 1 ?
- (mIsRtl ? Gravity.RIGHT : Gravity.LEFT) : Gravity.CENTER_HORIZONTAL);
+ mFolder.getFolderName().setGravity(getPageCount() > 1
+ ? (mIsRtl ? Gravity.RIGHT : Gravity.LEFT) : Gravity.CENTER_HORIZONTAL);
}
public int getDesiredWidth() {
diff --git a/tests/src/com/android/launcher3/folder/FolderTest.kt b/tests/src/com/android/launcher3/folder/FolderTest.kt
index e1daa74..4eb335e 100644
--- a/tests/src/com/android/launcher3/folder/FolderTest.kt
+++ b/tests/src/com/android/launcher3/folder/FolderTest.kt
@@ -18,23 +18,56 @@
import android.content.Context
import android.graphics.Point
+import android.view.KeyEvent
import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.widget.TextView
+import androidx.core.view.isVisible
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.launcher3.Alarm
+import com.android.launcher3.DragSource
import com.android.launcher3.DropTarget.DragObject
import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.OnAlarmListener
+import com.android.launcher3.R
import com.android.launcher3.celllayout.board.FolderPoint
import com.android.launcher3.celllayout.board.TestWorkspaceBuilder
+import com.android.launcher3.dragndrop.DragController
+import com.android.launcher3.dragndrop.DragOptions
+import com.android.launcher3.dragndrop.DragView
+import com.android.launcher3.folder.Folder.MIN_CONTENT_DIMEN
+import com.android.launcher3.folder.Folder.ON_EXIT_CLOSE_DELAY
+import com.android.launcher3.folder.Folder.SCROLL_LEFT
+import com.android.launcher3.folder.Folder.SCROLL_NONE
+import com.android.launcher3.folder.Folder.STATE_ANIMATING
+import com.android.launcher3.folder.Folder.STATE_CLOSED
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.util.ActivityContextWrapper
import com.android.launcher3.util.ModelTestExtensions.clearModelDb
+import java.util.ArrayList
import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertFalse
+import junit.framework.TestCase.assertNull
+import junit.framework.TestCase.assertTrue
import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
+import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.whenever
/** Tests for [Folder] */
@SmallTest
@@ -44,7 +77,7 @@
private val context: Context =
ActivityContextWrapper(ApplicationProvider.getApplicationContext())
private val workspaceBuilder = TestWorkspaceBuilder(context)
- private val folder: Folder = Mockito.spy(Folder(context, null))
+ private val folder: Folder = spy(Folder(context, null))
@After
fun tearDown() {
@@ -60,8 +93,10 @@
folder.mContent = Mockito.mock(FolderPagedView::class.java)
val dragLayout = Mockito.mock(View::class.java)
val dragObject = Mockito.mock(DragObject::class.java)
- assertEquals(folder.deleteFolderOnDropCompleted, false)
+ folder.deleteFolderOnDropCompleted = false
+
folder.onDropCompleted(dragLayout, dragObject, true)
+
verify(folder, times(1)).replaceFolderWithFinalItem()
assertEquals(folder.deleteFolderOnDropCompleted, false)
}
@@ -74,12 +109,819 @@
folder.mContent = Mockito.mock(FolderPagedView::class.java)
val dragLayout = Mockito.mock(View::class.java)
val dragObject = Mockito.mock(DragObject::class.java)
- assertEquals(folder.deleteFolderOnDropCompleted, false)
+ folder.deleteFolderOnDropCompleted = false
+
folder.onDropCompleted(dragLayout, dragObject, true)
+
verify(folder, times(0)).replaceFolderWithFinalItem()
assertEquals(folder.deleteFolderOnDropCompleted, false)
}
+ @Test
+ fun `Test that we accept valid item type ITEM_TYPE_APPLICATION`() {
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_APPLICATION
+
+ val willAcceptResult = Folder.willAccept(itemInfo)
+
+ assertTrue(willAcceptResult)
+ }
+
+ @Test
+ fun `Test that we accept valid item type ITEM_TYPE_DEEP_SHORTCUT`() {
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_DEEP_SHORTCUT
+
+ val willAcceptResult = Folder.willAccept(itemInfo)
+
+ assertTrue(willAcceptResult)
+ }
+
+ @Test
+ fun `Test that we accept valid item type ITEM_TYPE_APP_PAIR`() {
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_APP_PAIR
+
+ val willAcceptResult = Folder.willAccept(itemInfo)
+
+ assertTrue(willAcceptResult)
+ }
+
+ @Test
+ fun `Test that we do not accept invalid item type ITEM_TYPE_APPWIDGET`() {
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_APPWIDGET
+
+ val willAcceptResult = Folder.willAccept(itemInfo)
+
+ assertFalse(willAcceptResult)
+ }
+
+ @Test
+ fun `Test that we do not accept invalid item type ITEM_TYPE_FOLDER`() {
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_FOLDER
+
+ val willAcceptResult = Folder.willAccept(itemInfo)
+
+ assertFalse(willAcceptResult)
+ }
+
+ @Test
+ fun `We should not animate open if items is null or less than or equal to 1`() {
+ folder.mInfo = Mockito.mock(FolderInfo::class.java)
+ val shouldAnimateOpenResult = folder.shouldAnimateOpen(null)
+
+ assertFalse(shouldAnimateOpenResult)
+ assertFalse(
+ folder.shouldAnimateOpen(arrayListOf<ItemInfo>(Mockito.mock(ItemInfo::class.java)))
+ )
+ }
+
+ @Test
+ fun `We should animate open if items greater than 1`() {
+ val folderInfo =
+ workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+ folder.mInfo = folderInfo
+
+ val shouldAnimateOpenResult = folder.shouldAnimateOpen(folder.mInfo.getContents())
+
+ assertTrue(shouldAnimateOpenResult)
+ }
+
+ @Test
+ fun `Should be true if there is an open folder`() {
+ val closeOpenFolderResult = folder.closeOpenFolder(Mockito.mock(Folder::class.java))
+
+ assertTrue(closeOpenFolderResult)
+ }
+
+ @Test
+ fun `Should be false if the open folder is this folder`() {
+ val closeOpenFolderResult = folder.closeOpenFolder(folder)
+
+ assertFalse(closeOpenFolderResult)
+ }
+
+ @Test
+ fun `Should be false if there is not an open folder`() {
+ val closeOpenFolderResult = folder.closeOpenFolder(null)
+
+ assertFalse(closeOpenFolderResult)
+ }
+
+ @Test
+ fun `If drag is in progress we should set mItemAddedBackToSelfViaIcon to true`() {
+ folder.itemAddedBackToSelfViaIcon = false
+ folder.isDragInProgress = true
+
+ folder.notifyDrop()
+
+ assertTrue(folder.itemAddedBackToSelfViaIcon)
+ }
+
+ @Test
+ fun `If drag is not in progress we should not set mItemAddedBackToSelfViaIcon to true`() {
+ folder.itemAddedBackToSelfViaIcon = false
+ folder.isDragInProgress = false
+
+ folder.notifyDrop()
+
+ assertFalse(folder.itemAddedBackToSelfViaIcon)
+ }
+
+ @Test
+ fun `If launcher dragging is not enabled onLongClick should return true`() {
+ `when`(folder.isLauncherDraggingEnabled).thenReturn(false)
+
+ val onLongClickResult = folder.onLongClick(Mockito.mock(View::class.java))
+
+ assertTrue(onLongClickResult)
+ }
+
+ @Test
+ fun `If launcher dragging is enabled we should return startDrag result`() {
+ `when`(folder.isLauncherDraggingEnabled).thenReturn(true)
+ val viewMock = Mockito.mock(View::class.java)
+ val dragOptions = Mockito.mock(DragOptions::class.java)
+
+ val onLongClickResult = folder.onLongClick(viewMock)
+
+ assertEquals(onLongClickResult, folder.startDrag(viewMock, dragOptions))
+ verify(folder, times(1)).startDrag(viewMock, dragOptions)
+ }
+
+ @Test
+ fun `Verify start drag works as intended when view is instanceof ItemInfo`() {
+ val itemInfo = ItemInfo()
+ itemInfo.rank = 5
+ val viewMock = Mockito.mock(View::class.java)
+ val dragOptions = DragOptions()
+ `when`(viewMock.tag).thenReturn(itemInfo)
+ folder.dragController = Mockito.mock(DragController::class.java)
+
+ folder.startDrag(viewMock, dragOptions)
+
+ assertEquals(folder.mEmptyCellRank, 5)
+ assertEquals(folder.currentDragView, viewMock)
+ verify(folder, times(1)).addDragListener(dragOptions)
+ verify(folder, times(1)).callBeginDragShared(viewMock, dragOptions)
+ }
+
+ @Test
+ fun `Verify start drag works as intended when view is not instanceof ItemInfo`() {
+ val viewMock = Mockito.mock(View::class.java)
+ val dragOptions = DragOptions()
+
+ folder.startDrag(viewMock, dragOptions)
+
+ verify(folder, times(0)).addDragListener(dragOptions)
+ verify(folder, times(0)).callBeginDragShared(viewMock, dragOptions)
+ }
+
+ @Test
+ fun `Verify that onDragStart has an effect if dragSource is this folder`() {
+ folder.itemsInvalidated = false
+ folder.isDragInProgress = false
+ folder.itemAddedBackToSelfViaIcon = true
+ folder.currentDragView = Mockito.mock(View::class.java)
+ val folderInfo =
+ workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+ folder.mInfo = spy(folderInfo)
+ val dragObject = DragObject(context)
+ dragObject.dragInfo = Mockito.mock(ItemInfo::class.java)
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ dragObject.dragSource = folder
+
+ folder.onDragStart(dragObject, DragOptions())
+
+ verify(folder.mContent, times(1)).removeItem(folder.currentDragView)
+ verify(folder.mInfo, times(1)).remove(dragObject.dragInfo, true)
+ assertTrue(folder.itemsInvalidated)
+ assertTrue(folder.isDragInProgress)
+ assertFalse(folder.itemAddedBackToSelfViaIcon)
+ }
+
+ @Test
+ fun `Verify that onDragStart has no effects if dragSource is not this folder`() {
+ folder.itemsInvalidated = false
+ folder.isDragInProgress = false
+ folder.itemAddedBackToSelfViaIcon = true
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ val dragObject = DragObject(context)
+ dragObject.dragSource = Mockito.mock(DragSource::class.java)
+
+ folder.onDragStart(dragObject, DragOptions())
+
+ verify(folder.mContent, times(0)).removeItem(folder.currentDragView)
+ assertFalse(folder.itemsInvalidated)
+ assertFalse(folder.isDragInProgress)
+ assertTrue(folder.itemAddedBackToSelfViaIcon)
+ }
+
+ @Test
+ fun `Verify onDragEnd that we call completeDragExit and set drag in progress false`() {
+ doNothing().`when`(folder).completeDragExit()
+ folder.isExternalDrag = true
+ folder.isDragInProgress = true
+ folder.dragController = Mockito.mock(DragController::class.java)
+
+ folder.onDragEnd()
+
+ verify(folder, times(1)).completeDragExit()
+ verify(folder.dragController, times(1)).removeDragListener(folder)
+ assertFalse(folder.isDragInProgress)
+ }
+
+ @Test
+ fun `Verify onDragEnd that we do not call completeDragExit and set drag in progress false`() {
+ folder.isExternalDrag = false
+ folder.isDragInProgress = true
+ folder.dragController = Mockito.mock(DragController::class.java)
+
+ folder.onDragEnd()
+
+ verify(folder, times(0)).completeDragExit()
+ verify(folder.dragController, times(1)).removeDragListener(folder)
+ assertFalse(folder.isDragInProgress)
+ }
+
+ @Test
+ fun `startEditingFolderName should set hint to empty and showLabelSuggestions`() {
+ doNothing().`when`(folder).showLabelSuggestions()
+ folder.isEditingName = false
+ folder.folderName = FolderNameEditText(context)
+ folder.folderName.hint = "hello"
+
+ folder.startEditingFolderName()
+
+ verify(folder, times(1)).showLabelSuggestions()
+ assertEquals("", folder.folderName.hint)
+ assertTrue(folder.isEditingName)
+ }
+
+ @Test
+ fun `Ensure we set the title and hint correctly onBackKey when we have a new title`() {
+ val expectedHint = null
+ val expectedTitle = "hello"
+ folder.isEditingName = true
+ folder.folderName = spy(FolderNameEditText(context))
+ folder.folderName.setText(expectedTitle)
+ val folderInfo =
+ workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+ folder.mInfo = spy(folderInfo)
+ folder.mInfo.title = "world"
+ folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
+
+ folder.onBackKey()
+
+ assertEquals(expectedTitle, folder.mInfo.title)
+ verify(folder.mFolderIcon, times(1)).onTitleChanged(expectedTitle)
+ assertEquals(expectedHint, folder.folderName.hint)
+ assertFalse(folder.isEditingName)
+ verify(folder.folderName, times(1)).clearFocus()
+ }
+
+ @Test
+ fun `Ensure we set the title and hint correctly onBackKey when we do not have a new title`() {
+ val expectedHint = context.getString(R.string.folder_hint_text)
+ val expectedTitle = ""
+ folder.isEditingName = true
+ folder.folderName = spy(FolderNameEditText(context))
+ folder.folderName.setText(expectedTitle)
+ val folderInfo =
+ workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+ folder.mInfo = spy(folderInfo)
+ folder.mInfo.title = "world"
+ folder.mFolderIcon = Mockito.mock(FolderIcon::class.java)
+
+ folder.onBackKey()
+
+ assertEquals(expectedTitle, folder.mInfo.title)
+ verify(folder.mFolderIcon, times(1)).onTitleChanged(expectedTitle)
+ assertEquals(expectedHint, folder.folderName.hint)
+ assertFalse(folder.isEditingName)
+ verify(folder.folderName, times(1)).clearFocus()
+ }
+
+ @Test
+ fun `ensure onEditorAction calls dispatchBackKey when actionId is IME_ACTION_DONE`() {
+ folder.folderName = Mockito.mock(FolderNameEditText::class.java)
+
+ val result =
+ folder.onEditorAction(
+ Mockito.mock(TextView::class.java),
+ EditorInfo.IME_ACTION_DONE,
+ Mockito.mock(KeyEvent::class.java)
+ )
+
+ assertTrue(result)
+ verify(folder.folderName, times(1)).dispatchBackKey()
+ }
+
+ @Test
+ fun `ensure onEditorAction does not call dispatchBackKey when actionId is not IME_ACTION_DONE`() {
+ folder.folderName = Mockito.mock(FolderNameEditText::class.java)
+
+ val result =
+ folder.onEditorAction(
+ Mockito.mock(TextView::class.java),
+ EditorInfo.IME_ACTION_NONE,
+ Mockito.mock(KeyEvent::class.java)
+ )
+
+ assertFalse(result)
+ verify(folder.folderName, times(0)).dispatchBackKey()
+ }
+
+ @Test
+ fun `in completeDragExit we close the folder when mIsOpen`() {
+ doNothing().`when`(folder).close(true)
+ folder.setIsOpen(true)
+ folder.rearrangeOnClose = false
+
+ folder.completeDragExit()
+
+ verify(folder, times(1)).close(true)
+ assertTrue(folder.rearrangeOnClose)
+ }
+
+ @Test
+ fun `in completeDragExit we want to rearrange on close when it is animating`() {
+ folder.setIsOpen(false)
+ folder.rearrangeOnClose = false
+ folder.state = STATE_ANIMATING
+
+ folder.completeDragExit()
+
+ verify(folder, times(0)).close(true)
+ assertTrue(folder.rearrangeOnClose)
+ }
+
+ @Test
+ fun `in completeDragExit we want to call rearrangeChildren and clearDragInfo when not open and not animating`() {
+ doNothing().`when`(folder).rearrangeChildren()
+ doNothing().`when`(folder).clearDragInfo()
+ folder.setIsOpen(false)
+ folder.rearrangeOnClose = false
+ folder.state = STATE_CLOSED
+
+ folder.completeDragExit()
+
+ verify(folder, times(0)).close(true)
+ assertFalse(folder.rearrangeOnClose)
+ verify(folder, times(1)).rearrangeChildren()
+ verify(folder, times(1)).clearDragInfo()
+ }
+
+ @Test
+ fun `clearDragInfo should set current drag view to null and isExternalDrag to false`() {
+ folder.currentDragView = Mockito.mock(DragView::class.java)
+ folder.isExternalDrag = true
+
+ folder.clearDragInfo()
+
+ assertNull(folder.currentDragView)
+ assertFalse(folder.isExternalDrag)
+ }
+
+ @Test
+ fun `onDragExit should set alarm if drag is not complete`() {
+ folder.onExitAlarm = Mockito.mock(Alarm::class.java)
+ val dragObject = Mockito.mock(DragObject::class.java)
+ dragObject.dragComplete = false
+
+ folder.onDragExit(dragObject)
+
+ verify(folder.onExitAlarm, times(1)).setOnAlarmListener(folder.mOnExitAlarmListener)
+ verify(folder.onExitAlarm, times(1)).setAlarm(ON_EXIT_CLOSE_DELAY.toLong())
+ }
+
+ @Test
+ fun `onDragExit should not set alarm if drag is complete`() {
+ folder.onExitAlarm = Mockito.mock(Alarm::class.java)
+ val dragObject = Mockito.mock(DragObject::class.java)
+ dragObject.dragComplete = true
+
+ folder.onDragExit(dragObject)
+
+ verify(folder.onExitAlarm, times(0)).setOnAlarmListener(folder.mOnExitAlarmListener)
+ verify(folder.onExitAlarm, times(0)).setAlarm(ON_EXIT_CLOSE_DELAY.toLong())
+ }
+
+ @Test
+ fun `onDragExit should not clear scroll hint if already SCROLL_NONE`() {
+ folder.onExitAlarm = Mockito.mock(Alarm::class.java)
+ val dragObject = Mockito.mock(DragObject::class.java)
+ folder.scrollHintDir = SCROLL_NONE
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+
+ folder.onDragExit(dragObject)
+
+ verify(folder.mContent, times(0)).clearScrollHint()
+ }
+
+ @Test
+ fun `onDragExit should clear scroll hint if not SCROLL_NONE and then set scroll hint to scroll none`() {
+ folder.onExitAlarm = Mockito.mock(Alarm::class.java)
+ val dragObject = Mockito.mock(DragObject::class.java)
+ folder.scrollHintDir = SCROLL_LEFT
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+
+ folder.onDragExit(dragObject)
+
+ verify(folder.mContent, times(1)).clearScrollHint()
+ assertEquals(folder.scrollHintDir, SCROLL_NONE)
+ }
+
+ @Test
+ fun `onDragExit we should cancel reorder pause and hint alarms`() {
+ folder.onExitAlarm = Mockito.mock(Alarm::class.java)
+ val dragObject = Mockito.mock(DragObject::class.java)
+ folder.scrollHintDir = SCROLL_NONE
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ folder.reorderAlarm = Mockito.mock(Alarm::class.java)
+ folder.onScrollHintAlarm = Mockito.mock(Alarm::class.java)
+ folder.scrollPauseAlarm = Mockito.mock(Alarm::class.java)
+
+ folder.onDragExit(dragObject)
+
+ verify(folder.reorderAlarm, times(1)).cancelAlarm()
+ verify(folder.onScrollHintAlarm, times(1)).cancelAlarm()
+ verify(folder.scrollPauseAlarm, times(1)).cancelAlarm()
+ assertEquals(folder.scrollHintDir, SCROLL_NONE)
+ }
+
+ @Test
+ fun `when calling prepareAccessibilityDrop we should cancel pending reorder alarm and call onAlarm`() {
+ folder.reorderAlarm = Mockito.mock(Alarm::class.java)
+ folder.mReorderAlarmListener = Mockito.mock(OnAlarmListener::class.java)
+ `when`(folder.reorderAlarm.alarmPending()).thenReturn(true)
+
+ folder.prepareAccessibilityDrop()
+
+ verify(folder.reorderAlarm, times(1)).cancelAlarm()
+ verify(folder.mReorderAlarmListener, times(1)).onAlarm(folder.reorderAlarm)
+ }
+
+ @Test
+ fun `when calling prepareAccessibilityDrop we should not do anything if there is no pending alarm`() {
+ folder.reorderAlarm = Mockito.mock(Alarm::class.java)
+ folder.mReorderAlarmListener = Mockito.mock(OnAlarmListener::class.java)
+ `when`(folder.reorderAlarm.alarmPending()).thenReturn(false)
+
+ folder.prepareAccessibilityDrop()
+
+ verify(folder.reorderAlarm, times(0)).cancelAlarm()
+ verify(folder.mReorderAlarmListener, times(0)).onAlarm(folder.reorderAlarm)
+ }
+
+ @Test
+ fun `isDropEnabled should be true as long as state is not STATE_ANIMATING`() {
+ folder.state = STATE_CLOSED
+
+ val isDropEnabled = folder.isDropEnabled
+
+ assertTrue(isDropEnabled)
+ }
+
+ @Test
+ fun `isDropEnabled should be false if state is STATE_ANIMATING`() {
+ folder.state = STATE_ANIMATING
+
+ val isDropEnabled = folder.isDropEnabled
+
+ assertFalse(isDropEnabled)
+ }
+
+ @Test
+ fun `getItemCount should return the number of items in the folder`() {
+ val folderInfo =
+ workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+ folder.mInfo = folderInfo
+
+ val itemCount = folder.itemCount
+
+ assertEquals(itemCount, 2)
+ }
+
+ @Test
+ fun `hideItem should set the visibility of the corresponding ItemInfo to invisible`() {
+ val itemInfo = ItemInfo()
+ val view = View(context)
+ view.isVisible = true
+ doReturn(view).whenever(folder).getViewForInfo(itemInfo)
+
+ folder.hideItem(itemInfo)
+
+ assertFalse(view.isVisible)
+ }
+
+ @Test
+ fun `showItem should set the visibility of the corresponding ItemInfo to visible`() {
+ val itemInfo = ItemInfo()
+ val view = View(context)
+ view.isVisible = false
+ doReturn(view).whenever(folder).getViewForInfo(itemInfo)
+
+ folder.showItem(itemInfo)
+
+ assertTrue(view.isVisible)
+ }
+
+ @Test
+ fun `onDragEnter should cancel exit alarm and set the scroll area offset to dragRegionWidth divided by two minus xOffset`() {
+ folder.mPrevTargetRank = 1
+ val dragObject = Mockito.mock(DragObject::class.java)
+ val dragView = Mockito.mock(DragView::class.java)
+ dragObject.dragView = dragView
+ folder.onExitAlarm = Mockito.mock(Alarm::class.java)
+ `when`(dragObject.dragView.getDragRegionWidth()).thenReturn(100)
+ dragObject.xOffset = 20
+
+ folder.onDragEnter(dragObject)
+
+ verify(folder.onExitAlarm, times(1)).cancelAlarm()
+ assertEquals(-1, folder.mPrevTargetRank)
+ assertEquals(30, folder.scrollAreaOffset)
+ }
+
+ @Test
+ fun `acceptDrop should return true with the correct item type as a parameter`() {
+ val dragObject = Mockito.mock(DragObject::class.java)
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_APP_PAIR
+ dragObject.dragInfo = itemInfo
+
+ val result = folder.acceptDrop(dragObject)
+
+ assertTrue(result)
+ }
+
+ @Test
+ fun `acceptDrop should return false with the incorrect item type as a parameter`() {
+ val dragObject = Mockito.mock(DragObject::class.java)
+ val itemInfo = Mockito.mock(ItemInfo::class.java)
+ itemInfo.itemType = ITEM_TYPE_APPWIDGET
+ dragObject.dragInfo = itemInfo
+
+ val result = folder.acceptDrop(dragObject)
+
+ assertFalse(result)
+ }
+
+ @Test
+ fun `rearrangeChildren should return early if content view are not bound`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ folder.itemsInvalidated = false
+ doReturn(false).whenever(folder.mContent).areViewsBound()
+
+ folder.rearrangeChildren()
+
+ verify(folder.mContent, times(0)).arrangeChildren(folder.iconsInReadingOrder)
+ assertFalse(folder.itemsInvalidated)
+ }
+
+ @Test
+ fun `rearrangeChildren should call arrange children and invalidate items`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ folder.itemsInvalidated = false
+ doReturn(true).whenever(folder.mContent).areViewsBound()
+ val iconsInReadingOrderList = ArrayList<View>()
+ `when`(folder.iconsInReadingOrder).thenReturn(iconsInReadingOrderList)
+ doNothing().`when`(folder.mContent).arrangeChildren(iconsInReadingOrderList)
+
+ folder.rearrangeChildren()
+
+ verify(folder.mContent, times(1)).arrangeChildren(folder.iconsInReadingOrder)
+ assertTrue(folder.itemsInvalidated)
+ }
+
+ @Test
+ fun `getItemCount should return the size of info getContents size`() {
+ val folderInfo =
+ workspaceBuilder.createFolderInCell(FolderPoint(Point(1, 0), TWO_ICON_FOLDER_TYPE), 0)
+ folder.mInfo = folderInfo
+
+ val itemCount = folder.itemCount
+
+ assertEquals(2, itemCount)
+ }
+
+ @Test
+ fun `replaceFolderWithFinalItem should set mDestroyed to true if we replace folder with final item`() {
+ val launcherDelegate = Mockito.mock(LauncherDelegate::class.java)
+ folder.mLauncherDelegate = launcherDelegate
+ `when`(folder.mLauncherDelegate.replaceFolderWithFinalItem(folder)).thenReturn(true)
+
+ folder.replaceFolderWithFinalItem()
+
+ assertTrue(folder.isDestroyed)
+ }
+
+ @Test
+ fun `replaceFolderWithFinalItem should set mDestroyed to false if we do not replace folder with final item`() {
+ val launcherDelegate = Mockito.mock(LauncherDelegate::class.java)
+ folder.mLauncherDelegate = launcherDelegate
+ `when`(folder.mLauncherDelegate.replaceFolderWithFinalItem(folder)).thenReturn(false)
+
+ folder.replaceFolderWithFinalItem()
+
+ assertFalse(folder.isDestroyed)
+ }
+
+ @Test
+ fun `getContentAreaHeight should return maxContentAreaHeight`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.mContent.desiredHeight).thenReturn(100)
+ `when`(folder.maxContentAreaHeight).thenReturn(50)
+
+ val height = folder.contentAreaHeight
+
+ assertEquals(50, height)
+ }
+
+ @Test
+ fun `getContentAreaHeight should return desiredHeight`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.mContent.desiredHeight).thenReturn(50)
+ `when`(folder.maxContentAreaHeight).thenReturn(100)
+
+ val height = folder.contentAreaHeight
+
+ assertEquals(50, height)
+ }
+
+ @Test
+ fun `getContentAreaHeight should return MIN_CONTENT_DIMEN`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.mContent.desiredHeight).thenReturn(1)
+ `when`(folder.maxContentAreaHeight).thenReturn(2)
+
+ val height = folder.contentAreaHeight
+
+ assertEquals(MIN_CONTENT_DIMEN, height)
+ }
+
+ @Test
+ fun `getContentAreaWidth should return desired width`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.mContent.desiredWidth).thenReturn(50)
+
+ val width = folder.contentAreaWidth
+
+ assertEquals(50, width)
+ }
+
+ @Test
+ fun `getContentAreaWidth should return MIN_CONTENT_DIMEN`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.mContent.desiredWidth).thenReturn(1)
+
+ val width = folder.contentAreaWidth
+
+ assertEquals(MIN_CONTENT_DIMEN, width)
+ }
+
+ @Test
+ fun `getFolderWidth should return padding left plus padding right plus desired width`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.mContent.desiredWidth).thenReturn(1)
+ `when`(folder.paddingLeft).thenReturn(10)
+ `when`(folder.paddingRight).thenReturn(10)
+
+ val width = folder.folderWidth
+
+ assertEquals(21, width)
+ }
+
+ @Test
+ fun `getFolderHeight with no params should return getFolderHeight`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.contentAreaHeight).thenReturn(100)
+ `when`(folder.getFolderHeight(folder.contentAreaHeight)).thenReturn(120)
+
+ val height = folder.folderHeight
+
+ assertEquals(120, height)
+ }
+
+ @Test
+ fun `getFolderWidth with contentAreaHeight should return padding top plus padding bottom plus contentAreaHeight plus footer height`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ `when`(folder.footerHeight).thenReturn(100)
+ `when`(folder.paddingTop).thenReturn(10)
+ `when`(folder.paddingBottom).thenReturn(10)
+
+ val height = folder.getFolderHeight(100)
+
+ assertEquals(220, height)
+ }
+
+ @Test
+ fun `onRemove should call removeItem with the correct views`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ val items =
+ arrayListOf<ItemInfo>(
+ Mockito.mock(ItemInfo::class.java),
+ Mockito.mock(ItemInfo::class.java)
+ )
+ val view1 = Mockito.mock(View::class.java)
+ val view2 = Mockito.mock(View::class.java)
+ doReturn(view1).whenever(folder).getViewForInfo(items[0])
+ doReturn(view2).whenever(folder).getViewForInfo(items[1])
+ doReturn(2).whenever(folder).itemCount
+
+ folder.onRemove(items)
+
+ verify(folder.mContent, times(1)).removeItem(view1)
+ verify(folder.mContent, times(1)).removeItem(view2)
+ }
+
+ @Test
+ fun `onRemove should set mRearrangeOnClose to true and not call rearrangeChildren if animating`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ folder.state = STATE_ANIMATING
+ val items =
+ arrayListOf<ItemInfo>(
+ Mockito.mock(ItemInfo::class.java),
+ Mockito.mock(ItemInfo::class.java)
+ )
+ val view1 = Mockito.mock(View::class.java)
+ val view2 = Mockito.mock(View::class.java)
+ doReturn(view1).whenever(folder).getViewForInfo(items[0])
+ doReturn(view2).whenever(folder).getViewForInfo(items[1])
+ doReturn(2).whenever(folder).itemCount
+
+ folder.onRemove(items)
+
+ assertTrue(folder.rearrangeOnClose)
+ verify(folder, times(0)).rearrangeChildren()
+ }
+
+ @Test
+ fun `onRemove should set not change mRearrangeOnClose and not call rearrangeChildren if not animating`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ folder.state = STATE_CLOSED
+ folder.rearrangeOnClose = false
+ val items =
+ arrayListOf<ItemInfo>(
+ Mockito.mock(ItemInfo::class.java),
+ Mockito.mock(ItemInfo::class.java)
+ )
+ val view1 = Mockito.mock(View::class.java)
+ val view2 = Mockito.mock(View::class.java)
+ doReturn(view1).whenever(folder).getViewForInfo(items[0])
+ doReturn(view2).whenever(folder).getViewForInfo(items[1])
+ doReturn(2).whenever(folder).itemCount
+
+ folder.onRemove(items)
+
+ assertFalse(folder.rearrangeOnClose)
+ verify(folder, times(1)).rearrangeChildren()
+ }
+
+ @Test
+ fun `onRemove should call close if mIsOpen is true and item count is less than or equal to one`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ val items =
+ arrayListOf<ItemInfo>(
+ Mockito.mock(ItemInfo::class.java),
+ Mockito.mock(ItemInfo::class.java)
+ )
+ val view1 = Mockito.mock(View::class.java)
+ val view2 = Mockito.mock(View::class.java)
+ doReturn(view1).whenever(folder).getViewForInfo(items[0])
+ doReturn(view2).whenever(folder).getViewForInfo(items[1])
+ doReturn(1).whenever(folder).itemCount
+ folder.setIsOpen(true)
+ doNothing().`when`(folder).close(true)
+
+ folder.onRemove(items)
+
+ verify(folder, times(1)).close(true)
+ }
+
+ @Test
+ fun `onRemove should call replaceFolderWithFinalItem if mIsOpen is false and item count is less than or equal to one`() {
+ folder.mContent = Mockito.mock(FolderPagedView::class.java)
+ val items =
+ arrayListOf<ItemInfo>(
+ Mockito.mock(ItemInfo::class.java),
+ Mockito.mock(ItemInfo::class.java)
+ )
+ val view1 = Mockito.mock(View::class.java)
+ val view2 = Mockito.mock(View::class.java)
+ doReturn(view1).whenever(folder).getViewForInfo(items[0])
+ doReturn(view2).whenever(folder).getViewForInfo(items[1])
+ doReturn(1).whenever(folder).itemCount
+ folder.setIsOpen(false)
+
+ folder.onRemove(items)
+
+ verify(folder, times(1)).replaceFolderWithFinalItem()
+ }
+
companion object {
const val TWO_ICON_FOLDER_TYPE = 'A'
}