From 8cceeffe0b7a2b2fe517bb0534154d4da2706096 Mon Sep 17 00:00:00 2001 From: "jorgegil@google.com" Date: Wed, 18 Nov 2020 18:18:44 -0800 Subject: [PATCH] Add unit tests and cleanup PipBoundsState 1. Adds missing unit tests 2. Cleans up public API (nullability and doc) 3. Renames AnimatingBoundsState to MotionBoundsState to improve readability of what that state actually holds, that is, the state of the "bounds in motion" which can be the bounds used during an animation but also the bounds used during a drag or resize operation. Bug: 169373982 Test: atest com.android.wm.shell.pip Change-Id: I951fa3ea1310b69c93b53a1690c0a1cf0632dd33 --- .../android/wm/shell/pip/PipBoundsState.java | 142 ++++++++---------- .../wm/shell/pip/phone/PipMotionHelper.java | 40 ++--- .../wm/shell/pip/phone/PipTouchHandler.java | 14 +- .../wm/shell/pip/PipBoundsStateTest.java | 34 +++++ 4 files changed, 126 insertions(+), 104 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index ce1139b4264d7..53aa614774832 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -59,42 +59,39 @@ public final class PipBoundsState { private final @NonNull Rect mExpandedBounds = new Rect(); private final @NonNull Rect mNormalMovementBounds = new Rect(); private final @NonNull Rect mExpandedMovementBounds = new Rect(); - private final Context mContext; + private final @NonNull Context mContext; private float mAspectRatio; private int mStashedState = STASH_TYPE_NONE; private int mStashOffset; - private PipReentryState mPipReentryState; - private ComponentName mLastPipComponentName; - private final DisplayInfo mDisplayInfo = new DisplayInfo(); - private final DisplayLayout mDisplayLayout = new DisplayLayout(); + private @Nullable PipReentryState mPipReentryState; + private @Nullable ComponentName mLastPipComponentName; + private final @NonNull DisplayInfo mDisplayInfo = new DisplayInfo(); + private final @NonNull DisplayLayout mDisplayLayout = new DisplayLayout(); /** The current minimum edge size of PIP. */ private int mMinEdgeSize; /** The preferred minimum (and default) size specified by apps. */ - private Size mOverrideMinSize; - private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState(); + private @Nullable Size mOverrideMinSize; + private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState(); private boolean mIsImeShowing; private int mImeHeight; private boolean mIsShelfShowing; private int mShelfHeight; - private Runnable mOnMinimalSizeChangeCallback; - private BiConsumer mOnShelfVisibilityChangeCallback; + private @Nullable Runnable mOnMinimalSizeChangeCallback; + private @Nullable BiConsumer mOnShelfVisibilityChangeCallback; - public PipBoundsState(Context context) { + public PipBoundsState(@NonNull Context context) { mContext = context; reloadResources(); } - /** - * Reloads the resources. - */ + /** Reloads the resources. */ public void onConfigurationChanged() { reloadResources(); } private void reloadResources() { - mStashOffset = mContext.getResources() - .getDimensionPixelSize(R.dimen.pip_stash_offset); + mStashOffset = mContext.getResources().getDimensionPixelSize(R.dimen.pip_stash_offset); } /** Set the current PIP bounds. */ @@ -102,12 +99,14 @@ public final class PipBoundsState { mBounds.set(bounds); } + /** Get the current PIP bounds. */ @NonNull public Rect getBounds() { return new Rect(mBounds); } /** Returns the current movement bounds. */ + @NonNull public Rect getMovementBounds() { return mMovementBounds; } @@ -135,28 +134,28 @@ public final class PipBoundsState { } /** Set the normal movement bounds. */ - public void setNormalMovementBounds(Rect bounds) { + public void setNormalMovementBounds(@NonNull Rect bounds) { mNormalMovementBounds.set(bounds); } /** Returns the normal movement bounds. */ + @NonNull public Rect getNormalMovementBounds() { return mNormalMovementBounds; } /** Set the expanded movement bounds. */ - public void setExpandedMovementBounds(Rect bounds) { + public void setExpandedMovementBounds(@NonNull Rect bounds) { mExpandedMovementBounds.set(bounds); } /** Returns the expanded movement bounds. */ + @NonNull public Rect getExpandedMovementBounds() { return mExpandedMovementBounds; } - /** - * Dictate where PiP currently should be stashed, if at all. - */ + /** Dictate where PiP currently should be stashed, if at all. */ public void setStashed(@StashType int stashedState) { mStashedState = stashedState; } @@ -169,50 +168,39 @@ public final class PipBoundsState { return mStashedState; } - /** - * Whether PiP is stashed or not. - */ + /** Whether PiP is stashed or not. */ public boolean isStashed() { return mStashedState != STASH_TYPE_NONE; } - /** - * Returns the offset from the edge of the screen for PiP stash. - */ + /** Returns the offset from the edge of the screen for PiP stash. */ public int getStashOffset() { return mStashOffset; } + /** Set the PIP aspect ratio. */ public void setAspectRatio(float aspectRatio) { mAspectRatio = aspectRatio; } + /** Get the PIP aspect ratio. */ public float getAspectRatio() { return mAspectRatio; } - /** - * Save the reentry state to restore to when re-entering PIP mode. - * - * TODO(b/169373982): consider refactoring this so that this class alone can use mBounds and - * calculate the snap fraction to save for re-entry. - */ + /** Save the reentry state to restore to when re-entering PIP mode. */ public void saveReentryState(@NonNull Rect bounds, float fraction) { mPipReentryState = new PipReentryState(new Size(bounds.width(), bounds.height()), fraction); } - /** - * Returns the saved reentry state. - */ + /** Returns the saved reentry state. */ @Nullable public PipReentryState getReentryState() { return mPipReentryState; } - /** - * Set the last {@link ComponentName} to enter PIP mode. - */ - public void setLastPipComponentName(ComponentName lastPipComponentName) { + /** Set the last {@link ComponentName} to enter PIP mode. */ + public void setLastPipComponentName(@Nullable ComponentName lastPipComponentName) { final boolean changed = !Objects.equals(mLastPipComponentName, lastPipComponentName); mLastPipComponentName = lastPipComponentName; if (changed) { @@ -220,41 +208,40 @@ public final class PipBoundsState { } } + /** Get the last PIP component name, if any. */ + @Nullable public ComponentName getLastPipComponentName() { return mLastPipComponentName; } + /** Get the current display info. */ @NonNull public DisplayInfo getDisplayInfo() { return mDisplayInfo; } - /** - * Update the display info. - */ + /** Update the display info. */ public void setDisplayInfo(@NonNull DisplayInfo displayInfo) { mDisplayInfo.copyFrom(displayInfo); } + /** Set the rotation of the display. */ public void setDisplayRotation(int rotation) { mDisplayInfo.rotation = rotation; } - /** - * Returns the display's bound. - */ + /** Returns the display's bounds. */ @NonNull public Rect getDisplayBounds() { return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); } - /** - * Update the display layout. - */ + /** Update the display layout. */ public void setDisplayLayout(@NonNull DisplayLayout displayLayout) { mDisplayLayout.set(displayLayout); } + /** Get the display layout. */ @NonNull public DisplayLayout getDisplayLayout() { return mDisplayLayout; @@ -275,10 +262,8 @@ public final class PipBoundsState { return mMinEdgeSize; } - /** - * Sets the preferred size of PIP as specified by the activity in PIP mode. - */ - public void setOverrideMinSize(Size overrideMinSize) { + /** Sets the preferred size of PIP as specified by the activity in PIP mode. */ + public void setOverrideMinSize(@Nullable Size overrideMinSize) { final boolean changed = !Objects.equals(overrideMinSize, mOverrideMinSize); mOverrideMinSize = overrideMinSize; if (changed && mOnMinimalSizeChangeCallback != null) { @@ -287,6 +272,7 @@ public final class PipBoundsState { } /** Returns the preferred minimal size specified by the activity in PIP. */ + @Nullable public Size getOverrideMinSize() { return mOverrideMinSize; } @@ -297,8 +283,10 @@ public final class PipBoundsState { return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight()); } - public AnimatingBoundsState getAnimatingBoundsState() { - return mAnimatingBoundsState; + /** Get the state of the bounds in motion. */ + @NonNull + public MotionBoundsState getMotionBoundsState() { + return mMotionBoundsState; } /** Set whether the IME is currently showing and its height. */ @@ -344,41 +332,41 @@ public final class PipBoundsState { /** * Registers a callback when the minimal size of PIP that is set by the app changes. */ - public void setOnMinimalSizeChangeCallback(Runnable onMinimalSizeChangeCallback) { + public void setOnMinimalSizeChangeCallback(@Nullable Runnable onMinimalSizeChangeCallback) { mOnMinimalSizeChangeCallback = onMinimalSizeChangeCallback; } /** Set a callback to be notified when the shelf visibility changes. */ public void setOnShelfVisibilityChangeCallback( - BiConsumer onShelfVisibilityChangeCallback) { + @Nullable BiConsumer onShelfVisibilityChangeCallback) { mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback; } - /** Source of truth for the current animation bounds of PIP. */ - public static class AnimatingBoundsState { - /** The bounds used when PIP is being dragged or animated. */ - private final Rect mTemporaryBounds = new Rect(); + /** Source of truth for the current bounds of PIP that may be in motion. */ + public static class MotionBoundsState { + /** The bounds used when PIP is in motion (e.g. during a drag or animation) */ + private final @NonNull Rect mBoundsInMotion = new Rect(); /** The destination bounds to which PIP is animating. */ - private final Rect mAnimatingToBounds = new Rect(); + private final @NonNull Rect mAnimatingToBounds = new Rect(); /** Whether PIP is being dragged or animated (e.g. resizing, in fling, etc). */ - public boolean isAnimating() { - return !mTemporaryBounds.isEmpty(); + public boolean isInMotion() { + return !mBoundsInMotion.isEmpty(); } /** Set the temporary bounds used to represent the drag or animation bounds of PIP. */ - public void setTemporaryBounds(Rect bounds) { - mTemporaryBounds.set(bounds); + public void setBoundsInMotion(@NonNull Rect bounds) { + mBoundsInMotion.set(bounds); } /** Set the bounds to which PIP is animating. */ - public void setAnimatingToBounds(Rect bounds) { + public void setAnimatingToBounds(@NonNull Rect bounds) { mAnimatingToBounds.set(bounds); } - /** Called when all ongoing dragging and animation operations have ended. */ + /** Called when all ongoing motion operations have ended. */ public void onAllAnimationsEnded() { - mTemporaryBounds.setEmpty(); + mBoundsInMotion.setEmpty(); } /** Called when an ongoing physics animation has ended. */ @@ -386,20 +374,22 @@ public final class PipBoundsState { mAnimatingToBounds.setEmpty(); } - /** Returns the temporary animation bounds. */ - public Rect getTemporaryBounds() { - return mTemporaryBounds; + /** Returns the motion bounds. */ + @NonNull + public Rect getBoundsInMotion() { + return mBoundsInMotion; } /** Returns the destination bounds to which PIP is currently animating. */ + @NonNull public Rect getAnimatingToBounds() { return mAnimatingToBounds; } void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; - pw.println(prefix + AnimatingBoundsState.class.getSimpleName()); - pw.println(innerPrefix + "mTemporaryBounds=" + mTemporaryBounds); + pw.println(prefix + MotionBoundsState.class.getSimpleName()); + pw.println(innerPrefix + "mBoundsInMotion=" + mBoundsInMotion); pw.println(innerPrefix + "mAnimatingToBounds=" + mAnimatingToBounds); } } @@ -432,9 +422,7 @@ public final class PipBoundsState { } } - /** - * Dumps internal state. - */ + /** Dumps internal state. */ public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); @@ -461,6 +449,6 @@ public final class PipBoundsState { } else { mPipReentryState.dump(pw, innerPrefix); } - mAnimatingBoundsState.dump(pw, innerPrefix); + mMotionBoundsState.dump(pw, innerPrefix); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java index 8fa944886905e..903f7d7738966 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java @@ -90,7 +90,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, }); /** - * PhysicsAnimator instance for animating {@link PipBoundsState#getAnimatingBoundsState()} + * PhysicsAnimator instance for animating {@link PipBoundsState#getMotionBoundsState()} * using physics animations. */ private final PhysicsAnimator mTemporaryBoundsPhysicsAnimator; @@ -98,7 +98,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private MagnetizedObject mMagnetizedPip; /** - * Update listener that resizes the PIP to {@link PipBoundsState#getAnimatingBoundsState()}. + * Update listener that resizes the PIP to {@link PipBoundsState#getMotionBoundsState()}. */ private final PhysicsAnimator.UpdateListener mResizePipUpdateListener; @@ -172,14 +172,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mFloatingContentCoordinator = floatingContentCoordinator; mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback); mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance( - mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds()); + mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler( mSfAnimationHandlerThreadLocal.get()); mResizePipUpdateListener = (target, values) -> { - if (mPipBoundsState.getAnimatingBoundsState().isAnimating()) { + if (mPipBoundsState.getMotionBoundsState().isInMotion()) { mPipTaskOrganizer.scheduleUserResizePip(getBounds(), - mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds(), null); + mPipBoundsState.getMotionBoundsState().getBoundsInMotion(), null); } }; } @@ -187,8 +187,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, @NonNull @Override public Rect getFloatingBoundsOnScreen() { - return !mPipBoundsState.getAnimatingBoundsState().getAnimatingToBounds().isEmpty() - ? mPipBoundsState.getAnimatingBoundsState().getAnimatingToBounds() : getBounds(); + return !mPipBoundsState.getMotionBoundsState().getAnimatingToBounds().isEmpty() + ? mPipBoundsState.getMotionBoundsState().getAnimatingToBounds() : getBounds(); } @NonNull @@ -207,7 +207,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, */ void synchronizePinnedStackBounds() { cancelPhysicsAnimation(); - mPipBoundsState.getAnimatingBoundsState().onAllAnimationsEnded(); + mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded(); if (mPipTaskOrganizer.isInPip()) { mFloatingContentCoordinator.onContentMoved(this); @@ -242,7 +242,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, resizePipUnchecked(toBounds); mPipBoundsState.setBounds(toBounds); } else { - mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(toBounds); + mPipBoundsState.getMotionBoundsState().setBoundsInMotion(toBounds); mPipTaskOrganizer.scheduleUserResizePip(getBounds(), toBounds, (Rect newBounds) -> { mMainHandler.post(() -> { @@ -278,8 +278,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // If we're already in the dismiss target area, then there won't be a move to set the // temporary bounds, so just initialize it to the current bounds. - if (!mPipBoundsState.getAnimatingBoundsState().isAnimating()) { - mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(getBounds()); + if (!mPipBoundsState.getMotionBoundsState().isInMotion()) { + mPipBoundsState.getMotionBoundsState().setBoundsInMotion(getBounds()); } mTemporaryBoundsPhysicsAnimator .spring(FloatProperties.RECT_X, destinationX, velX, mSpringConfig) @@ -396,7 +396,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, final float xEndValue = velocityX < 0 ? leftEdge : rightEdge; - final int startValueY = mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds().top; + final int startValueY = mPipBoundsState.getMotionBoundsState().getBoundsInMotion().top; final float estimatedFlingYEndValue = PhysicsAnimator.estimateFlingEndValue(startValueY, velocityY, mFlingConfigY); @@ -411,7 +411,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, void animateToBounds(Rect bounds, PhysicsAnimator.SpringConfig springConfig) { if (!mTemporaryBoundsPhysicsAnimator.isRunning()) { // Animate from the current bounds if we're not already animating. - mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(getBounds()); + mPipBoundsState.getMotionBoundsState().setBoundsInMotion(getBounds()); } mTemporaryBoundsPhysicsAnimator @@ -492,7 +492,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, */ private void cancelPhysicsAnimation() { mTemporaryBoundsPhysicsAnimator.cancel(); - mPipBoundsState.getAnimatingBoundsState().onPhysicsAnimationEnded(); + mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded(); mSpringingToTouch = false; } @@ -565,17 +565,17 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) { - // All animations (including dragging) have actually finished. + // All motion operations have actually finished. mPipBoundsState.setBounds( - mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds()); - mPipBoundsState.getAnimatingBoundsState().onAllAnimationsEnded(); + mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); + mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded(); if (!mDismissalPending) { // do not schedule resize if PiP is dismissing, which may cause app re-open to // mBounds instead of it's normal bounds. mPipTaskOrganizer.scheduleFinishResizePip(getBounds()); } } - mPipBoundsState.getAnimatingBoundsState().onPhysicsAnimationEnded(); + mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded(); mSpringingToTouch = false; mDismissalPending = false; } @@ -586,7 +586,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}. */ private void setAnimatingToBounds(Rect bounds) { - mPipBoundsState.getAnimatingBoundsState().setAnimatingToBounds(bounds); + mPipBoundsState.getMotionBoundsState().setAnimatingToBounds(bounds); mFloatingContentCoordinator.onContentMoved(this); } @@ -625,7 +625,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, MagnetizedObject getMagnetizedPip() { if (mMagnetizedPip == null) { mMagnetizedPip = new MagnetizedObject( - mContext, mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds(), + mContext, mPipBoundsState.getMotionBoundsState().getBoundsInMotion(), FloatProperties.RECT_X, FloatProperties.RECT_Y) { @Override public float getWidth(@NonNull Rect animatedPipBounds) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index 48fa2115305da..a78c4ecdb39f1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -706,7 +706,7 @@ public class PipTouchHandler { return; } - Rect bounds = getPossiblyAnimatingBounds(); + Rect bounds = getPossiblyMotionBounds(); mDelta.set(0f, 0f); mStartPosition.set(bounds.left, bounds.top); mMovementWithinDismiss = touchState.getDownTouchPosition().y @@ -745,7 +745,7 @@ public class PipTouchHandler { mDelta.x += left - lastX; mDelta.y += top - lastY; - mTmpBounds.set(getPossiblyAnimatingBounds()); + mTmpBounds.set(getPossiblyMotionBounds()); mTmpBounds.offsetTo((int) left, (int) top); mMotionHelper.movePip(mTmpBounds, true /* isDragging */); @@ -895,12 +895,12 @@ public class PipTouchHandler { } /** - * Returns the PIP bounds if we're not animating, or the current, temporary animating bounds - * otherwise. + * Returns the PIP bounds if we're not in the middle of a motion operation, or the current, + * temporary motion bounds otherwise. */ - Rect getPossiblyAnimatingBounds() { - return mPipBoundsState.getAnimatingBoundsState().isAnimating() - ? mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds() + Rect getPossiblyMotionBounds() { + return mPipBoundsState.getMotionBoundsState().isInMotion() + ? mPipBoundsState.getMotionBoundsState().getBoundsInMotion() : mPipBoundsState.getBounds(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java index 59e10c1890467..4bcca06b592fe 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java @@ -135,4 +135,38 @@ public class PipBoundsStateTest extends ShellTestCase { verify(callback, never()).accept(true, 100); } + + @Test + public void testSetOverrideMinSize_changed_callbackInvoked() { + final Runnable callback = mock(Runnable.class); + mPipBoundsState.setOverrideMinSize(new Size(5, 5)); + mPipBoundsState.setOnMinimalSizeChangeCallback(callback); + + mPipBoundsState.setOverrideMinSize(new Size(10, 10)); + + verify(callback).run(); + } + + @Test + public void testSetOverrideMinSize_notChanged_callbackNotInvoked() { + final Runnable callback = mock(Runnable.class); + mPipBoundsState.setOverrideMinSize(new Size(5, 5)); + mPipBoundsState.setOnMinimalSizeChangeCallback(callback); + + mPipBoundsState.setOverrideMinSize(new Size(5, 5)); + + verify(callback, never()).run(); + } + + @Test + public void testGetOverrideMinEdgeSize() { + mPipBoundsState.setOverrideMinSize(null); + assertEquals(0, mPipBoundsState.getOverrideMinEdgeSize()); + + mPipBoundsState.setOverrideMinSize(new Size(5, 10)); + assertEquals(5, mPipBoundsState.getOverrideMinEdgeSize()); + + mPipBoundsState.setOverrideMinSize(new Size(15, 10)); + assertEquals(10, mPipBoundsState.getOverrideMinEdgeSize()); + } }