Bubble v2 dismiss changes.

Including:
- Smaller bottom action view
- Make gradient darker
- Text("hide" and "end call") not all caps
- Larger text size
- Padding between icon and text
- Speed up scaling and hiding animation
- Animate opacity together with scaling
- Show "Call ended" text in toast instead of bubble
Bug: 67605985
Test: NewBubbleTest
PiperOrigin-RevId: 181400165
Change-Id: I21b4dcc6324d2dc3eb41377d5264a391c116262f
diff --git a/java/com/android/newbubble/BottomActionViewController.java b/java/com/android/newbubble/BottomActionViewController.java
index 7c71051..a34d3a2 100644
--- a/java/com/android/newbubble/BottomActionViewController.java
+++ b/java/com/android/newbubble/BottomActionViewController.java
@@ -32,14 +32,16 @@
   // the bubble, to prevent the bottom action view from animating if the user just wants to fling
   // the bubble.
   private static final int SHOW_TARGET_DELAY = 100;
-  private static final int SHOW_TARGET_DURATION = 350;
-  private static final int HIDE_TARGET_DURATION = 225;
+  private static final int SHOW_HIDE_TARGET_DURATION = 175;
+  private static final int HIGHLIGHT_TARGET_DURATION = 150;
   private static final float HIGHLIGHT_TARGET_SCALE = 1.5f;
+  private static final float UNHIGHLIGHT_TARGET_ALPHA = 0.38f;
 
   private final Context context;
   private final WindowManager windowManager;
   private final int gradientHeight;
   private final int bottomActionViewTop;
+  private final int textOffsetSize;
 
   private View bottomActionView;
   private View dismissView;
@@ -54,6 +56,8 @@
     gradientHeight =
         context.getResources().getDimensionPixelSize(R.dimen.bubble_bottom_action_view_height);
     bottomActionViewTop = context.getResources().getDisplayMetrics().heightPixels - gradientHeight;
+    textOffsetSize =
+        context.getResources().getDimensionPixelSize(R.dimen.bubble_bottom_action_text_offset);
   }
 
   /** Creates and show the bottom action view. */
@@ -104,7 +108,7 @@
         .alpha(1f)
         .setInterpolator(new LinearInterpolator())
         .setStartDelay(SHOW_TARGET_DELAY)
-        .setDuration(SHOW_TARGET_DURATION)
+        .setDuration(SHOW_HIDE_TARGET_DURATION)
         .start();
   }
 
@@ -117,7 +121,7 @@
         .animate()
         .alpha(0f)
         .setInterpolator(new LinearInterpolator())
-        .setDuration(HIDE_TARGET_DURATION)
+        .setDuration(SHOW_HIDE_TARGET_DURATION)
         .withEndAction(
             () -> {
               // Use removeViewImmediate instead of removeView to avoid view flashing before removed
@@ -143,32 +147,56 @@
     boolean shouldHighlightDismiss = y > bottomActionViewTop && x < middle;
     boolean shouldHighlightEndCall = y > bottomActionViewTop && x >= middle;
 
+    // Set target alpha back to 1
+    if (!dismissHighlighted && endCallHighlighted && !shouldHighlightEndCall) {
+      dismissView.animate().alpha(1f).setDuration(HIGHLIGHT_TARGET_DURATION).start();
+    }
+    if (!endCallHighlighted && dismissHighlighted && !shouldHighlightDismiss) {
+      endCallView.animate().alpha(1f).setDuration(HIGHLIGHT_TARGET_DURATION).start();
+    }
+
+    // Scale unhighlight target back to 1x
     if (!shouldHighlightDismiss && dismissHighlighted) {
       // Unhighlight dismiss
-      dismissView.animate().scaleX(1f).scaleY(1f).setDuration(HIDE_TARGET_DURATION).start();
+      dismissView.animate().scaleX(1f).scaleY(1f).setDuration(HIGHLIGHT_TARGET_DURATION).start();
       dismissHighlighted = false;
     } else if (!shouldHighlightEndCall && endCallHighlighted) {
       // Unhighlight end call
-      endCallView.animate().scaleX(1f).scaleY(1f).setDuration(HIDE_TARGET_DURATION).start();
+      endCallView.animate().scaleX(1f).scaleY(1f).setDuration(HIGHLIGHT_TARGET_DURATION).start();
       endCallHighlighted = false;
     }
 
+    // Scale highlight target larger
     if (shouldHighlightDismiss && !dismissHighlighted) {
       // Highlight dismiss
+      dismissView.setPivotY(dismissView.getHeight() / 2 + textOffsetSize);
       dismissView
           .animate()
           .scaleX(HIGHLIGHT_TARGET_SCALE)
           .scaleY(HIGHLIGHT_TARGET_SCALE)
-          .setDuration(SHOW_TARGET_DURATION)
+          .setDuration(HIGHLIGHT_TARGET_DURATION)
+          .start();
+      // Fade the other target
+      endCallView
+          .animate()
+          .alpha(UNHIGHLIGHT_TARGET_ALPHA)
+          .setDuration(HIGHLIGHT_TARGET_DURATION)
           .start();
       dismissHighlighted = true;
     } else if (shouldHighlightEndCall && !endCallHighlighted) {
       // Highlight end call
+      endCallView.setPivotY(dismissView.getHeight() / 2 + textOffsetSize);
       endCallView
           .animate()
           .scaleX(HIGHLIGHT_TARGET_SCALE)
           .scaleY(HIGHLIGHT_TARGET_SCALE)
-          .setDuration(SHOW_TARGET_DURATION)
+          .setDuration(HIGHLIGHT_TARGET_DURATION)
+          .start();
+      // Fade the other target
+      dismissView
+          .animate()
+          .alpha(UNHIGHLIGHT_TARGET_ALPHA)
+          .setDuration(HIGHLIGHT_TARGET_DURATION)
           .start();
       endCallHighlighted = true;
     }
diff --git a/java/com/android/newbubble/NewBubble.java b/java/com/android/newbubble/NewBubble.java
index f5a036f..202cfcd 100644
--- a/java/com/android/newbubble/NewBubble.java
+++ b/java/com/android/newbubble/NewBubble.java
@@ -40,8 +40,6 @@
 import android.support.v4.os.BuildCompat;
 import android.support.v4.view.animation.LinearOutSlowInInterpolator;
 import android.text.TextUtils;
-import android.transition.TransitionManager;
-import android.transition.TransitionValues;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -49,7 +47,6 @@
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -59,7 +56,6 @@
 import android.view.animation.AnticipateInterpolator;
 import android.view.animation.OvershootInterpolator;
 import android.widget.ImageView;
-import android.widget.TextView;
 import android.widget.Toast;
 import android.widget.ViewAnimator;
 import com.android.dialer.common.LogUtil;
@@ -84,13 +80,12 @@
   // This class has some odd behavior that is not immediately obvious in order to avoid jank when
   // resizing. See http://go/bubble-resize for details.
 
-  // How long text should show after showText(CharSequence) is called
-  private static final int SHOW_TEXT_DURATION_MILLIS = 3000;
   // How long the new window should show before destroying the old one during resize operations.
   // This ensures the new window has had time to draw first.
   private static final int WINDOW_REDRAW_DELAY_MILLIS = 50;
 
   private static final int EXPAND_AND_COLLAPSE_ANIMATION_DURATION = 200;
+  private static final int HIDE_BUBBLE_ANIMATION_DURATION = 250;
 
   private static Boolean canShowBubblesForTesting = null;
 
@@ -110,13 +105,11 @@
 
   @Visibility private int visibility;
   private boolean expanded;
-  private boolean textShowing;
-  private boolean hideAfterText;
   private CharSequence textAfterShow;
   private int collapseEndAction;
 
   ViewHolder viewHolder;
-  private ViewPropertyAnimator collapseAnimation;
+  private AnimatorSet collapseAnimatorSet;
   private Integer overrideGravity;
   @VisibleForTesting AnimatorSet exitAnimatorSet;
 
@@ -124,20 +117,6 @@
   private final int leftBoundary;
   private int savedYPosition = -1;
 
-  private final Runnable collapseRunnable =
-      new Runnable() {
-        @Override
-        public void run() {
-          textShowing = false;
-          if (hideAfterText) {
-            // Always reset here since text shouldn't keep showing.
-            hideAndReset();
-          } else {
-            viewHolder.getPrimaryButton().setDisplayedChild(ViewHolder.CHILD_INDEX_AVATAR_AND_ICON);
-          }
-        }
-      };
-
   /** Type of action after bubble collapse */
   @Retention(RetentionPolicy.SOURCE)
   @IntDef({CollapseEnd.NOTHING, CollapseEnd.HIDE})
@@ -309,7 +288,7 @@
   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
   public void startCollapse(@CollapseEnd int endAction, boolean shouldRecoverYPosition) {
     View expandedView = viewHolder.getExpandedView();
-    if (expandedView.getVisibility() != View.VISIBLE || collapseAnimation != null) {
+    if (expandedView.getVisibility() != View.VISIBLE || collapseAnimatorSet != null) {
       // Drawer is already collapsed or animation is running.
       return;
     }
@@ -353,32 +332,27 @@
     fadeOut.setInterpolator(accelerateDecelerateInterpolator);
 
     // Play all animation together
-    AnimatorSet collapseAnimatorSet = new AnimatorSet();
+    collapseAnimatorSet = new AnimatorSet();
     collapseAnimatorSet.setDuration(EXPAND_AND_COLLAPSE_ANIMATION_DURATION);
     collapseAnimatorSet.playTogether(revealAnim, fadeOut, xValueAnimator);
     collapseAnimatorSet.addListener(
         new AnimatorListenerAdapter() {
           @Override
           public void onAnimationEnd(Animator animation) {
-            collapseAnimation = null;
+            collapseAnimatorSet = null;
             expanded = false;
 
-            if (textShowing) {
-              // Will do resize once the text is done.
-              return;
-            }
-
-            // If this collapse was to come before a hide, do it now.
-            if (collapseEndAction == CollapseEnd.HIDE) {
-              hide();
-            }
-            collapseEndAction = CollapseEnd.NOTHING;
-
             // If collapse on the right side, the primary button move left a bit after drawer
             // visibility becoming GONE. To avoid it, we create a new ViewHolder.
             // It also set primary button clickable back to true, so no need to reset manually.
             replaceViewHolder();
 
+            // If this collapse was to come before a hide, do it now.
+            if (collapseEndAction == CollapseEnd.HIDE) {
+              hide();
+              collapseEndAction = CollapseEnd.NOTHING;
+            }
+
             // Resume normal gravity after any resizing is done.
             handler.postDelayed(
                 () -> {
@@ -407,8 +381,6 @@
       return;
     }
 
-    hideAfterText = false;
-
     boolean isRtl =
         TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
     if (windowParams == null) {
@@ -489,10 +461,6 @@
 
   /** Hide the bubble. */
   public void hide() {
-    if (hideAfterText) {
-      // hideAndReset() will be called after showing text, do nothing here.
-      return;
-    }
     hideHelper(this::defaultAfterHidingAnimation);
   }
 
@@ -564,76 +532,16 @@
   }
 
   /**
-   * Display text in the main bubble. The bubble's drawer is not expandable while text is showing,
-   * and the drawer will be closed if already open.
+   * Display text. The bubble's drawer is not expandable while text is showing, and the drawer will
+   * be closed if already open.
    *
    * @param text the text to display to the user
    */
   public void showText(@NonNull CharSequence text) {
-    textShowing = true;
     if (expanded) {
       startCollapse(CollapseEnd.NOTHING, false /* shouldRecoverYPosition */);
-      doShowText(text);
-    } else {
-      // Need to transition from old bounds to new bounds manually
-      NewChangeOnScreenBounds transition = new NewChangeOnScreenBounds();
-      // Prepare and capture start values
-      TransitionValues startValues = new TransitionValues();
-      startValues.view = viewHolder.getPrimaryButton();
-      transition.addTarget(startValues.view);
-      transition.captureStartValues(startValues);
-
-      // If our view is not laid out yet, postpone showing the text.
-      if (startValues.values.isEmpty()) {
-        textAfterShow = text;
-        return;
-      }
-
-      doShowText(text);
-      // Hide the text so we can animate it in
-      viewHolder.getPrimaryText().setAlpha(0);
-
-      ViewAnimator primaryButton = viewHolder.getPrimaryButton();
-      // Cancel the automatic transition scheduled in doShowText
-      TransitionManager.endTransitions((ViewGroup) primaryButton.getParent());
-      primaryButton
-          .getViewTreeObserver()
-          .addOnPreDrawListener(
-              new OnPreDrawListener() {
-                @Override
-                public boolean onPreDraw() {
-                  primaryButton.getViewTreeObserver().removeOnPreDrawListener(this);
-
-                  // Prepare and capture end values, always use the size of primaryText since
-                  // its invisibility makes primaryButton smaller than expected
-                  TransitionValues endValues = new TransitionValues();
-                  endValues.values.put(
-                      NewChangeOnScreenBounds.PROPNAME_WIDTH,
-                      viewHolder.getPrimaryText().getWidth());
-                  endValues.values.put(
-                      NewChangeOnScreenBounds.PROPNAME_HEIGHT,
-                      viewHolder.getPrimaryText().getHeight());
-                  endValues.view = primaryButton;
-                  transition.addTarget(endValues.view);
-                  transition.captureEndValues(endValues);
-
-                  // animate the primary button bounds change
-                  Animator bounds =
-                      transition.createAnimator(primaryButton, startValues, endValues);
-
-                  // Animate the text in
-                  Animator alpha =
-                      ObjectAnimator.ofFloat(viewHolder.getPrimaryText(), View.ALPHA, 1f);
-
-                  AnimatorSet set = new AnimatorSet();
-                  set.play(bounds).before(alpha);
-                  set.start();
-                  return false;
-                }
-              });
     }
-    handler.removeCallbacks(collapseRunnable);
-    handler.postDelayed(collapseRunnable, SHOW_TEXT_DURATION_MILLIS);
+    Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
   }
 
   @Nullable
@@ -662,9 +570,6 @@
   }
 
   void primaryButtonClick() {
-    if (textShowing || currentInfo.getActions().isEmpty()) {
-      return;
-    }
     if (expanded) {
       logBasicOrCallImpression(DialerImpression.Type.BUBBLE_V2_CLICK_TO_COLLAPSE);
       startCollapse(CollapseEnd.NOTHING, true /* shouldRecoverYPosition */);
@@ -702,12 +607,7 @@
     // Make bubble non clickable to prevent further buggy actions
     viewHolder.setChildClickable(false);
 
-    if (textShowing) {
-      hideAfterText = true;
-      return;
-    }
-
-    if (collapseAnimation != null) {
+    if (collapseAnimatorSet != null) {
       collapseEndAction = CollapseEnd.HIDE;
       return;
     }
@@ -732,6 +632,7 @@
     exitAnimatorSet.playTogether(
         scaleXAnimator, scaleYAnimator, avatarAlphaAnimator, iconAlphaAnimator);
     exitAnimatorSet.setInterpolator(new AnticipateInterpolator());
+    exitAnimatorSet.setDuration(HIDE_BUBBLE_ANIMATION_DURATION);
     exitAnimatorSet.addListener(
         new AnimatorListenerAdapter() {
           @Override
@@ -795,13 +696,6 @@
     configureButton(currentInfo.getActions().get(3), viewHolder.getEndCallButton());
   }
 
-  @VisibleForTesting
-  void doShowText(@NonNull CharSequence text) {
-    TransitionManager.beginDelayedTransition((ViewGroup) viewHolder.getPrimaryButton().getParent());
-    viewHolder.getPrimaryText().setText(text);
-    viewHolder.getPrimaryButton().setDisplayedChild(ViewHolder.CHILD_INDEX_TEXT);
-  }
-
   private void configureButton(Action action, NewCheckableButton button) {
     boolean isRtl =
         TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
@@ -844,7 +738,6 @@
     viewHolder
         .getPrimaryButton()
         .setDisplayedChild(oldViewHolder.getPrimaryButton().getDisplayedChild());
-    viewHolder.getPrimaryText().setText(oldViewHolder.getPrimaryText().getText());
     viewHolder.getPrimaryIcon().setX(isDrawingFromRight() ? 0 : primaryIconMoveDistance);
     viewHolder
         .getPrimaryIcon()
@@ -889,16 +782,10 @@
 
   void bottomActionEndCall() {
     logBasicOrCallImpression(DialerImpression.Type.BUBBLE_V2_BOTTOM_ACTION_END_CALL);
-    // Hide without animation
-    hideHelper(
-        () -> {
-          defaultAfterHidingAnimation();
-          DialerCall call = getCall();
-          if (call != null) {
-            call.disconnect();
-            Toast.makeText(context, R.string.incall_call_ended, Toast.LENGTH_SHORT).show();
-          }
-        });
+    DialerCall call = getCall();
+    if (call != null) {
+      call.disconnect();
+    }
   }
 
   private boolean isDrawingFromRight() {
@@ -987,15 +874,11 @@
   @VisibleForTesting
   class ViewHolder {
 
-    public static final int CHILD_INDEX_AVATAR_AND_ICON = 0;
-    public static final int CHILD_INDEX_TEXT = 1;
-
     private NewMoveHandler moveHandler;
     private final NewWindowRoot root;
     private final ViewAnimator primaryButton;
     private final ImageView primaryIcon;
     private final ImageView primaryAvatar;
-    private final TextView primaryText;
     private final View arrow;
 
     private final NewCheckableButton fullScreenButton;
@@ -1013,7 +896,6 @@
       primaryButton = contentView.findViewById(R.id.bubble_button_primary);
       primaryAvatar = contentView.findViewById(R.id.bubble_icon_avatar);
       primaryIcon = contentView.findViewById(R.id.bubble_icon_primary);
-      primaryText = contentView.findViewById(R.id.bubble_text);
       arrow = contentView.findViewById(R.id.bubble_triangle);
 
       fullScreenButton = contentView.findViewById(R.id.bubble_button_full_screen);
@@ -1032,6 +914,15 @@
           });
       root.setOnConfigurationChangedListener(
           (configuration) -> {
+            if (expanded) {
+              // Collapse immediately without animation
+              if (collapseAnimatorSet != null) {
+                collapseAnimatorSet.removeAllListeners();
+                collapseAnimatorSet.cancel();
+              }
+              setDrawerVisibility(View.GONE);
+              expanded = false;
+            }
             // The values in the current MoveHandler may be stale, so replace it. Then ensure the
             // Window is in bounds
             moveHandler = new NewMoveHandler(primaryButton, NewBubble.this);
@@ -1087,10 +978,6 @@
       return primaryAvatar;
     }
 
-    public TextView getPrimaryText() {
-      return primaryText;
-    }
-
     public View getExpandedView() {
       return expandedView;
     }
diff --git a/java/com/android/newbubble/res/drawable/bottom_action_scrim.xml b/java/com/android/newbubble/res/drawable/bottom_action_scrim.xml
index bd13382..1109aa6 100644
--- a/java/com/android/newbubble/res/drawable/bottom_action_scrim.xml
+++ b/java/com/android/newbubble/res/drawable/bottom_action_scrim.xml
@@ -20,5 +20,5 @@
   <gradient
       android:angle="90"
       android:endColor="@android:color/transparent"
-      android:startColor="#AA000000"/>
+      android:startColor="#FF000000"/>
 </shape>
diff --git a/java/com/android/newbubble/res/layout/bottom_action_base.xml b/java/com/android/newbubble/res/layout/bottom_action_base.xml
index bf08e1b..af7f798 100644
--- a/java/com/android/newbubble/res/layout/bottom_action_base.xml
+++ b/java/com/android/newbubble/res/layout/bottom_action_base.xml
@@ -18,6 +18,7 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/bubble_bottom_action_view_height"
     android:orientation="horizontal"
+    android:gravity="center"
     android:background="@drawable/bottom_action_scrim">
 
   <LinearLayout
@@ -25,19 +26,19 @@
       android:layout_width="0dp"
       android:layout_height="match_parent"
       android:layout_weight="1"
-      android:gravity="center_horizontal|center_vertical">
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/bubble_button_icon_padding"
-        android:src="@drawable/quantum_ic_clear_vd_theme_24"
-        android:tint="@color/bubble_button_color_white"/>
+      android:gravity="center">
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAllCaps="true"
+        android:layout_marginTop="@dimen/bubble_bottom_action_text_offset"
         android:textColor="@color/bubble_button_color_white"
-        android:text="Hide"/>
+        android:textSize="16sp"
+        android:fontFamily="roboto-medium"
+        android:text="@string/bubble_bottom_action_hide"
+        android:drawableStart="@drawable/quantum_ic_clear_vd_theme_24"
+        android:drawableTint="@color/bubble_button_color_white"
+        android:drawablePadding="10dp"
+        android:elevation="2dp"/>
   </LinearLayout>
 
   <LinearLayout
@@ -45,19 +46,19 @@
       android:layout_width="0dp"
       android:layout_height="match_parent"
       android:layout_weight="1"
-      android:gravity="center_horizontal|center_vertical">
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/bubble_button_icon_padding"
-        android:src="@drawable/quantum_ic_call_end_vd_theme_24"
-        android:tint="@color/bubble_button_color_white"/>
+      android:gravity="center">
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAllCaps="true"
+        android:layout_marginTop="@dimen/bubble_bottom_action_text_offset"
         android:textColor="@color/bubble_button_color_white"
-        android:text="End call"/>
+        android:textSize="16sp"
+        android:fontFamily="roboto-medium"
+        android:text="@string/bubble_bottom_action_end_call"
+        android:drawableStart="@drawable/quantum_ic_call_end_vd_theme_24"
+        android:drawableTint="@color/bubble_button_color_white"
+        android:drawablePadding="10dp"
+        android:elevation="2dp"/>
   </LinearLayout>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/java/com/android/newbubble/res/layout/new_bubble_base.xml b/java/com/android/newbubble/res/layout/new_bubble_base.xml
index f6ce26d..2b53b36 100644
--- a/java/com/android/newbubble/res/layout/new_bubble_base.xml
+++ b/java/com/android/newbubble/res/layout/new_bubble_base.xml
@@ -66,16 +66,6 @@
             tools:backgroundTint="#FF0000AA"
             tools:src="@android:drawable/ic_btn_speak_now"/>
       </FrameLayout>
-      <TextView
-          android:id="@+id/bubble_text"
-          android:layout_width="wrap_content"
-          android:layout_height="@dimen/bubble_size"
-          android:paddingStart="@dimen/bubble_icon_padding"
-          android:paddingEnd="@dimen/bubble_icon_padding"
-          android:gravity="center"
-          android:minWidth="@dimen/bubble_size"
-          android:textAppearance="@style/TextAppearance.AppCompat"
-          tools:text="Call ended"/>
     </ViewAnimator>
   </RelativeLayout>
   <!-- The RelativeLayout below serves as boundary for @id/bubble_expanded_layout during animation -->
diff --git a/java/com/android/newbubble/res/values/strings.xml b/java/com/android/newbubble/res/values/strings.xml
index 5b82b18..ce7d456 100644
--- a/java/com/android/newbubble/res/values/strings.xml
+++ b/java/com/android/newbubble/res/values/strings.xml
@@ -24,4 +24,9 @@
   <!-- A string to describe available action for accessibility user. It will be read as "Actions:
     double tap to collapse call action menu". -->
   <string name="a11y_bubble_primary_button_collapse_action">Collapse call action menu</string>
+
+  <!-- The label of drag-and-drop target for dismissing bubble. [CHAR LIMIT=10]-->
+  <string name="bubble_bottom_action_hide">Hide</string>
+  <!-- The label of drag-and-drop target for ending call. [CHAR LIMIT=10]-->
+  <string name="bubble_bottom_action_end_call">End call</string>
 </resources>
\ No newline at end of file
diff --git a/java/com/android/newbubble/res/values/values.xml b/java/com/android/newbubble/res/values/values.xml
index 040a5be..540f665 100644
--- a/java/com/android/newbubble/res/values/values.xml
+++ b/java/com/android/newbubble/res/values/values.xml
@@ -26,8 +26,8 @@
   <dimen name="bubble_button_padding_horizontal">16dp</dimen>
 
   <dimen name="bubble_off_screen_size_horizontal">-4dp</dimen>
-  <!-- 64dp - 16dp(bubble_shadow_padding_size_vertical) -->
-  <dimen name="bubble_safe_margin_vertical">48dp</dimen>
+  <!-- 36dp - 16dp(bubble_shadow_padding_size_vertical) -->
+  <dimen name="bubble_safe_margin_vertical">20dp</dimen>
 
   <dimen name="bubble_shadow_padding_size_vertical">16dp</dimen>
   <dimen name="bubble_shadow_padding_size_vertical_minus">-16dp</dimen>
@@ -42,5 +42,6 @@
   <dimen name="bubble_small_icon_size">24dp</dimen>
   <dimen name="bubble_small_icon_padding">4dp</dimen>
 
-  <dimen name="bubble_bottom_action_view_height">180dp</dimen>
+  <dimen name="bubble_bottom_action_view_height">124dp</dimen>
+  <dimen name="bubble_bottom_action_text_offset">28dp</dimen>
 </resources>