fix(calls): bound + unclip the answer drag — disc rides a clamped track (trackMax/lateralMax), clipChildren=false up the chain, halo follows; no clip-square, no full-screen runaway
This commit is contained in:
parent
fe32bed081
commit
628618aafe
2 changed files with 35 additions and 10 deletions
|
|
@ -250,6 +250,13 @@ public class IncomingCallActivity extends Activity {
|
||||||
// made "slide to answer" indistinguishable from a twitch. dp(88) ≈ a disc
|
// made "slide to answer" indistinguishable from a twitch. dp(88) ≈ a disc
|
||||||
// diameter of climb. needsDevice: tune one-handed reach on a tall phone.
|
// diameter of climb. needsDevice: tune one-handed reach on a tall phone.
|
||||||
final float commitDistance = Math.max(touchSlop * 4f, dp(88f));
|
final float commitDistance = Math.max(touchSlop * 4f, dp(88f));
|
||||||
|
// The disc rides a BOUNDED track. trackMax caps how far up it can follow the
|
||||||
|
// finger (progress p already saturates at the commit point, so chasing the
|
||||||
|
// finger further just slides the disc off into empty screen); lateralMax
|
||||||
|
// keeps the slide on its vertical rail. Without these the disc trails the
|
||||||
|
// finger 1:1 across the whole screen.
|
||||||
|
final float trackMax = commitDistance;
|
||||||
|
final float lateralMax = dp(24f);
|
||||||
return new View.OnTouchListener() {
|
return new View.OnTouchListener() {
|
||||||
private float downX;
|
private float downX;
|
||||||
private float downY;
|
private float downY;
|
||||||
|
|
@ -279,10 +286,11 @@ public class IncomingCallActivity extends Activity {
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
float up = -dy; // upward = positive progress
|
float up = -dy; // upward = positive progress
|
||||||
float p = (float) Math.min(1.0, Math.max(0.0, up / commitDistance));
|
float p = (float) Math.min(1.0, Math.max(0.0, up / commitDistance));
|
||||||
// Track the finger UP its rail: a little lateral follow,
|
// Follow the finger UP its rail, clamped to the track: the
|
||||||
// but the disc never travels downward (down = no commit).
|
// disc never travels downward and never past trackMax, with
|
||||||
disc.setTranslationX(0.15f * dx);
|
// only a small clamped lateral give.
|
||||||
disc.setTranslationY(Math.min(0f, dy));
|
disc.setTranslationX(Math.max(-lateralMax, Math.min(lateralMax, 0.15f * dx)));
|
||||||
|
disc.setTranslationY(-Math.min(Math.max(up, 0f), trackMax));
|
||||||
applyProgressVisuals(disc, glow, decline, p);
|
applyProgressVisuals(disc, glow, decline, p);
|
||||||
hapticLadder(disc, p);
|
hapticLadder(disc, p);
|
||||||
}
|
}
|
||||||
|
|
@ -327,6 +335,10 @@ public class IncomingCallActivity extends Activity {
|
||||||
float gs = 0.58f + 0.42f * p; // peak 1.0 (the 124dp glow already covers the disc)
|
float gs = 0.58f + 0.42f * p; // peak 1.0 (the 124dp glow already covers the disc)
|
||||||
glow.setScaleX(gs);
|
glow.setScaleX(gs);
|
||||||
glow.setScaleY(gs);
|
glow.setScaleY(gs);
|
||||||
|
// Keep the halo glued behind the moving disc — otherwise it blooms at the
|
||||||
|
// rest position while the disc slides up and away, decoupling the two.
|
||||||
|
glow.setTranslationX(disc.getTranslationX());
|
||||||
|
glow.setTranslationY(disc.getTranslationY());
|
||||||
}
|
}
|
||||||
if (decline != null) {
|
if (decline != null) {
|
||||||
// The screen "takes a side": the decline disc recedes as answer climbs.
|
// The screen "takes a side": the decline disc recedes as answer climbs.
|
||||||
|
|
@ -381,6 +393,7 @@ public class IncomingCallActivity extends Activity {
|
||||||
}
|
}
|
||||||
if (glow != null) {
|
if (glow != null) {
|
||||||
glow.animate().alpha(0f).scaleX(0.58f).scaleY(0.58f)
|
glow.animate().alpha(0f).scaleX(0.58f).scaleY(0.58f)
|
||||||
|
.translationX(0f).translationY(0f)
|
||||||
.setInterpolator(new DecelerateInterpolator())
|
.setInterpolator(new DecelerateInterpolator())
|
||||||
.setDuration(dur + 60)
|
.setDuration(dur + 60)
|
||||||
.start();
|
.start();
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
android:paddingStart="24dp"
|
android:paddingStart="24dp"
|
||||||
android:paddingEnd="24dp">
|
android:paddingEnd="24dp"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
@ -19,10 +21,12 @@
|
||||||
android:layout_weight="1.1" />
|
android:layout_weight="1.1" />
|
||||||
|
|
||||||
<!-- Avatar disc (caller initial, set in code) behind a breathing halo. Sized
|
<!-- Avatar disc (caller initial, set in code) behind a breathing halo. Sized
|
||||||
124dp to match the over-lock hero avatar so answer-from-lock doesn't pop. -->
|
124dp to match the over-lock hero avatar so answer-from-lock doesn't pop.
|
||||||
|
clipChildren=false so the pulsing halo can bloom past the 160dp box. -->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:clipChildren="false">
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/call_avatar_halo"
|
android:id="@+id/call_avatar_halo"
|
||||||
|
|
@ -72,12 +76,18 @@
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="2" />
|
android:layout_weight="2" />
|
||||||
|
|
||||||
|
<!-- clipChildren/clipToPadding=false so the answer disc can slide UP out of the
|
||||||
|
action row (and the column + FrameLayout below) without being clipped at a
|
||||||
|
container edge — otherwise the dragged disc vanishes behind the 124dp glow
|
||||||
|
box. The whole ancestor chain to the root must opt out. -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingBottom="56dp"
|
android:paddingBottom="56dp"
|
||||||
android:weightSum="2">
|
android:weightSum="2"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
<!-- Decline -->
|
<!-- Decline -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
@ -127,7 +137,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center">
|
android:gravity="center"
|
||||||
|
android:clipChildren="false">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/answer_hint"
|
android:id="@+id/answer_hint"
|
||||||
|
|
@ -140,7 +151,8 @@
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:clipChildren="false">
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/answer_glow"
|
android:id="@+id/answer_glow"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue