diff options
Diffstat (limited to 'src/com/android/launcher3/CellLayout.java')
-rw-r--r-- | src/com/android/launcher3/CellLayout.java | 741 |
1 files changed, 235 insertions, 506 deletions
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index e6865b2e6..2cde3d53d 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -22,6 +22,7 @@ import android.animation.AnimatorSet; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; @@ -33,7 +34,10 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.TransitionDrawable; +import android.os.Build; import android.os.Parcelable; +import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -41,11 +45,16 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; -import android.view.animation.Animation; +import android.view.accessibility.AccessibilityEvent; import android.view.animation.DecelerateInterpolator; -import android.view.animation.LayoutAnimationController; +import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler; import com.android.launcher3.FolderIcon.FolderRingAnimator; +import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate; +import com.android.launcher3.accessibility.FolderAccessibilityHelper; +import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; +import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.PendingAddWidgetInfo; import java.util.ArrayList; import java.util.Arrays; @@ -54,55 +63,47 @@ import java.util.Comparator; import java.util.HashMap; import java.util.Stack; -public class CellLayout extends ViewGroup { +public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { + public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2; + public static final int FOLDER_ACCESSIBILITY_DRAG = 1; + static final String TAG = "CellLayout"; private Launcher mLauncher; - private int mCellWidth; - private int mCellHeight; + @Thunk int mCellWidth; + @Thunk int mCellHeight; private int mFixedCellWidth; private int mFixedCellHeight; - private int mCountX; - private int mCountY; + @Thunk int mCountX; + @Thunk int mCountY; private int mOriginalWidthGap; private int mOriginalHeightGap; - private int mWidthGap; - private int mHeightGap; + @Thunk int mWidthGap; + @Thunk int mHeightGap; private int mMaxGap; private boolean mDropPending = false; private boolean mIsDragTarget = true; // These are temporary variables to prevent having to allocate a new object just to // return an (x, y) value from helper functions. Do NOT use them to maintain other state. - private final int[] mTmpXY = new int[2]; - private final int[] mTmpPoint = new int[2]; - int[] mTempLocation = new int[2]; + @Thunk final int[] mTmpPoint = new int[2]; + @Thunk final int[] mTempLocation = new int[2]; boolean[][] mOccupied; boolean[][] mTmpOccupied; - private boolean mLastDownOnOccupiedCell = false; private OnTouchListener mInterceptTouchListener; + private StylusEventHelper mStylusEventHelper; private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); private int[] mFolderLeaveBehindCell = {-1, -1}; - private float FOREGROUND_ALPHA_DAMPER = 0.65f; - private int mForegroundAlpha = 0; private float mBackgroundAlpha; - private float mBackgroundAlphaMultiplier = 1.0f; - private boolean mDrawBackground = true; - - private Drawable mNormalBackground; - private Drawable mActiveGlowBackground; - private Drawable mOverScrollForegroundDrawable; - private Drawable mOverScrollLeft; - private Drawable mOverScrollRight; - private Rect mBackgroundRect; - private Rect mForegroundRect; - private int mForegroundPadding; + + private static final int BACKGROUND_ACTIVATE_DURATION = 120; + private final TransitionDrawable mBackground; // These values allow a fixed measurement to be set on the CellLayout. private int mFixedWidth = -1; @@ -110,12 +111,11 @@ public class CellLayout extends ViewGroup { // If we're actively dragging something over this screen, mIsDragOverlapping is true private boolean mIsDragOverlapping = false; - boolean mUseActiveGlowBackground = false; // These arrays are used to implement the drag visualization on x-large screens. // They are used as circular arrays, indexed by mDragOutlineCurrent. - private Rect[] mDragOutlines = new Rect[4]; - private float[] mDragOutlineAlphas = new float[mDragOutlines.length]; + @Thunk Rect[] mDragOutlines = new Rect[4]; + @Thunk float[] mDragOutlineAlphas = new float[mDragOutlines.length]; private InterruptibleInOutAnimator[] mDragOutlineAnims = new InterruptibleInOutAnimator[mDragOutlines.length]; @@ -123,12 +123,10 @@ public class CellLayout extends ViewGroup { private int mDragOutlineCurrent = 0; private final Paint mDragOutlinePaint = new Paint(); - private final FastBitmapView mTouchFeedbackView; + private final ClickShadowView mTouchFeedbackView; - private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new - HashMap<CellLayout.LayoutParams, Animator>(); - private HashMap<View, ReorderPreviewAnimation> - mShakeAnimators = new HashMap<View, ReorderPreviewAnimation>(); + @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<>(); + @Thunk HashMap<View, ReorderPreviewAnimation> mShakeAnimators = new HashMap<>(); private boolean mItemPlacementDirty = false; @@ -156,19 +154,22 @@ public class CellLayout extends ViewGroup { private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f; private static final int REORDER_ANIMATION_DURATION = 150; - private float mReorderPreviewAnimationMagnitude; + @Thunk float mReorderPreviewAnimationMagnitude; private ArrayList<View> mIntersectingViews = new ArrayList<View>(); private Rect mOccupiedRect = new Rect(); private int[] mDirectionVector = new int[2]; int[] mPreviousReorderDirection = new int[2]; private static final int INVALID_DIRECTION = -100; - private DropTarget.DragEnforcer mDragEnforcer; - private Rect mTempRect = new Rect(); + private final Rect mTempRect = new Rect(); private final static Paint sPaint = new Paint(); + // Related to accessible drag and drop + private DragAndDropAccessibilityDelegate mTouchHelper; + private boolean mUseTouchHelper = false; + public CellLayout(Context context) { this(context, null); } @@ -179,7 +180,6 @@ public class CellLayout extends ViewGroup { public CellLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mDragEnforcer = new DropTarget.DragEnforcer(context); // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show // the user where a dragged item will land when dropped. @@ -187,8 +187,7 @@ public class CellLayout extends ViewGroup { setClipToPadding(false); mLauncher = (Launcher) context; - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); mCellWidth = mCellHeight = -1; @@ -196,8 +195,8 @@ public class CellLayout extends ViewGroup { mWidthGap = mOriginalWidthGap = 0; mHeightGap = mOriginalHeightGap = 0; mMaxGap = Integer.MAX_VALUE; - mCountX = (int) grid.numColumns; - mCountY = (int) grid.numRows; + mCountX = (int) grid.inv.numColumns; + mCountY = (int) grid.inv.numRows; mOccupied = new boolean[mCountX][mCountY]; mTmpOccupied = new boolean[mCountX][mCountY]; mPreviousReorderDirection[0] = INVALID_DIRECTION; @@ -210,20 +209,12 @@ public class CellLayout extends ViewGroup { final Resources res = getResources(); mHotseatScale = (float) grid.hotseatIconSizePx / grid.iconSizePx; - mNormalBackground = res.getDrawable(R.drawable.screenpanel); - mActiveGlowBackground = res.getDrawable(R.drawable.screenpanel_hover); - - mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); - mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); - mForegroundPadding = - res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); + mBackground = (TransitionDrawable) res.getDrawable(R.drawable.bg_screenpanel); + mBackground.setCallback(this); mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * grid.iconSizePx); - mNormalBackground.setFilterBitmap(true); - mActiveGlowBackground.setFilterBitmap(true); - // Initialize the data structures used for the drag visualization. mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out mDragCell[0] = mDragCell[1] = -1; @@ -281,19 +272,78 @@ public class CellLayout extends ViewGroup { mDragOutlineAnims[i] = anim; } - mBackgroundRect = new Rect(); - mForegroundRect = new Rect(); - mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap, mCountX, mCountY); - mTouchFeedbackView = new FastBitmapView(context); - // Make the feedback view large enough to hold the blur bitmap. - addView(mTouchFeedbackView, (int) (grid.cellWidthPx * 1.5), (int) (grid.cellHeightPx * 1.5)); + mStylusEventHelper = new StylusEventHelper(this); + + mTouchFeedbackView = new ClickShadowView(context); + addView(mTouchFeedbackView); addView(mShortcutsAndWidgets); } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public void enableAccessibleDrag(boolean enable, int dragType) { + mUseTouchHelper = enable; + if (!enable) { + ViewCompat.setAccessibilityDelegate(this, null); + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + setOnClickListener(mLauncher); + } else { + if (dragType == WORKSPACE_ACCESSIBILITY_DRAG && + !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) { + mTouchHelper = new WorkspaceAccessibilityHelper(this); + } else if (dragType == FOLDER_ACCESSIBILITY_DRAG && + !(mTouchHelper instanceof FolderAccessibilityHelper)) { + mTouchHelper = new FolderAccessibilityHelper(this); + } + ViewCompat.setAccessibilityDelegate(this, mTouchHelper); + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + setOnClickListener(mTouchHelper); + } + + // Invalidate the accessibility hierarchy + if (getParent() != null) { + getParent().notifySubtreeAccessibilityStateChanged( + this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); + } + } + + @Override + public boolean dispatchHoverEvent(MotionEvent event) { + // Always attempt to dispatch hover events to accessibility first. + if (mUseTouchHelper && mTouchHelper.dispatchHoverEvent(event)) { + return true; + } + return super.dispatchHoverEvent(event); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (mUseTouchHelper || + (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) { + return true; + } + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + boolean handled = super.onTouchEvent(ev); + // Stylus button press on a home screen should not switch between overview mode and + // the home screen mode, however, once in overview mode stylus button press should be + // enabled to allow rearranging the different home screens. So check what mode + // the workspace is in, and only perform stylus button presses while in overview mode. + if (mLauncher.mWorkspace.isInOverviewMode() + && mStylusEventHelper.checkAndPerformStylusEvent(ev)) { + return true; + } + return handled; + } + public void enableHardwareLayer(boolean hasLayer) { mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint); } @@ -337,47 +387,19 @@ public class CellLayout extends ViewGroup { return mDropPending; } - void setOverScrollAmount(float r, boolean left) { - if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { - mOverScrollForegroundDrawable = mOverScrollLeft; - } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { - mOverScrollForegroundDrawable = mOverScrollRight; - } - - r *= FOREGROUND_ALPHA_DAMPER; - mForegroundAlpha = (int) Math.round((r * 255)); - mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); - invalidate(); - } - - void setPressedIcon(BubbleTextView icon, Bitmap background, int padding) { + @Override + public void setPressedIcon(BubbleTextView icon, Bitmap background) { if (icon == null || background == null) { mTouchFeedbackView.setBitmap(null); mTouchFeedbackView.animate().cancel(); } else { - int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - - (mCountX * mCellWidth); - mTouchFeedbackView.setTranslationX(icon.getLeft() + (int) Math.ceil(offset / 2f) - - padding); - mTouchFeedbackView.setTranslationY(icon.getTop() - padding); if (mTouchFeedbackView.setBitmap(background)) { - mTouchFeedbackView.setAlpha(0); - mTouchFeedbackView.animate().alpha(1) - .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION) - .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR) - .start(); + mTouchFeedbackView.alignWithIconView(icon, mShortcutsAndWidgets); + mTouchFeedbackView.animateShadow(); } } } - void setUseActiveGlowBackground(boolean use) { - mUseActiveGlowBackground = use; - } - - void disableBackground() { - mDrawBackground = false; - } - void disableDragTarget() { mIsDragTarget = false; } @@ -389,7 +411,11 @@ public class CellLayout extends ViewGroup { void setIsDragOverlapping(boolean isDragOverlapping) { if (mIsDragOverlapping != isDragOverlapping) { mIsDragOverlapping = isDragOverlapping; - setUseActiveGlowBackground(mIsDragOverlapping); + if (mIsDragOverlapping) { + mBackground.startTransition(BACKGROUND_ACTIVATE_DURATION); + } else { + mBackground.reverseTransition(BACKGROUND_ACTIVATE_DURATION); + } invalidate(); } } @@ -400,24 +426,17 @@ public class CellLayout extends ViewGroup { @Override protected void onDraw(Canvas canvas) { + if (!mIsDragTarget) { + return; + } + // When we're large, we are either drawn in a "hover" state (ie when dragging an item to // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) // When we're small, we are either drawn normally or in the "accepts drops" state (during // a drag). However, we also drag the mini hover background *over* one of those two // backgrounds - if (mDrawBackground && mBackgroundAlpha > 0.0f) { - Drawable bg; - - if (mUseActiveGlowBackground) { - // In the mini case, we draw the active_glow bg *over* the active background - bg = mActiveGlowBackground; - } else { - bg = mNormalBackground; - } - - bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); - bg.setBounds(mBackgroundRect); - bg.draw(canvas); + if (mBackgroundAlpha > 0.0f) { + mBackground.draw(canvas); } final Paint paint = mDragOutlinePaint; @@ -453,8 +472,7 @@ public class CellLayout extends ViewGroup { int previewOffset = FolderRingAnimator.sPreviewSize; // The folder outer / inner ring image(s) - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile grid = mLauncher.getDeviceProfile(); for (int i = 0; i < mFolderOuterRings.size(); i++) { FolderRingAnimator fra = mFolderOuterRings.get(i); @@ -513,15 +531,6 @@ public class CellLayout extends ViewGroup { } } - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - if (mForegroundAlpha > 0) { - mOverScrollForegroundDrawable.setBounds(mForegroundRect); - mOverScrollForegroundDrawable.draw(canvas); - } - } - public void showFolderAccept(FolderRingAnimator fra) { mFolderOuterRings.add(fra); } @@ -578,11 +587,11 @@ public class CellLayout extends ViewGroup { mInterceptTouchListener = listener; } - int getCountX() { + public int getCountX() { return mCountX; } - int getCountY() { + public int getCountY() { return mCountY; } @@ -591,8 +600,12 @@ public class CellLayout extends ViewGroup { mShortcutsAndWidgets.setIsHotseat(isHotseat); } + public boolean isHotseat() { + return mIsHotseat; + } + public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, - boolean markCells, boolean inLayout) { + boolean markCells) { final LayoutParams lp = params; // Hotseat icons - remove text @@ -613,11 +626,7 @@ public class CellLayout extends ViewGroup { if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; child.setId(childId); - if (inLayout) { - mShortcutsAndWidgets.addView(child, index, lp, true); - } else { - mShortcutsAndWidgets.addView(child, index, lp, false); - } + mShortcutsAndWidgets.addView(child, index, lp); if (markCells) markCellsAsOccupiedForView(child); @@ -626,11 +635,6 @@ public class CellLayout extends ViewGroup { return false; } - public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, - boolean markCells) { - return addViewToCellLayout(child, index, childId, params, markCells, false); - } - @Override public void removeAllViews() { clearOccupiedCells(); @@ -645,10 +649,6 @@ public class CellLayout extends ViewGroup { } } - public void removeViewWithoutMarkingCells(View view) { - mShortcutsAndWidgets.removeView(view); - } - @Override public void removeView(View view) { markCellsAsUnoccupiedForView(view); @@ -683,25 +683,13 @@ public class CellLayout extends ViewGroup { mShortcutsAndWidgets.removeViewsInLayout(start, count); } - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - // First we clear the tag to ensure that on every touch down we start with a fresh slate, - // even in the case where we return early. Not clearing here was causing bugs whereby on - // long-press we'd end up picking up an item from a previous drag operation. - if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { - return true; - } - - return false; - } - /** * Given a point, return the cell that strictly encloses that point * @param x X coordinate of the point * @param y Y coordinate of the point * @param result Array of 2 ints to hold the x and y coordinate of the cell */ - void pointToCellExact(int x, int y, int[] result) { + public void pointToCellExact(int x, int y, int[] result) { final int hStartPadding = getPaddingLeft(); final int vStartPadding = getPaddingTop(); @@ -790,9 +778,7 @@ public class CellLayout extends ViewGroup { public float getDistanceFromCell(float x, float y, int[] cell) { cellToCenterPoint(cell[0], cell[1], mTmpPoint); - float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + - Math.pow(y - mTmpPoint[1], 2)); - return distance; + return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]); } int getCellWidth() { @@ -811,28 +797,6 @@ public class CellLayout extends ViewGroup { return mHeightGap; } - Rect getContentRect(Rect r) { - if (r == null) { - r = new Rect(); - } - int left = getPaddingLeft(); - int top = getPaddingTop(); - int right = left + getWidth() - getPaddingLeft() - getPaddingRight(); - int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom(); - r.set(left, top, right, bottom); - return r; - } - - /** Return a rect that has the cellWidth/cellHeight (left, top), and - * widthGap/heightGap (right, bottom) */ - static void getMetrics(Rect metrics, int paddedMeasureWidth, - int paddedMeasureHeight, int countX, int countY) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - metrics.set(grid.calculateCellWidth(paddedMeasureWidth, countX), - grid.calculateCellHeight(paddedMeasureHeight, countY), 0, 0); - } - public void setFixedSize(int width, int height) { mFixedWidth = width; mFixedHeight = height; @@ -840,9 +804,6 @@ public class CellLayout extends ViewGroup { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); @@ -850,8 +811,8 @@ public class CellLayout extends ViewGroup { int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight()); int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom()); if (mFixedCellWidth < 0 || mFixedCellHeight < 0) { - int cw = grid.calculateCellWidth(childWidthSize, mCountX); - int ch = grid.calculateCellHeight(childHeightSize, mCountY); + int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX); + int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY); if (cw != mCellWidth || ch != mCellHeight) { mCellWidth = cw; mCellHeight = ch; @@ -885,19 +846,20 @@ public class CellLayout extends ViewGroup { mWidthGap = mOriginalWidthGap; mHeightGap = mOriginalHeightGap; } - int count = getChildCount(); - int maxWidth = 0; - int maxHeight = 0; - for (int i = 0; i < count; i++) { - View child = getChildAt(i); - int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth, - MeasureSpec.EXACTLY); - int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight, - MeasureSpec.EXACTLY); - child.measure(childWidthMeasureSpec, childheightMeasureSpec); - maxWidth = Math.max(maxWidth, child.getMeasuredWidth()); - maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); - } + + // Make the feedback view large enough to hold the blur bitmap. + mTouchFeedbackView.measure( + MeasureSpec.makeMeasureSpec(mCellWidth + mTouchFeedbackView.getExtraSize(), + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mCellHeight + mTouchFeedbackView.getExtraSize(), + MeasureSpec.EXACTLY)); + + mShortcutsAndWidgets.measure( + MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY)); + + int maxWidth = mShortcutsAndWidgets.getMeasuredWidth(); + int maxHeight = mShortcutsAndWidgets.getMeasuredHeight(); if (mFixedWidth > 0 && mFixedHeight > 0) { setMeasuredDimension(maxWidth, maxHeight); } else { @@ -911,13 +873,13 @@ public class CellLayout extends ViewGroup { (mCountX * mCellWidth); int left = getPaddingLeft() + (int) Math.ceil(offset / 2f); int top = getPaddingTop(); - int count = getChildCount(); - for (int i = 0; i < count; i++) { - View child = getChildAt(i); - child.layout(left, top, - left + r - l, - top + b - t); - } + + mTouchFeedbackView.layout(left, top, + left + mTouchFeedbackView.getMeasuredWidth(), + top + mTouchFeedbackView.getMeasuredHeight()); + mShortcutsAndWidgets.layout(left, top, + left + r - l, + top + b - t); } @Override @@ -925,12 +887,9 @@ public class CellLayout extends ViewGroup { super.onSizeChanged(w, h, oldw, oldh); // Expand the background drawing bounds by the padding baked into the background drawable - Rect padding = new Rect(); - mNormalBackground.getPadding(padding); - mBackgroundRect.set(-padding.left, -padding.top, w + padding.right, h + padding.bottom); - - mForegroundRect.set(mForegroundPadding, mForegroundPadding, - w - mForegroundPadding, h - mForegroundPadding); + mBackground.getPadding(mTempRect); + mBackground.setBounds(-mTempRect.left, -mTempRect.top, + w + mTempRect.right, h + mTempRect.bottom); } @Override @@ -947,25 +906,18 @@ public class CellLayout extends ViewGroup { return mBackgroundAlpha; } - public void setBackgroundAlphaMultiplier(float multiplier) { - - if (mBackgroundAlphaMultiplier != multiplier) { - mBackgroundAlphaMultiplier = multiplier; - invalidate(); - } - } - - public float getBackgroundAlphaMultiplier() { - return mBackgroundAlphaMultiplier; - } - public void setBackgroundAlpha(float alpha) { if (mBackgroundAlpha != alpha) { mBackgroundAlpha = alpha; - invalidate(); + mBackground.setAlpha((int) (mBackgroundAlpha * 255)); } } + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || (mIsDragTarget && who == mBackground); + } + public void setShortcutAndWidgetAlpha(float alpha) { mShortcutsAndWidgets.setAlpha(alpha); } @@ -1062,36 +1014,6 @@ public class CellLayout extends ViewGroup { return false; } - /** - * Estimate where the top left cell of the dragged item will land if it is dropped. - * - * @param originX The X value of the top left corner of the item - * @param originY The Y value of the top left corner of the item - * @param spanX The number of horizontal cells that the item spans - * @param spanY The number of vertical cells that the item spans - * @param result The estimated drop cell X and Y. - */ - void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { - final int countX = mCountX; - final int countY = mCountY; - - // pointToCellRounded takes the top left of a cell but will pad that with - // cellWidth/2 and cellHeight/2 when finding the matching cell - pointToCellRounded(originX, originY, result); - - // If the item isn't fully on this screen, snap to the edges - int rightOverhang = result[0] + spanX - countX; - if (rightOverhang > 0) { - result[0] -= rightOverhang; // Snap to right - } - result[0] = Math.max(0, result[0]); // Snap to left - int bottomOverhang = result[1] + spanY - countY; - if (bottomOverhang > 0) { - result[1] -= bottomOverhang; // Snap to bottom - } - result[1] = Math.max(0, result[1]); // Snap to top - } - void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { final int oldDragCellX = mDragCell[0]; @@ -1175,9 +1097,8 @@ public class CellLayout extends ViewGroup { * @return The X, Y cell of a vacant area that can contain this object, * nearest the requested location. */ - int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, - int[] result) { - return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); + int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) { + return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null); } /** @@ -1197,30 +1118,10 @@ public class CellLayout extends ViewGroup { */ int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, int[] result, int[] resultSpan) { - return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, + return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true, result, resultSpan); } - /** - * Find a vacant area that will fit the given bounds nearest the requested - * cell location. Uses Euclidean distance to score multiple vacant areas. - * - * @param pixelX The X location at which you want to search for a vacant area. - * @param pixelY The Y location at which you want to search for a vacant area. - * @param spanX Horizontal span of the object. - * @param spanY Vertical span of the object. - * @param ignoreOccupied If true, the result can be an occupied cell - * @param result Array in which to place the result, or null (in which case a new array will - * be allocated) - * @return The X, Y cell of a vacant area that can contain this object, - * nearest the requested location. - */ - int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, - boolean ignoreOccupied, int[] result) { - return findNearestArea(pixelX, pixelY, spanX, spanY, - spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); - } - private final Stack<Rect> mTempRectStack = new Stack<Rect>(); private void lazyInitTempRectStack() { if (mTempRectStack.isEmpty()) { @@ -1252,12 +1153,9 @@ public class CellLayout extends ViewGroup { * @return The X, Y cell of a vacant area that can contain this object, * nearest the requested location. */ - int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, - View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, - boolean[][] occupied) { + private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, + int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) { lazyInitTempRectStack(); - // mark space take by ignoreView as available (method checks if ignoreView is null) - markCellsAsUnoccupiedForView(ignoreView, occupied); // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds // to the center of the item, but we are searching based on the top-left cell, so @@ -1288,7 +1186,7 @@ public class CellLayout extends ViewGroup { // First, let's see if this thing fits anywhere for (int i = 0; i < minSpanX; i++) { for (int j = 0; j < minSpanY; j++) { - if (occupied[x + i][y + j]) { + if (mOccupied[x + i][y + j]) { continue inner; } } @@ -1305,7 +1203,7 @@ public class CellLayout extends ViewGroup { while (!(hitMaxX && hitMaxY)) { if (incX && !hitMaxX) { for (int j = 0; j < ySize; j++) { - if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { + if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) { // We can't move out horizontally hitMaxX = true; } @@ -1315,7 +1213,7 @@ public class CellLayout extends ViewGroup { } } else if (!hitMaxY) { for (int i = 0; i < xSize; i++) { - if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { + if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) { // We can't move out vertically hitMaxY = true; } @@ -1332,7 +1230,7 @@ public class CellLayout extends ViewGroup { hitMaxX = xSize >= spanX; hitMaxY = ySize >= spanY; } - final int[] cellXY = mTmpXY; + final int[] cellXY = mTmpPoint; cellToCenterPoint(x, y, cellXY); // We verify that the current rect is not a sub-rect of any of our previous @@ -1348,8 +1246,7 @@ public class CellLayout extends ViewGroup { } } validRegions.push(currentRect); - double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) - + Math.pow(cellXY[1] - pixelY, 2)); + double distance = Math.hypot(cellXY[0] - pixelX, cellXY[1] - pixelY); if ((distance <= bestDistance && !contained) || currentRect.contains(bestRect)) { @@ -1364,8 +1261,6 @@ public class CellLayout extends ViewGroup { } } } - // re-mark space taken by ignoreView as occupied - markCellsAsOccupiedForView(ignoreView, occupied); // Return -1, -1 if no suitable location found if (bestDistance == Double.MAX_VALUE) { @@ -1419,8 +1314,7 @@ public class CellLayout extends ViewGroup { } } - float distance = (float) - Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); + float distance = (float) Math.hypot(x - cellX, y - cellY); int[] curDirection = mTmpPoint; computeDirectionVector(x - cellX, y - cellY, curDirection); // The direction score is just the dot product of the two candidate direction @@ -2036,7 +1930,7 @@ public class CellLayout extends ViewGroup { } } - ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY, + private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { // Copy the current state into the solution. This solution will be manipulated as necessary. @@ -2272,7 +2166,7 @@ public class CellLayout extends ViewGroup { } } - private void completeAnimationImmediately() { + @Thunk void completeAnimationImmediately() { if (a != null) { a.cancel(); } @@ -2325,7 +2219,7 @@ public class CellLayout extends ViewGroup { mLauncher.getWorkspace().updateItemLocationsInDatabase(this); } - public void setUseTempCoords(boolean useTempCoords) { + private void setUseTempCoords(boolean useTempCoords) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); @@ -2333,11 +2227,11 @@ public class CellLayout extends ViewGroup { } } - ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, + private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, View dragView, ItemConfiguration solution) { int[] result = new int[2]; int[] resultSpan = new int[2]; - findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, + findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, resultSpan); if (result[0] >= 0 && result[1] >= 0) { copyCurrentStateToSolution(solution, false); @@ -2593,7 +2487,7 @@ public class CellLayout extends ViewGroup { return mItemPlacementDirty; } - private class ItemConfiguration { + @Thunk class ItemConfiguration { HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); private HashMap<View, CellAndSpan> savedMap = new HashMap<View, CellAndSpan>(); ArrayList<View> sortedViews = new ArrayList<View>(); @@ -2654,45 +2548,6 @@ public class CellLayout extends ViewGroup { } /** - * Find a vacant area that will fit the given bounds nearest the requested - * cell location. Uses Euclidean distance to score multiple vacant areas. - * - * @param pixelX The X location at which you want to search for a vacant area. - * @param pixelY The Y location at which you want to search for a vacant area. - * @param spanX Horizontal span of the object. - * @param spanY Vertical span of the object. - * @param ignoreView Considers space occupied by this view as unoccupied - * @param result Previously returned value to possibly recycle. - * @return The X, Y cell of a vacant area that can contain this object, - * nearest the requested location. - */ - int[] findNearestVacantArea( - int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { - return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); - } - - /** - * Find a vacant area that will fit the given bounds nearest the requested - * cell location. Uses Euclidean distance to score multiple vacant areas. - * - * @param pixelX The X location at which you want to search for a vacant area. - * @param pixelY The Y location at which you want to search for a vacant area. - * @param minSpanX The minimum horizontal span required - * @param minSpanY The minimum vertical span required - * @param spanX Horizontal span of the object. - * @param spanY Vertical span of the object. - * @param ignoreView Considers space occupied by this view as unoccupied - * @param result Previously returned value to possibly recycle. - * @return The X, Y cell of a vacant area that can contain this object, - * nearest the requested location. - */ - int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, - int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { - return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, - result, resultSpan, mOccupied); - } - - /** * Find a starting cell position that will fit the given bounds nearest the requested * cell location. Uses Euclidean distance to score multiple vacant areas. * @@ -2705,9 +2560,8 @@ public class CellLayout extends ViewGroup { * @return The X, Y cell of a vacant area that can contain this object, * nearest the requested location. */ - int[] findNearestArea( - int pixelX, int pixelY, int spanX, int spanY, int[] result) { - return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); + int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) { + return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null); } boolean existsEmptyCell() { @@ -2727,104 +2581,33 @@ public class CellLayout extends ViewGroup { * * @return True if a vacant cell of the specified dimension was found, false otherwise. */ - boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { - return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); - } - - /** - * Like above, but ignores any cells occupied by the item "ignoreView" - * - * @param cellXY The array that will contain the position of a vacant cell if such a cell - * can be found. - * @param spanX The horizontal span of the cell we want to find. - * @param spanY The vertical span of the cell we want to find. - * @param ignoreView The home screen item we should treat as not occupying any space - * @return - */ - boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { - return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, - ignoreView, mOccupied); - } - - /** - * Like above, but if intersectX and intersectY are not -1, then this method will try to - * return coordinates for rectangles that contain the cell [intersectX, intersectY] - * - * @param spanX The horizontal span of the cell we want to find. - * @param spanY The vertical span of the cell we want to find. - * @param ignoreView The home screen item we should treat as not occupying any space - * @param intersectX The X coordinate of the cell that we should try to overlap - * @param intersectX The Y coordinate of the cell that we should try to overlap - * - * @return True if a vacant cell of the specified dimension was found, false otherwise. - */ - boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, - int intersectX, int intersectY) { - return findCellForSpanThatIntersectsIgnoring( - cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); - } - - /** - * The superset of the above two methods - */ - boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, - int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { - // mark space take by ignoreView as available (method checks if ignoreView is null) - markCellsAsUnoccupiedForView(ignoreView, occupied); - + public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { boolean foundCell = false; - while (true) { - int startX = 0; - if (intersectX >= 0) { - startX = Math.max(startX, intersectX - (spanX - 1)); - } - int endX = mCountX - (spanX - 1); - if (intersectX >= 0) { - endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); - } - int startY = 0; - if (intersectY >= 0) { - startY = Math.max(startY, intersectY - (spanY - 1)); - } - int endY = mCountY - (spanY - 1); - if (intersectY >= 0) { - endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); - } - - for (int y = startY; y < endY && !foundCell; y++) { - inner: - for (int x = startX; x < endX; x++) { - for (int i = 0; i < spanX; i++) { - for (int j = 0; j < spanY; j++) { - if (occupied[x + i][y + j]) { - // small optimization: we can skip to after the column we just found - // an occupied cell - x += i; - continue inner; - } + final int endX = mCountX - (spanX - 1); + final int endY = mCountY - (spanY - 1); + + for (int y = 0; y < endY && !foundCell; y++) { + inner: + for (int x = 0; x < endX; x++) { + for (int i = 0; i < spanX; i++) { + for (int j = 0; j < spanY; j++) { + if (mOccupied[x + i][y + j]) { + // small optimization: we can skip to after the column we just found + // an occupied cell + x += i; + continue inner; } } - if (cellXY != null) { - cellXY[0] = x; - cellXY[1] = y; - } - foundCell = true; - break; } - } - if (intersectX == -1 && intersectY == -1) { + if (cellXY != null) { + cellXY[0] = x; + cellXY[1] = y; + } + foundCell = true; break; - } else { - // if we failed to find anything, try again but without any requirements of - // intersecting - intersectX = -1; - intersectY = -1; - continue; } } - // re-mark space taken by ignoreView as occupied - markCellsAsOccupiedForView(ignoreView, occupied); return foundCell; } @@ -2834,7 +2617,6 @@ public class CellLayout extends ViewGroup { * or it may have begun on another layout. */ void onDragEnter() { - mDragEnforcer.onDragEnter(); mDragging = true; } @@ -2842,7 +2624,6 @@ public class CellLayout extends ViewGroup { * Called when drag has left this CellLayout or has been completed (successfully or not) */ void onDragExit() { - mDragEnforcer.onDragExit(); // This can actually be called when we aren't in a drag, e.g. when adding a new // item to this layout via the customize drawer. // Guard against that case. @@ -2908,18 +2689,16 @@ public class CellLayout extends ViewGroup { * @param height Height in pixels * @param result An array of length 2 in which to store the result (may be null). */ - public static int[] rectToCell(int width, int height, int[] result) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - Rect padding = grid.getWorkspacePadding(grid.isLandscape ? - CellLayout.LANDSCAPE : CellLayout.PORTRAIT); + public static int[] rectToCell(Launcher launcher, int width, int height, int[] result) { + DeviceProfile grid = launcher.getDeviceProfile(); + Rect padding = grid.getWorkspacePadding(Utilities.isRtl(launcher.getResources())); // Always assume we're working with the smallest span to make sure we // reserve enough space in both orientations. - int parentWidth = grid.calculateCellWidth(grid.widthPx - - padding.left - padding.right, (int) grid.numColumns); - int parentHeight = grid.calculateCellHeight(grid.heightPx - - padding.top - padding.bottom, (int) grid.numRows); + int parentWidth = DeviceProfile.calculateCellWidth(grid.widthPx + - padding.left - padding.right, (int) grid.inv.numColumns); + int parentHeight = DeviceProfile.calculateCellHeight(grid.heightPx + - padding.top - padding.bottom, (int) grid.inv.numRows); int smallerSize = Math.min(parentWidth, parentHeight); // Always round up to next largest cell @@ -2934,13 +2713,6 @@ public class CellLayout extends ViewGroup { return result; } - public int[] cellSpansToSize(int hSpans, int vSpans) { - int[] size = new int[2]; - size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; - size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; - return size; - } - /** * Calculate the grid spans needed to fit given item */ @@ -2959,49 +2731,11 @@ public class CellLayout extends ViewGroup { info.spanX = info.spanY = 1; return; } - int[] spans = rectToCell(minWidth, minHeight, null); + int[] spans = rectToCell(mLauncher, minWidth, minHeight, null); info.spanX = spans[0]; info.spanY = spans[1]; } - /** - * Find the first vacant cell, if there is one. - * - * @param vacant Holds the x and y coordinate of the vacant cell - * @param spanX Horizontal cell span. - * @param spanY Vertical cell span. - * - * @return True if a vacant cell was found - */ - public boolean getVacantCell(int[] vacant, int spanX, int spanY) { - - return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); - } - - static boolean findVacantCell(int[] vacant, int spanX, int spanY, - int xCount, int yCount, boolean[][] occupied) { - - for (int y = 0; (y + spanY) <= yCount; y++) { - for (int x = 0; (x + spanX) <= xCount; x++) { - boolean available = !occupied[x][y]; -out: for (int i = x; i < x + spanX; i++) { - for (int j = y; j < y + spanY; j++) { - available = available && !occupied[i][j]; - if (!available) break out; - } - } - - if (available) { - vacant[0] = x; - vacant[1] = y; - return true; - } - } - } - - return false; - } - private void clearOccupiedCells() { for (int x = 0; x < mCountX; x++) { for (int y = 0; y < mCountY; y++) { @@ -3010,27 +2744,16 @@ out: for (int i = x; i < x + spanX; i++) { } } - public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { - markCellsAsUnoccupiedForView(view); - markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); - } - public void markCellsAsOccupiedForView(View view) { - markCellsAsOccupiedForView(view, mOccupied); - } - public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { if (view == null || view.getParent() != mShortcutsAndWidgets) return; LayoutParams lp = (LayoutParams) view.getLayoutParams(); - markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); + markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true); } public void markCellsAsUnoccupiedForView(View view) { - markCellsAsUnoccupiedForView(view, mOccupied); - } - public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { if (view == null || view.getParent() != mShortcutsAndWidgets) return; LayoutParams lp = (LayoutParams) view.getLayoutParams(); - markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); + markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false); } private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, @@ -3076,17 +2799,6 @@ out: for (int i = x; i < x + spanX; i++) { return new CellLayout.LayoutParams(p); } - public static class CellLayoutAnimationController extends LayoutAnimationController { - public CellLayoutAnimationController(Animation animation, float delay) { - super(animation, delay); - } - - @Override - protected long getDelayForView(View view) { - return (int) (Math.random() * 150); - } - } - public static class LayoutParams extends ViewGroup.MarginLayoutParams { /** * Horizontal location of the item in the grid. @@ -3245,7 +2957,7 @@ out: for (int i = x; i < x + spanX; i++) { // 2. When long clicking on an empty cell in a CellLayout, we save information about the // cellX and cellY coordinates and which page was clicked. We then set this as a tag on // the CellLayout that was long clicked - static final class CellInfo { + public static final class CellInfo { View cell; int cellX = -1; int cellY = -1; @@ -3254,7 +2966,7 @@ out: for (int i = x; i < x + spanX; i++) { long screenId; long container; - CellInfo(View v, ItemInfo info) { + public CellInfo(View v, ItemInfo info) { cell = v; cellX = info.cellX; cellY = info.cellY; @@ -3271,7 +2983,24 @@ out: for (int i = x; i < x + spanX; i++) { } } - public boolean lastDownOnOccupiedCell() { - return mLastDownOnOccupiedCell; + public boolean findVacantCell(int spanX, int spanY, int[] outXY) { + return Utilities.findVacantCell(outXY, spanX, spanY, mCountX, mCountY, mOccupied); + } + + public boolean isRegionVacant(int x, int y, int spanX, int spanY) { + int x2 = x + spanX - 1; + int y2 = y + spanY - 1; + if (x < 0 || y < 0 || x2 >= mCountX || y2 >= mCountY) { + return false; + } + for (int i = x; i <= x2; i++) { + for (int j = y; j <= y2; j++) { + if (mOccupied[i][j]) { + return false; + } + } + } + + return true; } } |