diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml index aee00a95ae..9a6f8c35bd 100644 --- a/res/layout/arrow_toast.xml +++ b/res/layout/arrow_toast.xml @@ -28,13 +28,14 @@ android:padding="16dp" android:background="@drawable/arrow_toast_rounded_background" android:elevation="2dp" + android:outlineProvider="none" android:textColor="@color/arrow_tip_view_content" android:textSize="14sp"/> + android:layout_height="10dp"/> diff --git a/res/values-v28/dimens.xml b/res/values-v28/dimens.xml index ffa8cc4258..3f118cd9eb 100644 --- a/res/values-v28/dimens.xml +++ b/res/values-v28/dimens.xml @@ -1,5 +1,5 @@ - 6dp diff --git a/res/values/strings.xml b/res/values/strings.xml index c851cf8273..a470bcdf4e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -105,6 +105,11 @@ To get info without opening apps, you can add widgets to your Home screen + + + Tap to change widget settings + Got it diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 74ac8c24c4..ac582cdcbf 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -30,6 +30,7 @@ import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.PendingRequestArgs; +import com.android.launcher3.views.ArrowTipView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.util.WidgetSizes; @@ -42,6 +43,8 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O private static final float DIMMED_HANDLE_ALPHA = 0f; private static final float RESIZE_THRESHOLD = 0.66f; + private static final String KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN = + "launcher.reconfigurable_widget_education_tip_seen"; private static final Rect sTmpRect = new Rect(); private static final int HANDLE_COUNT = 4; @@ -238,6 +241,15 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mWidgetView.getAppWidgetId(), Launcher.REQUEST_RECONFIGURE_APPWIDGET); }); + if (!hasSeenReconfigurableWidgetEducationTip()) { + post(() -> { + if (showReconfigurableWidgetEducationTip() != null) { + mLauncher.getSharedPrefs().edit() + .putBoolean(KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN, + true).apply(); + } + }); + } } // When we create the resize frame, we first mark all cells as unoccupied. The appropriate @@ -679,4 +691,21 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O || keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END || 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() + .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); + } + + private boolean hasSeenReconfigurableWidgetEducationTip() { + return mLauncher.getSharedPrefs() + .getBoolean(KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN, false) + || Utilities.IS_RUNNING_IN_TEST_HARNESS; + } } diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java index 07d377615b..f3068a7d43 100644 --- a/src/com/android/launcher3/views/ArrowTipView.java +++ b/src/com/android/launcher3/views/ArrowTipView.java @@ -73,6 +73,9 @@ public class ArrowTipView extends AbstractFloatingView { public boolean onControllerInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { close(true); + if (mActivity.getDragLayer().isEventOverView(this, ev)) { + return true; + } } return false; } @@ -111,19 +114,19 @@ public class ArrowTipView extends AbstractFloatingView { 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)); - // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable. - arrowPaint.setPathEffect(new CornerPathEffect( - context.getResources().getDimension(R.dimen.arrow_toast_corner_radius))); + 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); } - - mIsOpen = true; - - mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS); } /** @@ -136,10 +139,10 @@ public class ArrowTipView extends AbstractFloatingView { /** * Show the ArrowTipView (tooltip) center, start, or end aligned. * - * @param text The text to be shown in the tooltip. - * @param gravity The gravity aligns the tooltip center, start, or end. + * @param text The text to be shown in the tooltip. + * @param gravity The gravity aligns the tooltip center, start, or end. * @param arrowMarginStart The margin from start to place arrow (ignored if center) - * @param top The Y coordinate of the bottom of tooltip. + * @param top The Y coordinate of the bottom of tooltip. * @return The tooltip. */ public ArrowTipView show(String text, int gravity, int arrowMarginStart, int top) { @@ -166,6 +169,9 @@ public class ArrowTipView extends AbstractFloatingView { params.leftMargin = mActivity.getDeviceProfile().workspacePadding.left; params.rightMargin = mActivity.getDeviceProfile().workspacePadding.right; post(() -> setY(top - (mIsPointingUp ? 0 : getHeight()))); + + mIsOpen = true; + mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS); setAlpha(0); animate() .alpha(1f) @@ -180,14 +186,13 @@ public class ArrowTipView extends AbstractFloatingView { /** * Show the ArrowTipView (tooltip) custom aligned. * - * @param text The text to be shown in the tooltip. - * @param arrowXCoord The X coordinate for the arrow on the tip. The arrow is usually in the - * center of ArrowTipView unless the ArrowTipView goes beyond screen margin. - * @param yCoord The Y coordinate of the bottom of the tooltip. - * @return The tool tip view. + * @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 yCoord The Y coordinate of the pointed tip end of the tooltip. + * @return The tool tip view. {@code null} if the tip can not be shown. */ - @Nullable - public ArrowTipView showAtLocation(String text, int arrowXCoord, int yCoord) { + @Nullable public ArrowTipView showAtLocation(String text, @Px int arrowXCoord, @Px int yCoord) { ViewGroup parent = mActivity.getDragLayer(); @Px int parentViewWidth = parent.getWidth(); @Px int maxTextViewWidth = getContext().getResources() @@ -209,19 +214,30 @@ public class ArrowTipView extends AbstractFloatingView { float halfWidth = getWidth() / 2f; float xCoord; if (arrowXCoord - halfWidth < minViewMargin) { + // If the tooltip is estimated to go beyond the left margin, place its start just at + // the left margin. xCoord = minViewMargin; } else if (arrowXCoord + halfWidth > parentViewWidth - minViewMargin) { + // If the tooltip is estimated to go beyond the right margin, place it such that its + // end is just at the right margin. xCoord = parentViewWidth - minViewMargin - getWidth(); } else { + // Place the tooltip such that its center is at arrowXCoord. xCoord = arrowXCoord - halfWidth; } setX(xCoord); - setY(yCoord - getHeight()); + // 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 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); requestLayout(); }); + mIsOpen = true; + mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS); setAlpha(0); animate() .alpha(1f) diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java index edd42b4683..3bf993e199 100644 --- a/src/com/android/launcher3/widget/BaseWidgetSheet.java +++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java @@ -207,16 +207,18 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView if (view == null || !ViewCompat.isLaidOut(view)) { return null; } - - mActivityContext.getSharedPrefs().edit() - .putBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, true).apply(); int[] coords = new int[2]; view.getLocationOnScreen(coords); - ArrowTipView arrowTipView = new ArrowTipView(mActivityContext); - return arrowTipView.showAtLocation( - getContext().getString(R.string.long_press_widget_to_add), - /* arrowXCoord= */coords[0] + view.getWidth() / 2, - /* yCoord= */coords[1]); + ArrowTipView arrowTipView = + new ArrowTipView(mActivityContext, /* isPointingUp= */ false).showAtLocation( + getContext().getString(R.string.long_press_widget_to_add), + /* arrowXCoord= */coords[0] + view.getWidth() / 2, + /* yCoord= */coords[1]); + if (arrowTipView != null) { + mActivityContext.getSharedPrefs().edit() + .putBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, true).apply(); + } + return arrowTipView; } /** Returns {@code true} if tip has previously been shown on any of {@link BaseWidgetSheet}. */