Merge "Updating layouts to use frame vs translation and clipping."
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 757d2aa..f646a92 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -46,19 +46,6 @@
}
};
- public static final Property<AnimateableViewBounds, Integer> CLIP_RIGHT =
- new IntProperty<AnimateableViewBounds>("clipRight") {
- @Override
- public void setValue(AnimateableViewBounds object, int clip) {
- object.setClipRight(clip, false /* force */);
- }
-
- @Override
- public Integer get(AnimateableViewBounds object) {
- return object.getClipRight();
- }
- };
-
public AnimateableViewBounds(View source, int cornerRadius) {
mSourceView = source;
mCornerRadius = cornerRadius;
@@ -102,19 +89,6 @@
return mClipRect.bottom;
}
- /** Sets the right clip. */
- public void setClipRight(int right, boolean force) {
- if (right != mClipRect.right || force) {
- mClipRect.right = right;
- updateClipBounds();
- }
- }
-
- /** Returns the right clip. */
- public int getClipRight() {
- return mClipRect.right;
- }
-
private void updateClipBounds() {
mClipBounds.set(mClipRect.left, mClipRect.top,
mSourceView.getWidth() - mClipRect.right,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 9b9d58c..25f9e80 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -19,7 +19,6 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
-import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
import java.util.Collections;
@@ -80,7 +79,6 @@
float width = normalizedTaskWidths[i] * rowScale;
if (rowWidth + width > normalizedWorkspaceWidth) {
// That is too long for this row, create new row
- rowWidth = 0f;
if ((rowCount + 1) * rowScale > normalizedWorkspaceHeight) {
// The new row is too high, so we need to try fitting again. Update the
// scale to be the smaller of the scale needed to fit the task in the
@@ -88,9 +86,11 @@
rowScale = Math.min(normalizedWorkspaceWidth / (rowWidth + width),
normalizedWorkspaceHeight / (rowCount + 1));
rowCount = 1;
+ rowWidth = 0;
i = 0;
} else {
// The new row fits, so continue
+ rowWidth = width;
rowCount++;
i++;
}
@@ -103,20 +103,20 @@
}
// Normalize each of the actual rects to that scale
- int height = (int) (rowScale * workspaceHeight);
- float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
float defaultRowLeft = ((1f - (maxRowWidth / normalizedWorkspaceWidth)) *
workspaceWidth) / 2f;
float rowLeft = defaultRowLeft;
+ float rowTop = ((1f - (rowScale * rowCount)) * workspaceHeight) / 2f;
+ float rowHeight = rowScale * workspaceHeight;
for (int i = 0; i < numFreeformTasks; i++) {
Task task = freeformTasks.get(i);
- int width = (int) (height * normalizedTaskWidths[i]);
+ float width = rowHeight * normalizedTaskWidths[i];
if (rowLeft + width > workspaceWidth) {
// This goes on the next line
- rowTop += height;
+ rowTop += rowHeight;
rowLeft = defaultRowLeft;
}
- RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + height);
+ RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + rowHeight);
rowLeft += width;
mTaskRectMap.put(task.key, rect);
}
@@ -140,34 +140,29 @@
public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut,
TaskStackLayoutAlgorithm stackLayout) {
if (mTaskRectMap.containsKey(task.key)) {
- Rect taskRect = stackLayout.mTaskRect;
- RectF ffRect = mTaskRectMap.get(task.key);
- float scale = Math.max(ffRect.width() / taskRect.width(),
- ffRect.height() / taskRect.height());
- int topOffset = (stackLayout.mFreeformRect.top - taskRect.top);
- int scaleXOffset = (int) (((1f - scale) * taskRect.width()) / 2);
- int scaleYOffset = (int) (((1f - scale) * taskRect.height()) / 2);
+ final Rect taskRect = stackLayout.mTaskRect;
+ final RectF ffRect = mTaskRectMap.get(task.key);
- transformOut.scale = scale * 0.95f;
- transformOut.translationX = (int) (ffRect.left - scaleXOffset);
- transformOut.translationY = (int) (topOffset + ffRect.top - scaleYOffset);
+ transformOut.scale = 0.95f;
+ transformOut.alpha = 1f;
transformOut.translationZ = stackLayout.mMaxTranslationZ;
- transformOut.clipBottom = (int) (taskRect.height() - (ffRect.height() / scale));
- transformOut.clipRight = (int) (taskRect.width() - (ffRect.width() / scale));
if (task.thumbnail != null) {
- transformOut.thumbnailScale = Math.min(
- ((float) taskRect.width() - transformOut.clipRight) /
- task.thumbnail.getWidth(),
- ((float) taskRect.height() - transformOut.clipBottom) /
- task.thumbnail.getHeight());
+ if (task.bounds == null) {
+ // This is a stack task that has no freeform thumbnail, so keep the same bitmap
+ // scale as it had in the stack
+ transformOut.thumbnailScale = (float) taskRect.width() /
+ task.thumbnail.getWidth();
+ } else {
+ // This is a freeform rect so fit the bitmap to the task bounds
+ transformOut.thumbnailScale = Math.min(
+ ffRect.width() / task.thumbnail.getWidth(),
+ ffRect.height() / task.thumbnail.getHeight());
+ }
} else {
transformOut.thumbnailScale = 1f;
}
- transformOut.rect.set(taskRect);
- transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
- Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
- transformOut.rect.right -= transformOut.clipRight * scale;
- transformOut.rect.bottom -= transformOut.clipBottom * scale;
+ transformOut.rect.set(ffRect);
+ transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
transformOut.visible = true;
transformOut.p = 1f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 7d5daae..f599f52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -507,6 +507,15 @@
}
/**
+ * Returns the task progress that would put the task just off the back of the stack.
+ */
+ public float getStackBackTaskProgress(float stackScroll) {
+ float min = mUnfocusedRange.relativeMin +
+ mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
+ return stackScroll + min;
+ }
+
+ /**
* Returns the task progress that would put the task just off the front of the stack.
*/
public float getStackFrontTaskProgress(float stackScroll) {
@@ -647,6 +656,7 @@
return transformOut;
}
+ int x = (mStackRect.width() - mTaskRect.width()) / 2;
int y;
float z;
float relP;
@@ -671,16 +681,13 @@
// Fill out the transform
transformOut.scale = 1f;
- transformOut.translationX = (mStackRect.width() - mTaskRect.width()) / 2;
- transformOut.translationY = y;
+ transformOut.alpha = 1f;
transformOut.translationZ = z;
transformOut.rect.set(mTaskRect);
- transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
+ transformOut.rect.offset(x, y);
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
(frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
- transformOut.clipBottom = 0;
- transformOut.clipRight = 0;
transformOut.thumbnailScale = 1f;
transformOut.p = relP;
return transformOut;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index cc5aaae..831cb12 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -20,6 +20,7 @@
import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -126,6 +127,7 @@
Task mFocusedTask;
// Optimizations
int mStackViewsAnimationDuration;
+ int mTaskCornerRadiusPx;
boolean mStackViewsDirty = true;
boolean mStackViewsClipDirty = true;
boolean mAwaitingFirstLayout = true;
@@ -174,6 +176,8 @@
public TaskStackView(Context context, TaskStack stack) {
super(context);
+ Resources res = context.getResources();
+
// Set the stack first
setStack(stack);
mViewPool = new ViewPool<>(context, this);
@@ -184,6 +188,8 @@
mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
+ mTaskCornerRadiusPx = res.getDimensionPixelSize(
+ R.dimen.recents_task_view_rounded_corners_radius);
int taskBarDismissDozeDelaySeconds = getResources().getInteger(
R.integer.recents_task_bar_dismiss_delay_seconds);
@@ -364,8 +370,7 @@
private boolean updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms,
ArrayList<Task> tasks,
float stackScroll,
- int[] visibleRangeOut,
- boolean boundTranslationsToRect) {
+ int[] visibleRangeOut) {
int taskTransformCount = taskTransforms.size();
int taskCount = tasks.size();
int frontMostVisibleIndex = -1;
@@ -411,11 +416,6 @@
break;
}
}
-
- if (boundTranslationsToRect) {
- transform.translationY = Math.min(transform.translationY,
- mLayoutAlgorithm.mStackRect.bottom);
- }
frontTransform = transform;
}
if (visibleRangeOut != null) {
@@ -433,7 +433,7 @@
float stackScroll = mStackScroller.getStackScroll();
int[] visibleStackRange = mTmpVisibleRange;
boolean isValidVisibleStackRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
- stackScroll, visibleStackRange, false);
+ stackScroll, visibleStackRange);
boolean hasStackBackTransform = false;
boolean hasStackFrontTransform = false;
if (DEBUG) {
@@ -490,7 +490,7 @@
}
// Animate the task into place
- tv.updateViewPropertiesToTaskTransform(transform, transform.clipBottom,
+ tv.updateViewPropertiesToTaskTransform(transform, 0,
mStackViewsAnimationDuration, mFastOutSlowInInterpolator,
mRequestUpdateClippingListener);
@@ -513,8 +513,9 @@
if (Float.compare(transform.p, 0f) <= 0) {
if (!hasStackBackTransform) {
hasStackBackTransform = true;
- mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpStackBackTransform,
- null);
+ mLayoutAlgorithm.getStackTransform(
+ mLayoutAlgorithm.getStackBackTaskProgress(0f), 0f,
+ mTmpStackBackTransform, null);
}
tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0, 0,
mFastOutSlowInInterpolator, mRequestUpdateClippingListener);
@@ -586,17 +587,11 @@
// stacked and we can make assumptions about the visibility of the this
// task relative to the ones in front of it.
if (frontTv != null) {
- mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
- mTmpTaskRect.offset(0, tv.getTranslationY());
- Utilities.scaleRectAboutCenter(mTmpTaskRect, tv.getScaleX());
- float taskBottom = mTmpTaskRect.bottom;
- mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
- mTmpTaskRect.offset(0, frontTv.getTranslationY());
- Utilities.scaleRectAboutCenter(mTmpTaskRect, frontTv.getScaleX());
- float frontTaskTop = mTmpTaskRect.top;
+ float taskBottom = tv.getBottom();
+ float frontTaskTop = frontTv.getTop();
if (frontTaskTop < taskBottom) {
// Map the stack view space coordinate (the rects) to view space
- clipBottom = (int) ((taskBottom - frontTaskTop) / tv.getScaleX()) - 1;
+ clipBottom = (int) (taskBottom - frontTaskTop) - mTaskCornerRadiusPx;
}
}
}
@@ -980,11 +975,11 @@
onFirstLayout();
}
+ requestSynchronizeStackViewsWithModel();
if (changed) {
if (mStackScroller.isScrollOutOfBounds()) {
mStackScroller.boundScroll();
}
- requestSynchronizeStackViewsWithModel();
synchronizeStackViewsWithModel();
requestUpdateStackViewsClip();
clipTaskViews(true /* forceUpdate */);
@@ -1147,8 +1142,7 @@
transformPointToViewLocal(point, tv);
x = point[0];
y = point[1];
- return (0 <= x) && (x < (tv.getMeasuredWidth() - tv.getViewBounds().getClipRight())) &&
- (0 <= y) && (y < (tv.getMeasuredHeight() - tv.getViewBounds().getClipBottom()));
+ return (0 <= x) && (x < tv.getWidth()) && (0 <= y) && (y < tv.getHeight());
}
@Override
@@ -1498,6 +1492,18 @@
event.taskView.animate()
.withEndAction(event.postAnimationTrigger.decrementAsRunnable());
+ // We translated the view but we need to animate it back from the current layout-space rect
+ // to its final layout-space rect
+ int x = (int) event.taskView.getTranslationX();
+ int y = (int) event.taskView.getTranslationY();
+ Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(),
+ event.taskView.getRight(), event.taskView.getBottom());
+ taskViewRect.offset(x, y);
+ event.taskView.setTranslationX(0);
+ event.taskView.setTranslationY(0);
+ event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
+ taskViewRect.right, taskViewRect.bottom);
+
// Animate the tack view back into position
requestSynchronizeStackViewsWithModel(250);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 813a1fc..4997709 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -232,8 +232,14 @@
mClipAnimation.playTogether(
ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_BOTTOM,
mViewBounds.getClipBottom(), clipBottom),
- ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_RIGHT,
- mViewBounds.getClipRight(), toTransform.clipRight),
+ ObjectAnimator.ofInt(this, TaskViewTransform.LEFT, getLeft(),
+ (int) toTransform.rect.left),
+ ObjectAnimator.ofInt(this, TaskViewTransform.TOP, getTop(),
+ (int) toTransform.rect.top),
+ ObjectAnimator.ofInt(this, TaskViewTransform.RIGHT, getRight(),
+ (int) toTransform.rect.right),
+ ObjectAnimator.ofInt(this, TaskViewTransform.BOTTOM, getBottom(),
+ (int) toTransform.rect.bottom),
ObjectAnimator.ofFloat(mThumbnailView, TaskViewThumbnail.BITMAP_SCALE,
mThumbnailView.getBitmapScale(), toTransform.thumbnailScale));
mClipAnimation.setStartDelay(toTransform.startDelay);
@@ -242,8 +248,9 @@
mClipAnimation.start();
} else {
mViewBounds.setClipBottom(clipBottom, false /* forceUpdate */);
- mViewBounds.setClipRight(toTransform.clipRight, false /* forceUpdate */);
mThumbnailView.setBitmapScale(toTransform.thumbnailScale);
+ setLeftTopRightBottom((int) toTransform.rect.left, (int) toTransform.rect.top,
+ (int) toTransform.rect.right, (int) toTransform.rect.bottom);
}
if (!config.useHardwareLayers) {
mThumbnailView.updateThumbnailVisibility(clipBottom - getPaddingBottom());
@@ -336,10 +343,10 @@
} else {
// Animate the task up if it was occluding the launch target
if (ctx.currentTaskOccludesLaunchTarget) {
- setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset);
+ setTranslationY(taskViewAffiliateGroupEnterOffset);
setAlpha(0f);
animate().alpha(1f)
- .translationY(transform.translationY)
+ .translationY(0)
.setUpdateListener(null)
.setListener(new AnimatorListenerAdapter() {
private boolean hasEnded;
@@ -372,7 +379,7 @@
animate().translationZ(transform.translationZ);
}
animate()
- .translationY(transform.translationY)
+ .translationY(0)
.setStartDelay(delay)
.setUpdateListener(ctx.updateListener)
.setListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 78a2c7f..d782a63 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -103,7 +103,7 @@
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ outline.setRect(0, 0, getWidth(), getHeight());
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index c3e0906..3ee50ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -18,6 +18,9 @@
import android.animation.ValueAnimator;
import android.graphics.RectF;
+import android.util.IntProperty;
+import android.util.Property;
+import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
@@ -25,26 +28,70 @@
/* The transform state for a task view */
public class TaskViewTransform {
+ public static final Property<View, Integer> LEFT =
+ new IntProperty<View>("left") {
+ @Override
+ public void setValue(View object, int v) {
+ object.setLeft(v);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return object.getLeft();
+ }
+ };
+
+ public static final Property<View, Integer> TOP =
+ new IntProperty<View>("top") {
+ @Override
+ public void setValue(View object, int v) {
+ object.setTop(v);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return object.getTop();
+ }
+ };
+
+ public static final Property<View, Integer> RIGHT =
+ new IntProperty<View>("right") {
+ @Override
+ public void setValue(View object, int v) {
+ object.setRight(v);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return object.getRight();
+ }
+ };
+
+ public static final Property<View, Integer> BOTTOM =
+ new IntProperty<View>("bottom") {
+ @Override
+ public void setValue(View object, int v) {
+ object.setBottom(v);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return object.getBottom();
+ }
+ };
+
// TODO: Move this out of the transform
public int startDelay = 0;
- public int translationX = 0;
- public int translationY = 0;
public float translationZ = 0;
public float scale = 1f;
public float alpha = 1f;
-
- // Clip and thumbnail scale are untransformed layout-space properties
- // The bottom clip is only used for freeform workspace tasks
- public int clipBottom = 0;
- public int clipRight = 0;
public float thumbnailScale = 1f;
public boolean visible = false;
float p = 0f;
- // This is a window-space rect that is purely used for coordinating the animation of an app
- // window into Recents.
+ // This is a window-space rect used for positioning the task in the stack and freeform workspace
public RectF rect = new RectF();
public TaskViewTransform() {
@@ -56,13 +103,9 @@
*/
public void reset() {
startDelay = 0;
- translationX = 0;
- translationY = 0;
translationZ = 0;
scale = 1f;
alpha = 1f;
- clipBottom = 0;
- clipRight = 0;
thumbnailScale = 1f;
visible = false;
rect.setEmpty();
@@ -76,12 +119,6 @@
public boolean hasScaleChangedFrom(float v) {
return (Float.compare(scale, v) != 0);
}
- public boolean hasTranslationXChangedFrom(float v) {
- return (Float.compare(translationX, v) != 0);
- }
- public boolean hasTranslationYChangedFrom(float v) {
- return (Float.compare(translationY, v) != 0);
- }
public boolean hasTranslationZChangedFrom(float v) {
return (Float.compare(translationZ, v) != 0);
}
@@ -95,12 +132,6 @@
boolean requiresLayers = false;
// Animate to the final state
- if (hasTranslationXChangedFrom(v.getTranslationX())) {
- anim.translationX(translationX);
- }
- if (hasTranslationYChangedFrom(v.getTranslationY())) {
- anim.translationY(translationY);
- }
if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
anim.translationZ(translationZ);
}
@@ -129,12 +160,6 @@
.start();
} else {
// Set the changed properties
- if (hasTranslationXChangedFrom(v.getTranslationX())) {
- v.setTranslationX(translationX);
- }
- if (hasTranslationYChangedFrom(v.getTranslationY())) {
- v.setTranslationY(translationY);
- }
if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
v.setTranslationZ(translationZ);
}
@@ -150,7 +175,8 @@
/** Reset the transform on a view. */
public static void reset(TaskView v) {
- // Cancel any running animations
+ // Cancel any running animations and reset the translation in case something else (like a
+ // dismiss animation) changes it
v.animate().cancel();
v.setTranslationX(0f);
v.setTranslationY(0f);
@@ -158,16 +184,15 @@
v.setScaleX(1f);
v.setScaleY(1f);
v.setAlpha(1f);
- v.getViewBounds().setClipRight(0, false /* forceUpdate */);
v.getViewBounds().setClipBottom(0, false /* forceUpdate */);
+ v.setLeftTopRightBottom(0, 0, 0, 0);
v.mThumbnailView.setBitmapScale(1f);
}
@Override
public String toString() {
- return "TaskViewTransform delay: " + startDelay +
- " x: " + translationX + " y: " + translationY + " z: " + translationZ +
- " scale: " + scale + " alpha: " + alpha + " visible: " + visible + " rect: " + rect +
- " p: " + p;
+ return "TaskViewTransform delay: " + startDelay + " z: " + translationZ +
+ " scale: " + scale + " alpha: " + alpha + " visible: " + visible +
+ " rect: " + rect + " p: " + p;
}
}