Updated EdgeEffect parameters for overscroll stretch
Added dampening logic to caluclate the distance to overscroll. Updated StretchEffect to support independent maximum stretch amounts for the x/y axis Removed debugging parameters to configure stretch distance since they are no longer used. Removed hidden API calls to configure stretch distance in ScrollView/HorizontalScrollView Bug: 179047472 Test: re-ran EdgeEffectTests Change-Id: I4698669273d364695a21c2cce00ec2cfec41b2cc
This commit is contained in:
@@ -130,7 +130,11 @@ public class EdgeEffect {
|
||||
public @interface EdgeEffectType {
|
||||
}
|
||||
|
||||
private static final float DEFAULT_MAX_STRETCH_INTENSITY = 0.08f;
|
||||
private static final float LINEAR_STRETCH_INTENSITY = 0.03f;
|
||||
|
||||
private static final float EXP_STRETCH_INTENSITY = 0.02f;
|
||||
|
||||
private static final float SCROLL_DIST_AFFECTED_BY_EXP_STRETCH = 0.4f;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final String TAG = "EdgeEffect";
|
||||
@@ -176,9 +180,6 @@ public class EdgeEffect {
|
||||
|
||||
private long mStartTime;
|
||||
private float mDuration;
|
||||
private float mStretchIntensity = DEFAULT_MAX_STRETCH_INTENSITY;
|
||||
private float mStretchDistanceFraction = 1f;
|
||||
private float mStretchDistance = -1f;
|
||||
|
||||
private final Interpolator mInterpolator = new DecelerateInterpolator();
|
||||
|
||||
@@ -268,16 +269,6 @@ public class EdgeEffect {
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the distance in pixels to stretch the content. This is only consumed as part
|
||||
* if {@link #setType(int)} is set to {@link #TYPE_STRETCH}
|
||||
* @param stretchDistance Stretch distance in pixels when the target View is overscrolled
|
||||
* @hide
|
||||
*/
|
||||
public void setStretchDistance(float stretchDistance) {
|
||||
mStretchDistance = stretchDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports if this EdgeEffect's animation is finished. If this method returns false
|
||||
* after a call to {@link #draw(Canvas)} the host widget should schedule another
|
||||
@@ -519,13 +510,6 @@ public class EdgeEffect {
|
||||
mEdgeEffectType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void setMaxStretchIntensity(float stretchIntensity) {
|
||||
mStretchIntensity = stretchIntensity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or clear the blend mode. A blend mode defines how source pixels
|
||||
* (generated by a drawing command) are composited with the destination pixels
|
||||
@@ -642,22 +626,19 @@ public class EdgeEffect {
|
||||
// assume rotations of increments of 90 degrees
|
||||
float x = mTmpPoints[10] - mTmpPoints[8];
|
||||
float width = right - left;
|
||||
float vecX = Math.max(-1f, Math.min(1f, x / width));
|
||||
float vecX = dampStretchVector(Math.max(-1f, Math.min(1f, x / width)));
|
||||
float y = mTmpPoints[11] - mTmpPoints[9];
|
||||
float height = bottom - top;
|
||||
float vecY = Math.max(-1f, Math.min(1f, y / height));
|
||||
float vecY = dampStretchVector(Math.max(-1f, Math.min(1f, y / height)));
|
||||
renderNode.stretch(
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
vecX * mStretchIntensity,
|
||||
vecY * mStretchIntensity,
|
||||
// TODO (njawad/mount) figure out proper stretch distance from UX
|
||||
// for now leverage placeholder logic if no stretch distance is provided to
|
||||
// consume the displacement ratio times the minimum of the width or height
|
||||
mStretchDistance > 0 ? mStretchDistance :
|
||||
(mStretchDistanceFraction * Math.max(mWidth, mHeight))
|
||||
vecX,
|
||||
vecY,
|
||||
mWidth,
|
||||
mHeight
|
||||
);
|
||||
}
|
||||
|
||||
@@ -794,4 +775,13 @@ public class EdgeEffect {
|
||||
return Math.abs(mVelocity) < VELOCITY_THRESHOLD
|
||||
&& Math.abs(displacement) < VALUE_THRESHOLD;
|
||||
}
|
||||
|
||||
private float dampStretchVector(float normalizedVec) {
|
||||
float sign = normalizedVec > 0 ? 1f : -1f;
|
||||
float overscroll = Math.abs(normalizedVec);
|
||||
float linearIntensity = LINEAR_STRETCH_INTENSITY * overscroll;
|
||||
double scalar = Math.E / SCROLL_DIST_AFFECTED_BY_EXP_STRETCH;
|
||||
double expIntensity = EXP_STRETCH_INTENSITY * (1 - Math.exp(-overscroll * scalar));
|
||||
return sign * (float) (linearIntensity + expIntensity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,26 +248,6 @@ public class HorizontalScrollView extends FrameLayout {
|
||||
setRightEdgeEffectColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* API used for prototyping stretch effect parameters in framework sample apps
|
||||
* @hide
|
||||
*/
|
||||
public void setEdgeEffectIntensity(float intensity) {
|
||||
mEdgeGlowLeft.setMaxStretchIntensity(intensity);
|
||||
mEdgeGlowRight.setMaxStretchIntensity(intensity);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* API used for prototyping stretch effect parameters in the framework sample apps
|
||||
* @hide
|
||||
*/
|
||||
public void setStretchDistance(float distance) {
|
||||
mEdgeGlowLeft.setStretchDistance(distance);
|
||||
mEdgeGlowRight.setStretchDistance(distance);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right edge effect color.
|
||||
*
|
||||
|
||||
@@ -280,26 +280,6 @@ public class ScrollView extends FrameLayout {
|
||||
setBottomEdgeEffectColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* API used for prototyping stretch effect parameters in framework sample apps
|
||||
* @hide
|
||||
*/
|
||||
public void setEdgeEffectIntensity(float intensity) {
|
||||
mEdgeGlowTop.setMaxStretchIntensity(intensity);
|
||||
mEdgeGlowBottom.setMaxStretchIntensity(intensity);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* API used for prototyping stretch effect parameters in the framework sample apps
|
||||
* @hide
|
||||
*/
|
||||
public void setStretchDistance(float distance) {
|
||||
mEdgeGlowTop.setStretchDistance(distance);
|
||||
mEdgeGlowBottom.setStretchDistance(distance);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bottom edge effect color.
|
||||
*
|
||||
|
||||
@@ -275,6 +275,8 @@ public final class RenderNode {
|
||||
* Call to apply a stretch effect to any child SurfaceControl layers
|
||||
*
|
||||
* TODO: Fold this into positionChanged & have HWUI do the ASurfaceControl calls?
|
||||
* (njawad) update to consume different stretch parameters for horizontal/vertical stretch
|
||||
* to ensure SkiaGLRenderEngine can also apply the same stretch to a surface
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@@ -718,7 +720,7 @@ public final class RenderNode {
|
||||
|
||||
/** @hide */
|
||||
public boolean stretch(float left, float top, float right, float bottom,
|
||||
float vecX, float vecY, float maxStretchAmount) {
|
||||
float vecX, float vecY, float maxStretchAmountX, float maxStretchAmountY) {
|
||||
if (Float.isInfinite(vecX) || Float.isNaN(vecX)) {
|
||||
throw new IllegalArgumentException("vecX must be a finite, non-NaN value " + vecX);
|
||||
}
|
||||
@@ -730,9 +732,13 @@ public final class RenderNode {
|
||||
"Stretch region must not be empty, got "
|
||||
+ new RectF(left, top, right, bottom).toString());
|
||||
}
|
||||
if (maxStretchAmount <= 0.0f) {
|
||||
if (maxStretchAmountX <= 0.0f) {
|
||||
throw new IllegalArgumentException(
|
||||
"The max stretch amount must be >0, got " + maxStretchAmount);
|
||||
"The max horizontal stretch amount must be >0, got " + maxStretchAmountX);
|
||||
}
|
||||
if (maxStretchAmountY <= 0.0f) {
|
||||
throw new IllegalArgumentException(
|
||||
"The max vertical stretch amount must be >0, got " + maxStretchAmountY);
|
||||
}
|
||||
return nStretch(
|
||||
mNativeRenderNode,
|
||||
@@ -742,7 +748,8 @@ public final class RenderNode {
|
||||
bottom,
|
||||
vecX,
|
||||
vecY,
|
||||
maxStretchAmount
|
||||
maxStretchAmountX,
|
||||
maxStretchAmountY
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1695,7 +1702,7 @@ public final class RenderNode {
|
||||
|
||||
@CriticalNative
|
||||
private static native boolean nStretch(long renderNode, float left, float top, float right,
|
||||
float bottom, float vecX, float vecY, float maxStretch);
|
||||
float bottom, float vecX, float vecY, float maxStretchX, float maxStretchY);
|
||||
|
||||
@CriticalNative
|
||||
private static native boolean nHasShadow(long renderNode);
|
||||
|
||||
@@ -33,7 +33,8 @@ static const SkString stretchShader = SkString(R"(
|
||||
uniform float uMaxStretchIntensity;
|
||||
|
||||
// Maximum percentage to stretch beyond bounds of target
|
||||
uniform float uStretchAffectedDist;
|
||||
uniform float uStretchAffectedDistX;
|
||||
uniform float uStretchAffectedDistY;
|
||||
|
||||
// Distance stretched as a function of the normalized overscroll times
|
||||
// scale intensity
|
||||
@@ -138,7 +139,7 @@ static const SkString stretchShader = SkString(R"(
|
||||
outU,
|
||||
inU,
|
||||
uOverscrollX,
|
||||
uStretchAffectedDist,
|
||||
uStretchAffectedDistX,
|
||||
uDistanceStretchedX,
|
||||
uDistDiffX
|
||||
);
|
||||
@@ -146,7 +147,7 @@ static const SkString stretchShader = SkString(R"(
|
||||
outV,
|
||||
inV,
|
||||
uOverscrollY,
|
||||
uStretchAffectedDist,
|
||||
uStretchAffectedDistY,
|
||||
uDistanceStretchedY,
|
||||
uDistDiffY
|
||||
);
|
||||
@@ -166,16 +167,14 @@ sk_sp<SkImageFilter> StretchEffect::getImageFilter(const sk_sp<SkImage>& snapsho
|
||||
return mStretchFilter;
|
||||
}
|
||||
|
||||
float distanceNotStretchedX = maxStretchAmount / stretchArea.width();
|
||||
float distanceNotStretchedY = maxStretchAmount / stretchArea.height();
|
||||
float normOverScrollDistX = mStretchDirection.x();
|
||||
float normOverScrollDistY = mStretchDirection.y();
|
||||
float distanceStretchedX = maxStretchAmount / (1 + abs(normOverScrollDistX));
|
||||
float distanceStretchedY = maxStretchAmount / (1 + abs(normOverScrollDistY));
|
||||
float diffX = distanceStretchedX - distanceNotStretchedX;
|
||||
float diffY = distanceStretchedY - distanceNotStretchedY;
|
||||
float viewportWidth = stretchArea.width();
|
||||
float viewportHeight = stretchArea.height();
|
||||
float normOverScrollDistX = mStretchDirection.x();
|
||||
float normOverScrollDistY = mStretchDirection.y();
|
||||
float distanceStretchedX = maxStretchAmountX / (1 + abs(normOverScrollDistX));
|
||||
float distanceStretchedY = maxStretchAmountY / (1 + abs(normOverScrollDistY));
|
||||
float diffX = distanceStretchedX;
|
||||
float diffY = distanceStretchedY;
|
||||
|
||||
if (mBuilder == nullptr) {
|
||||
mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
|
||||
@@ -183,7 +182,8 @@ sk_sp<SkImageFilter> StretchEffect::getImageFilter(const sk_sp<SkImage>& snapsho
|
||||
|
||||
mBuilder->child("uContentTexture") = snapshotImage->makeShader(
|
||||
SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
|
||||
mBuilder->uniform("uStretchAffectedDist").set(&maxStretchAmount, 1);
|
||||
mBuilder->uniform("uStretchAffectedDistX").set(&maxStretchAmountX, 1);
|
||||
mBuilder->uniform("uStretchAffectedDistY").set(&maxStretchAmountY, 1);
|
||||
mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1);
|
||||
mBuilder->uniform("uDistanceStretchedY").set(&distanceStretchedY, 1);
|
||||
mBuilder->uniform("uDistDiffX").set(&diffX, 1);
|
||||
|
||||
@@ -33,8 +33,12 @@ public:
|
||||
SmoothStep,
|
||||
};
|
||||
|
||||
StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmount)
|
||||
: stretchArea(area), maxStretchAmount(maxStretchAmount), mStretchDirection(direction) {}
|
||||
StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmountX,
|
||||
float maxStretchAmountY)
|
||||
: stretchArea(area)
|
||||
, maxStretchAmountX(maxStretchAmountX)
|
||||
, maxStretchAmountY(maxStretchAmountY)
|
||||
, mStretchDirection(direction) {}
|
||||
|
||||
StretchEffect() {}
|
||||
|
||||
@@ -50,7 +54,8 @@ public:
|
||||
this->stretchArea = other.stretchArea;
|
||||
this->mStretchDirection = other.mStretchDirection;
|
||||
this->mStretchFilter = nullptr;
|
||||
this->maxStretchAmount = other.maxStretchAmount;
|
||||
this->maxStretchAmountX = other.maxStretchAmountX;
|
||||
this->maxStretchAmountY = other.maxStretchAmountY;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -67,13 +72,15 @@ public:
|
||||
return setEmpty();
|
||||
}
|
||||
stretchArea.join(other.stretchArea);
|
||||
maxStretchAmount = std::max(maxStretchAmount, other.maxStretchAmount);
|
||||
maxStretchAmountX = std::max(maxStretchAmountX, other.maxStretchAmountX);
|
||||
maxStretchAmountY = std::max(maxStretchAmountY, other.maxStretchAmountY);
|
||||
}
|
||||
|
||||
sk_sp<SkImageFilter> getImageFilter(const sk_sp<SkImage>& snapshotImage) const;
|
||||
|
||||
SkRect stretchArea {0, 0, 0, 0};
|
||||
float maxStretchAmount = 0;
|
||||
float maxStretchAmountX = 0;
|
||||
float maxStretchAmountY = 0;
|
||||
|
||||
void setStretchDirection(const SkVector& direction) {
|
||||
mStretchFilter = nullptr;
|
||||
|
||||
@@ -181,9 +181,10 @@ static jboolean android_view_RenderNode_clearStretch(CRITICAL_JNI_PARAMS_COMMA j
|
||||
|
||||
static jboolean android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
|
||||
jfloat left, jfloat top, jfloat right,
|
||||
jfloat bottom, jfloat vX, jfloat vY, jfloat max) {
|
||||
StretchEffect effect =
|
||||
StretchEffect(SkRect::MakeLTRB(left, top, right, bottom), {.fX = vX, .fY = vY}, max);
|
||||
jfloat bottom, jfloat vX, jfloat vY, jfloat maxX,
|
||||
jfloat maxY) {
|
||||
StretchEffect effect = StretchEffect(SkRect::MakeLTRB(left, top, right, bottom),
|
||||
{.fX = vX, .fY = vY}, maxX, maxY);
|
||||
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
|
||||
renderNode->mutateStagingProperties().mutateLayerProperties().mutableStretchEffect().mergeWith(
|
||||
effect);
|
||||
@@ -662,7 +663,7 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
|
||||
env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
|
||||
info.canvasContext.getFrameNumber(), area.left, area.top,
|
||||
area.right, area.bottom, stretchDirection.fX, stretchDirection.fY,
|
||||
effect->maxStretchAmount);
|
||||
effect->maxStretchAmountX, effect->maxStretchAmountY);
|
||||
#endif
|
||||
env->DeleteLocalRef(localref);
|
||||
}
|
||||
@@ -738,7 +739,7 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"nSetOutlineEmpty", "(J)Z", (void*)android_view_RenderNode_setOutlineEmpty},
|
||||
{"nSetOutlineNone", "(J)Z", (void*)android_view_RenderNode_setOutlineNone},
|
||||
{"nClearStretch", "(J)Z", (void*)android_view_RenderNode_clearStretch},
|
||||
{"nStretch", "(JFFFFFFF)Z", (void*)android_view_RenderNode_stretch},
|
||||
{"nStretch", "(JFFFFFFFF)Z", (void*)android_view_RenderNode_stretch},
|
||||
{"nHasShadow", "(J)Z", (void*)android_view_RenderNode_hasShadow},
|
||||
{"nSetSpotShadowColor", "(JI)Z", (void*)android_view_RenderNode_setSpotShadowColor},
|
||||
{"nGetSpotShadowColor", "(J)I", (void*)android_view_RenderNode_getSpotShadowColor},
|
||||
|
||||
@@ -18,8 +18,6 @@ package com.android.test.hwui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
public class EdgeEffectStretchActivity extends Activity {
|
||||
|
||||
@@ -27,10 +25,5 @@ public class EdgeEffectStretchActivity extends Activity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.stretch_layout);
|
||||
HorizontalScrollView hsv = findViewById(R.id.horizontal_scroll_view);
|
||||
hsv.setStretchDistance(50f);
|
||||
|
||||
ScrollView sv = findViewById(R.id.scroll_view);
|
||||
sv.setStretchDistance(50f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ public class PositionListenerActivity extends Activity {
|
||||
// Although we could do this in a single call, the real one won't be - so mimic that
|
||||
if (dir.x != 0f) {
|
||||
node.stretch(0f, 0f, (float) getWidth(), (float) getHeight(),
|
||||
dir.x, 0f, maxStretchAmount);
|
||||
dir.x, 0f, maxStretchAmount, maxStretchAmount);
|
||||
}
|
||||
if (dir.y != 0f) {
|
||||
node.stretch(0f, 0f, (float) getWidth(), (float) getHeight(),
|
||||
0f, dir.y, maxStretchAmount);
|
||||
0f, dir.y, maxStretchAmount, maxStretchAmount);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -415,6 +415,7 @@ public class StretchShaderActivity extends Activity {
|
||||
bounds.height(),
|
||||
mOverScrollX,
|
||||
mOverScrollY,
|
||||
mStretchDistance,
|
||||
mStretchDistance
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ public class StretchySurfaceViewActivity extends Activity implements Callback {
|
||||
super.onDraw(canvas);
|
||||
|
||||
RenderNode node = ((RecordingCanvas) canvas).mNode;
|
||||
node.stretch(0f, 0f, getWidth(), getHeight() / 2f, 0f, 1f, 400f);
|
||||
node.stretch(0f, 0f, getWidth(), getHeight() / 2f, 0f,
|
||||
1f, 400f, 400f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user