Flip ArrowTipView when it goes beyond screen height.
Bug: 185354491 Test: Manually tested tips in widget picker, all apps, and reconfigurable widgets tip. Change-Id: I5d1c9e4b8bc3ae89834bc198016ffa409a2b28ad
This commit is contained in:
@@ -24,6 +24,9 @@ import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
|
||||
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
@@ -692,15 +695,19 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
|
||||
|| keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN);
|
||||
}
|
||||
|
||||
private ArrowTipView showReconfigurableWidgetEducationTip() {
|
||||
int[] coords = new int[2];
|
||||
mReconfigureButton.getLocationOnScreen(coords);
|
||||
int tipTopMargin = mLauncher.getResources()
|
||||
@Nullable private ArrowTipView showReconfigurableWidgetEducationTip() {
|
||||
Rect rect = new Rect();
|
||||
if (!mReconfigureButton.getGlobalVisibleRect(rect)) {
|
||||
return null;
|
||||
}
|
||||
@Px int tipMargin = mLauncher.getResources()
|
||||
.getDimensionPixelSize(R.dimen.widget_reconfigure_tip_top_margin);
|
||||
return new ArrowTipView(mLauncher, /* isPointingUp= */ true).showAtLocation(
|
||||
getContext().getString(R.string.reconfigurable_widget_education_tip),
|
||||
/* arrowXCoord= */ coords[0] + mReconfigureButton.getWidth() / 2,
|
||||
/* yCoord= */ coords[1] + mReconfigureButton.getHeight() + tipTopMargin);
|
||||
return new ArrowTipView(mLauncher, /* isPointingUp= */ true)
|
||||
.showAroundRect(
|
||||
getContext().getString(R.string.reconfigurable_widget_education_tip),
|
||||
/* arrowXCoord= */ rect.left + mReconfigureButton.getWidth() / 2,
|
||||
/* rect= */ rect,
|
||||
/* margin= */ tipMargin);
|
||||
}
|
||||
|
||||
private boolean hasSeenReconfigurableWidgetEducationTip() {
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.CornerPathEffect;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
@@ -53,9 +55,10 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
|
||||
protected final BaseDraggingActivity mActivity;
|
||||
private final Handler mHandler = new Handler();
|
||||
private final boolean mIsPointingUp;
|
||||
private final int mArrowWidth;
|
||||
private boolean mIsPointingUp;
|
||||
private Runnable mOnClosed;
|
||||
private View mArrowView;
|
||||
|
||||
public ArrowTipView(Context context) {
|
||||
this(context, false);
|
||||
@@ -109,24 +112,8 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
inflate(context, R.layout.arrow_toast, this);
|
||||
setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
View arrowView = findViewById(R.id.arrow);
|
||||
ViewGroup.LayoutParams arrowLp = arrowView.getLayoutParams();
|
||||
ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
|
||||
arrowLp.width, arrowLp.height, mIsPointingUp));
|
||||
Paint arrowPaint = arrowDrawable.getPaint();
|
||||
@Px int arrowTipRadius = getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.arrow_toast_corner_radius);
|
||||
arrowPaint.setColor(ContextCompat.getColor(getContext(), R.color.arrow_tip_view_bg));
|
||||
arrowPaint.setPathEffect(new CornerPathEffect(arrowTipRadius));
|
||||
arrowView.setBackground(arrowDrawable);
|
||||
// Add negative margin so that the rounded corners on base of arrow are not visible.
|
||||
if (mIsPointingUp) {
|
||||
removeView(arrowView);
|
||||
addView(arrowView, 0);
|
||||
((ViewGroup.MarginLayoutParams) arrowLp).setMargins(0, 0, 0, -1 * arrowTipRadius);
|
||||
} else {
|
||||
((ViewGroup.MarginLayoutParams) arrowLp).setMargins(0, -1 * arrowTipRadius, 0, 0);
|
||||
}
|
||||
mArrowView = findViewById(R.id.arrow);
|
||||
updateArrowTipInView();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,8 +139,7 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
|
||||
DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams();
|
||||
params.gravity = gravity;
|
||||
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) findViewById(
|
||||
R.id.arrow).getLayoutParams();
|
||||
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mArrowView.getLayoutParams();
|
||||
lp.gravity = gravity;
|
||||
|
||||
if (parent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
|
||||
@@ -184,7 +170,8 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the ArrowTipView (tooltip) custom aligned.
|
||||
* Show the ArrowTipView (tooltip) custom aligned. The tooltip is vertically flipped if it
|
||||
* cannot fit on screen in the requested orientation.
|
||||
*
|
||||
* @param text The text to be shown in the tooltip.
|
||||
* @param arrowXCoord The X coordinate for the arrow on the tooltip. The arrow is usually in the
|
||||
@@ -193,8 +180,51 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
* @return The tool tip view. {@code null} if the tip can not be shown.
|
||||
*/
|
||||
@Nullable public ArrowTipView showAtLocation(String text, @Px int arrowXCoord, @Px int yCoord) {
|
||||
return showAtLocation(
|
||||
text,
|
||||
arrowXCoord,
|
||||
/* yCoordDownPointingTip= */ yCoord,
|
||||
/* yCoordUpPointingTip= */ yCoord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the ArrowTipView (tooltip) custom aligned. The tooltip is vertically flipped if it
|
||||
* cannot fit on screen in the requested orientation.
|
||||
*
|
||||
* @param text The text to be shown in the tooltip.
|
||||
* @param arrowXCoord The X coordinate for the arrow on the tooltip. The arrow is usually in the
|
||||
* center of tooltip unless the tooltip goes beyond screen margin.
|
||||
* @param rect The coordinates of the view which requests the tooltip to be shown.
|
||||
* @param margin The margin between {@param rect} and the tooltip.
|
||||
* @return The tool tip view. {@code null} if the tip can not be shown.
|
||||
*/
|
||||
@Nullable public ArrowTipView showAroundRect(
|
||||
String text, @Px int arrowXCoord, Rect rect, @Px int margin) {
|
||||
return showAtLocation(
|
||||
text,
|
||||
arrowXCoord,
|
||||
/* yCoordDownPointingTip= */ rect.top - margin,
|
||||
/* yCoordUpPointingTip= */ rect.bottom + margin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the ArrowTipView (tooltip) custom aligned. The tooltip is vertically flipped if it
|
||||
* cannot fit on screen in the requested orientation.
|
||||
*
|
||||
* @param text The text to be shown in the tooltip.
|
||||
* @param arrowXCoord The X coordinate for the arrow on the tooltip. The arrow is usually in the
|
||||
* center of tooltip unless the tooltip goes beyond screen margin.
|
||||
* @param yCoordDownPointingTip The Y coordinate of the pointed tip end of the tooltip when the
|
||||
* tooltip is placed pointing downwards.
|
||||
* @param yCoordUpPointingTip The Y coordinate of the pointed tip end of the tooltip when the
|
||||
* tooltip is placed pointing upwards.
|
||||
* @return The tool tip view. {@code null} if the tip can not be shown.
|
||||
*/
|
||||
@Nullable private ArrowTipView showAtLocation(String text, @Px int arrowXCoord,
|
||||
@Px int yCoordDownPointingTip, @Px int yCoordUpPointingTip) {
|
||||
ViewGroup parent = mActivity.getDragLayer();
|
||||
@Px int parentViewWidth = parent.getWidth();
|
||||
@Px int parentViewHeight = parent.getHeight();
|
||||
@Px int maxTextViewWidth = getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.widget_picker_education_tip_max_width);
|
||||
@Px int minViewMargin = getContext().getResources()
|
||||
@@ -211,6 +241,7 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
requestLayout();
|
||||
|
||||
post(() -> {
|
||||
// Adjust the tooltip horizontally.
|
||||
float halfWidth = getWidth() / 2f;
|
||||
float xCoord;
|
||||
if (arrowXCoord - halfWidth < minViewMargin) {
|
||||
@@ -226,13 +257,24 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
xCoord = arrowXCoord - halfWidth;
|
||||
}
|
||||
setX(xCoord);
|
||||
// Place the tooltip such that its top is at yCoord if arrow is pointing upwards,
|
||||
// otherwise place it such that its bottom is at yCoord.
|
||||
setY(mIsPointingUp ? yCoord : yCoord - getHeight());
|
||||
|
||||
// Adjust the tooltip vertically.
|
||||
@Px int viewHeight = getHeight();
|
||||
if (mIsPointingUp
|
||||
? (yCoordUpPointingTip + viewHeight > parentViewHeight)
|
||||
: (yCoordDownPointingTip - viewHeight < 0)) {
|
||||
// Flip the view if it exceeds the vertical bounds of screen.
|
||||
mIsPointingUp = !mIsPointingUp;
|
||||
updateArrowTipInView();
|
||||
}
|
||||
// Place the tooltip such that its top is at yCoordUpPointingTip if arrow is displayed
|
||||
// pointing upwards, otherwise place it such that its bottom is at
|
||||
// yCoordDownPointingTip.
|
||||
setY(mIsPointingUp ? yCoordUpPointingTip : yCoordDownPointingTip - viewHeight);
|
||||
|
||||
// Adjust the arrow's relative position on tooltip to make sure the actual position of
|
||||
// arrow's pointed tip is always at arrowXCoord.
|
||||
View arrowView = findViewById(R.id.arrow);
|
||||
arrowView.setX(arrowXCoord - xCoord - arrowView.getWidth() / 2f);
|
||||
mArrowView.setX(arrowXCoord - xCoord - mArrowView.getWidth() / 2f);
|
||||
requestLayout();
|
||||
});
|
||||
|
||||
@@ -249,6 +291,27 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void updateArrowTipInView() {
|
||||
ViewGroup.LayoutParams arrowLp = mArrowView.getLayoutParams();
|
||||
ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
|
||||
arrowLp.width, arrowLp.height, mIsPointingUp));
|
||||
Paint arrowPaint = arrowDrawable.getPaint();
|
||||
@Px int arrowTipRadius = getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.arrow_toast_corner_radius);
|
||||
arrowPaint.setColor(ContextCompat.getColor(getContext(), R.color.arrow_tip_view_bg));
|
||||
arrowPaint.setPathEffect(new CornerPathEffect(arrowTipRadius));
|
||||
mArrowView.setBackground(arrowDrawable);
|
||||
// Add negative margin so that the rounded corners on base of arrow are not visible.
|
||||
removeView(mArrowView);
|
||||
if (mIsPointingUp) {
|
||||
addView(mArrowView, 0);
|
||||
((ViewGroup.MarginLayoutParams) arrowLp).setMargins(0, 0, 0, -1 * arrowTipRadius);
|
||||
} else {
|
||||
addView(mArrowView, 1);
|
||||
((ViewGroup.MarginLayoutParams) arrowLp).setMargins(0, -1 * arrowTipRadius, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback fired when toast is hidden
|
||||
*/
|
||||
@@ -256,4 +319,10 @@ public class ArrowTipView extends AbstractFloatingView {
|
||||
mOnClosed = runnable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
close(/* animate= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user