Add generic tooltip UI

Update existing shields tooltip
This commit is contained in:
Deep
2021-01-27 10:38:03 -05:00
parent a02f47951f
commit 64e79f44cb
15 changed files with 882 additions and 39 deletions
+2
View File
@@ -675,6 +675,7 @@ brave_java_resources = [
"java/res/drawable/ic_phone.xml",
"java/res/drawable/ic_polygon_1.xml",
"java/res/drawable/ic_shield_done_filled.xml",
"java/res/drawable/ic_shield_done_filled_20dp.xml",
"java/res/drawable/ic_sort.xml",
"java/res/drawable/ic_spot_graphic.xml",
"java/res/drawable/ic_spot_graphic_dark.xml",
@@ -718,6 +719,7 @@ brave_java_resources = [
"java/res/drawable/transparent_bg_bordered.xml",
"java/res/drawable/wallet_disconnected_button.xml",
"java/res/drawable/wallet_verify_button.xml",
"java/res/drawable/white_rounded_holo_button.xml",
"java/res/font/poppins_light.ttf",
"java/res/font/poppins_medium.ttf",
"java/res/layout-land/brave_rewards_site_banner.xml",
+4
View File
@@ -45,6 +45,9 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/custom_layout/HeightWrappingViewPager.java",
"../../brave/android/java/org/chromium/chrome/browser/custom_layout/NonSwipeableViewPager.java",
"../../brave/android/java/org/chromium/chrome/browser/custom_layout/VerticalViewPager.java",
"../../brave/android/java/org/chromium/chrome/browser/custom_layout/popup_window_tooltip/ArrowColorDrawable.java",
"../../brave/android/java/org/chromium/chrome/browser/custom_layout/popup_window_tooltip/PopupWindowTooltip.java",
"../../brave/android/java/org/chromium/chrome/browser/custom_layout/popup_window_tooltip/PopupWindowTooltipUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/document/BraveLauncherActivity.java",
"../../brave/android/java/org/chromium/chrome/browser/download/BraveMimeUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/download/settings/BraveDownloadSettings.java",
@@ -149,6 +152,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/shields/BraveShieldsHandler.java",
"../../brave/android/java/org/chromium/chrome/browser/shields/BraveShieldsMenuObserver.java",
"../../brave/android/java/org/chromium/chrome/browser/shields/BraveShieldsUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/shields/ShieldsTooltipEnum.java",
"../../brave/android/java/org/chromium/chrome/browser/signin/BraveSigninManager.java",
"../../brave/android/java/org/chromium/chrome/browser/site_settings/DesktopModePreferences.java",
"../../brave/android/java/org/chromium/chrome/browser/site_settings/PlayYTVideoInBrowserPreferences.java",
@@ -0,0 +1,108 @@
/**
* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.chromium.chrome.browser.custom_layout.popup_window_tooltip;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import androidx.annotation.ColorInt;
public class ArrowColorDrawable extends ColorDrawable {
public static final int LEFT = 0, TOP = 1, RIGHT = 2, BOTTOM = 3, AUTO = 4;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final int mBackgroundColor;
private Path mPath;
private final int mDirection;
ArrowColorDrawable(@ColorInt int foregroundColor, int direction) {
this.mBackgroundColor = Color.TRANSPARENT;
this.mPaint.setColor(foregroundColor);
this.mDirection = direction;
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
updatePath(bounds);
}
private synchronized void updatePath(Rect bounds) {
mPath = new Path();
switch (mDirection) {
case LEFT:
mPath.moveTo(bounds.width(), bounds.height());
mPath.lineTo(0, (float) bounds.height() / 2);
mPath.lineTo(bounds.width(), 0);
mPath.lineTo(bounds.width(), bounds.height());
break;
case TOP:
mPath.moveTo(0, bounds.height());
mPath.lineTo((float) bounds.width() / 2, 0);
mPath.lineTo(bounds.width(), bounds.height());
mPath.lineTo(0, bounds.height());
break;
case RIGHT:
mPath.moveTo(0, 0);
mPath.lineTo(bounds.width(), (float) bounds.height() / 2);
mPath.lineTo(0, bounds.height());
mPath.lineTo(0, 0);
break;
case BOTTOM:
mPath.moveTo(0, 0);
mPath.lineTo((float) bounds.width() / 2, bounds.height());
mPath.lineTo(bounds.width(), 0);
mPath.lineTo(0, 0);
break;
}
mPath.close();
}
@Override
public void draw(Canvas canvas) {
canvas.drawColor(mBackgroundColor);
if (mPath == null) updatePath(getBounds());
canvas.drawPath(mPath, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
public void setColor(@ColorInt int color) {
mPaint.setColor(color);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
if (mPaint.getColorFilter() != null) {
return PixelFormat.TRANSLUCENT;
}
switch (mPaint.getColor() >>> 24) {
case 255:
return PixelFormat.OPAQUE;
case 0:
return PixelFormat.TRANSPARENT;
}
return PixelFormat.TRANSLUCENT;
}
}
@@ -0,0 +1,501 @@
/**
* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.chromium.chrome.browser.custom_layout.popup_window_tooltip;
import static org.chromium.ui.base.ViewUtils.dpToPx;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import androidx.annotation.ColorInt;
import androidx.annotation.DimenRes;
import androidx.annotation.LayoutRes;
import org.chromium.base.Log;
import org.chromium.chrome.R;
public class PopupWindowTooltip implements PopupWindow.OnDismissListener {
private static final String TAG = PopupWindowTooltip.class.getSimpleName();
// Default Resources
private static final int mDefaultPopupWindowStyleRes = android.R.attr.popupWindowStyle;
private static final int mDefaultArrowColorRes = R.color.shields_tooltip_arrow_color_1;
private static final int mDefaultMarginRes = R.dimen.shields_tooltip_margin;
private static final int mDefaultPaddingRes = R.dimen.shields_tooltip_padding;
private static final int mDefaultArrowWidthRes = R.dimen.shields_tooltip_arrow_width;
private static final int mDefaultArrowHeightRes = R.dimen.shields_tooltip_arrow_height;
private final Context mContext;
private OnDismissListener mOnDismissListener;
private OnShowListener mOnShowListener;
private PopupWindow mPopupWindow;
private final int mGravity;
private final int mArrowDirection;
private final boolean mDismissOnInsideTouch;
private final boolean mDismissOnOutsideTouch;
private final boolean mModal;
private final View mContentView;
private View mContentLayout;
private final View mAnchorView;
private final float mMaxWidth;
private ViewGroup mRootView;
private ImageView mArrowView;
private final Drawable mArrowColorDrawable;
private final float mMargin;
private final float mPadding;
private final float mArrowWidth;
private final float mArrowHeight;
private boolean dismissed = false;
private int width;
private int height;
private PopupWindowTooltip(Builder builder) {
mContext = builder.context;
mGravity = builder.gravity;
mArrowDirection = builder.arrowDirection;
mDismissOnInsideTouch = builder.dismissOnInsideTouch;
mDismissOnOutsideTouch = builder.dismissOnOutsideTouch;
mModal = builder.modal;
mContentView = builder.contentView;
mAnchorView = builder.anchorView;
mMaxWidth = builder.maxWidth;
mArrowWidth = builder.arrowWidth;
mArrowHeight = builder.arrowHeight;
mArrowColorDrawable = builder.arrowColorDrawable;
mMargin = builder.margin;
mPadding = builder.padding;
mOnDismissListener = builder.onDismissListener;
mOnShowListener = builder.onShowListener;
mRootView = PopupWindowTooltipUtils.findFrameLayout(mAnchorView);
this.width = builder.width;
this.height = builder.height;
init();
}
private void init() {
configPopupWindow();
configContentView();
}
private void configPopupWindow() {
mPopupWindow = new PopupWindow(mContext, null, mDefaultPopupWindowStyleRes);
mPopupWindow.setOnDismissListener(this);
mPopupWindow.setWidth(width);
mPopupWindow.setHeight(height);
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setTouchable(true);
mPopupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
if (!mDismissOnOutsideTouch && (event.getAction() == MotionEvent.ACTION_DOWN)
&& ((x < 0) || (x >= mContentLayout.getMeasuredWidth()) || (y < 0)
|| (y >= mContentLayout.getMeasuredHeight()))) {
return true;
} else if (!mDismissOnOutsideTouch
&& event.getAction() == MotionEvent.ACTION_OUTSIDE) {
return true;
} else if ((event.getAction() == MotionEvent.ACTION_DOWN)
&& mDismissOnInsideTouch) {
dismiss();
return true;
}
return false;
}
});
mPopupWindow.setClippingEnabled(false);
}
public void show() {
verifyDismissed();
mContentLayout.getViewTreeObserver().addOnGlobalLayoutListener(mLocationLayoutListener);
mContentLayout.getViewTreeObserver().addOnGlobalLayoutListener(mAutoDismissLayoutListener);
mRootView.post(new Runnable() {
@Override
public void run() {
if (mRootView.isShown())
mPopupWindow.showAtLocation(mRootView, Gravity.NO_GRAVITY, mRootView.getWidth(),
mRootView.getHeight());
else
Log.e(TAG, "Tooltip cannot be shown, root view is invalid or has been closed.");
}
});
}
private void verifyDismissed() {
if (dismissed) {
throw new IllegalArgumentException("Tooltip has been dismissed.");
}
}
private PointF calculePopupLocation() {
PointF location = new PointF();
final RectF anchorRect = PopupWindowTooltipUtils.calculeRectInWindow(mAnchorView);
final PointF anchorCenter = new PointF(anchorRect.centerX(), anchorRect.centerY());
switch (mGravity) {
case Gravity.START:
location.x = anchorRect.left - mPopupWindow.getContentView().getWidth() - mMargin;
location.y = anchorCenter.y - mPopupWindow.getContentView().getHeight() / 2f;
break;
case Gravity.END:
location.x = anchorRect.right + mMargin;
location.y = anchorCenter.y - mPopupWindow.getContentView().getHeight() / 2f;
break;
case Gravity.TOP:
location.x = anchorCenter.x - mPopupWindow.getContentView().getWidth() / 2f;
location.y = anchorRect.top - mPopupWindow.getContentView().getHeight() - mMargin;
break;
case Gravity.BOTTOM:
location.x = anchorCenter.x - mPopupWindow.getContentView().getWidth() / 2f;
location.y = anchorRect.bottom + mMargin;
break;
case Gravity.CENTER:
location.x = anchorCenter.x - mPopupWindow.getContentView().getWidth() / 2f;
location.y = anchorCenter.y - mPopupWindow.getContentView().getHeight() / 2f;
break;
default:
throw new IllegalArgumentException(
"Gravity must have be CENTER, START, END, TOP or BOTTOM.");
}
return location;
}
private void configContentView() {
mContentView.setPadding((int) mPadding, (int) mPadding, (int) mPadding, (int) mPadding);
LinearLayout linearLayout = new LinearLayout(mContext);
linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
linearLayout.setOrientation(mArrowDirection == ArrowColorDrawable.LEFT
|| mArrowDirection == ArrowColorDrawable.RIGHT
? LinearLayout.HORIZONTAL
: LinearLayout.VERTICAL);
int layoutPadding = 0;
linearLayout.setPadding(layoutPadding, layoutPadding, layoutPadding, layoutPadding);
mArrowView = new ImageView(mContext);
mArrowView.setImageDrawable(mArrowColorDrawable);
LinearLayout.LayoutParams arrowLayoutParams;
if (mArrowDirection == ArrowColorDrawable.TOP
|| mArrowDirection == ArrowColorDrawable.BOTTOM) {
arrowLayoutParams =
new LinearLayout.LayoutParams((int) mArrowWidth, (int) mArrowHeight, 0);
} else {
arrowLayoutParams =
new LinearLayout.LayoutParams((int) mArrowHeight, (int) mArrowWidth, 0);
}
arrowLayoutParams.gravity = Gravity.CENTER;
mArrowView.setLayoutParams(arrowLayoutParams);
if (mArrowDirection == ArrowColorDrawable.BOTTOM
|| mArrowDirection == ArrowColorDrawable.RIGHT) {
linearLayout.addView(mContentView);
linearLayout.addView(mArrowView);
} else {
linearLayout.addView(mArrowView);
linearLayout.addView(mContentView);
}
LinearLayout.LayoutParams contentViewParams =
new LinearLayout.LayoutParams(width, height, 0);
contentViewParams.gravity = Gravity.CENTER;
mContentView.setLayoutParams(contentViewParams);
mContentLayout = linearLayout;
mContentLayout.setVisibility(View.INVISIBLE);
mPopupWindow.setContentView(mContentLayout);
}
public void dismiss() {
if (dismissed) return;
dismissed = true;
if (mPopupWindow != null) {
mPopupWindow.dismiss();
}
}
public boolean isShowing() {
return mPopupWindow != null && mPopupWindow.isShowing();
}
public <T extends View> T findViewById(int id) {
// noinspection unchecked
return (T) mContentLayout.findViewById(id);
}
@Override
public void onDismiss() {
dismissed = true;
mRootView = null;
if (mOnDismissListener != null) mOnDismissListener.onDismiss(this);
mOnDismissListener = null;
mPopupWindow.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(
mLocationLayoutListener);
mPopupWindow.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(
mArrowLayoutListener);
mPopupWindow.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(
mShowLayoutListener);
mPopupWindow.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(
mAutoDismissLayoutListener);
mPopupWindow = null;
}
private final ViewTreeObserver.OnGlobalLayoutListener mLocationLayoutListener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final PopupWindow popup = mPopupWindow;
if (popup == null || dismissed) return;
if (mMaxWidth > 0 && mContentView.getWidth() > mMaxWidth) {
PopupWindowTooltipUtils.setWidth(mContentView, mMaxWidth);
popup.update(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
return;
}
popup.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
popup.getContentView().getViewTreeObserver().addOnGlobalLayoutListener(
mArrowLayoutListener);
PointF location = calculePopupLocation();
popup.setClippingEnabled(true);
popup.update((int) location.x, (int) location.y, popup.getWidth(),
popup.getHeight());
popup.getContentView().requestLayout();
}
};
private final ViewTreeObserver.OnGlobalLayoutListener mArrowLayoutListener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final PopupWindow popup = mPopupWindow;
if (popup == null || dismissed) return;
popup.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
popup.getContentView().getViewTreeObserver().addOnGlobalLayoutListener(
mShowLayoutListener);
RectF achorRect = PopupWindowTooltipUtils.calculeRectOnScreen(mAnchorView);
RectF contentViewRect =
PopupWindowTooltipUtils.calculeRectOnScreen(mContentLayout);
float x, y;
if (mArrowDirection == ArrowColorDrawable.TOP
|| mArrowDirection == ArrowColorDrawable.BOTTOM) {
x = mContentLayout.getPaddingLeft() + dpToPx(mContext, 2);
float centerX =
(contentViewRect.width() / 2f) - (mArrowView.getWidth() / 2f);
float newX = centerX - (contentViewRect.centerX() - achorRect.centerX());
if (newX > x) {
if (newX + mArrowView.getWidth() + x > contentViewRect.width()) {
x = contentViewRect.width() - mArrowView.getWidth() - x;
} else {
x = newX;
}
}
y = mArrowView.getTop();
y = y + (mArrowDirection == ArrowColorDrawable.BOTTOM ? -1 : +1);
} else {
y = mContentLayout.getPaddingTop() + dpToPx(mContext, 2);
float centerY =
(contentViewRect.height() / 2f) - (mArrowView.getHeight() / 2f);
float newY = centerY - (contentViewRect.centerY() - achorRect.centerY());
if (newY > y) {
if (newY + mArrowView.getHeight() + y > contentViewRect.height()) {
y = contentViewRect.height() - mArrowView.getHeight() - y;
} else {
y = newY;
}
}
x = mArrowView.getLeft();
x = x + (mArrowDirection == ArrowColorDrawable.RIGHT ? -1 : +1);
}
mArrowView.setX((int) x);
mArrowView.setY((int) y);
popup.getContentView().requestLayout();
}
};
private final ViewTreeObserver.OnGlobalLayoutListener mShowLayoutListener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final PopupWindow popup = mPopupWindow;
if (popup == null || dismissed) return;
popup.getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
if (mOnShowListener != null) mOnShowListener.onShow(PopupWindowTooltip.this);
mOnShowListener = null;
mContentLayout.setVisibility(View.VISIBLE);
}
};
private final ViewTreeObserver.OnGlobalLayoutListener mAutoDismissLayoutListener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final PopupWindow popup = mPopupWindow;
if (popup == null || dismissed) return;
if (!mRootView.isShown()) dismiss();
}
};
public interface OnDismissListener {
void onDismiss(PopupWindowTooltip tooltip);
}
public interface OnShowListener {
void onShow(PopupWindowTooltip tooltip);
}
public static class Builder {
private final Context context;
private boolean dismissOnInsideTouch = true;
private boolean dismissOnOutsideTouch = true;
private boolean modal = false;
private View contentView;
private View anchorView;
private int arrowDirection = ArrowColorDrawable.AUTO;
private int gravity = Gravity.BOTTOM;
private float maxWidth;
private Drawable arrowColorDrawable;
private float margin = -1;
private float padding = -1;
private OnDismissListener onDismissListener;
private OnShowListener onShowListener;
private int arrowColor;
private float arrowHeight;
private float arrowWidth;
private int width = ViewGroup.LayoutParams.WRAP_CONTENT;
private int height = ViewGroup.LayoutParams.WRAP_CONTENT;
public Builder(Context context) {
this.context = context;
}
public PopupWindowTooltip build() throws IllegalArgumentException {
validateArguments();
if (arrowColor == 0) {
arrowColor = PopupWindowTooltipUtils.getColor(context, mDefaultArrowColorRes);
}
if (margin < 0) {
margin = context.getResources().getDimension(mDefaultMarginRes);
}
if (padding < 0) {
padding = context.getResources().getDimension(mDefaultPaddingRes);
}
if (arrowDirection == ArrowColorDrawable.AUTO)
arrowDirection = PopupWindowTooltipUtils.tooltipGravityToArrowDirection(gravity);
if (arrowColorDrawable == null)
arrowColorDrawable = new ArrowColorDrawable(arrowColor, arrowDirection);
if (arrowWidth == 0)
arrowWidth = context.getResources().getDimension(mDefaultArrowWidthRes);
if (arrowHeight == 0)
arrowHeight = context.getResources().getDimension(mDefaultArrowHeightRes);
return new PopupWindowTooltip(this);
}
private void validateArguments() throws IllegalArgumentException {
if (context == null) {
throw new IllegalArgumentException("Context not specified.");
}
if (anchorView == null) {
throw new IllegalArgumentException("Anchor view not specified.");
}
}
public Builder setWidth(int width) {
this.width = width;
return this;
}
public Builder setHeight(int height) {
this.height = height;
return this;
}
public Builder contentView(@LayoutRes int contentViewId) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.contentView = inflater.inflate(contentViewId, null, false);
return this;
}
public Builder dismissOnInsideTouch(boolean dismissOnInsideTouch) {
this.dismissOnInsideTouch = dismissOnInsideTouch;
return this;
}
public Builder dismissOnOutsideTouch(boolean dismissOnOutsideTouch) {
this.dismissOnOutsideTouch = dismissOnOutsideTouch;
return this;
}
public Builder modal(boolean modal) {
this.modal = modal;
return this;
}
public Builder anchorView(View anchorView) {
this.anchorView = anchorView;
return this;
}
public Builder gravity(int gravity) {
this.gravity = gravity;
return this;
}
public Builder arrowDirection(int arrowDirection) {
this.arrowDirection = arrowDirection;
return this;
}
public Builder maxWidth(@DimenRes int maxWidthRes) {
this.maxWidth = context.getResources().getDimension(maxWidthRes);
return this;
}
public Builder maxWidth(float maxWidth) {
this.maxWidth = maxWidth;
return this;
}
public Builder padding(float padding) {
this.padding = padding;
return this;
}
public Builder padding(@DimenRes int paddingRes) {
this.padding = context.getResources().getDimension(paddingRes);
return this;
}
public Builder margin(float margin) {
this.margin = margin;
return this;
}
public Builder margin(@DimenRes int marginRes) {
this.margin = context.getResources().getDimension(marginRes);
return this;
}
public Builder arrowColor(@ColorInt int arrowColor) {
this.arrowColor = arrowColor;
return this;
}
public Builder arrowHeight(float arrowHeight) {
this.arrowHeight = arrowHeight;
return this;
}
public Builder arrowWidth(float arrowWidth) {
this.arrowWidth = arrowWidth;
return this;
}
public Builder onDismissListener(OnDismissListener onDismissListener) {
this.onDismissListener = onDismissListener;
return this;
}
public Builder onShowListener(OnShowListener onShowListener) {
this.onShowListener = onShowListener;
return this;
}
}
}
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.chromium.chrome.browser.custom_layout.popup_window_tooltip;
import android.content.Context;
import android.graphics.RectF;
import android.os.Build;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.ColorRes;
public final class PopupWindowTooltipUtils {
public static RectF calculeRectOnScreen(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
return new RectF(location[0], location[1], location[0] + view.getMeasuredWidth(),
location[1] + view.getMeasuredHeight());
}
public static RectF calculeRectInWindow(View view) {
int[] location = new int[2];
view.getLocationInWindow(location);
return new RectF(location[0], location[1], location[0] + view.getMeasuredWidth(),
location[1] + view.getMeasuredHeight());
}
public static void setWidth(View view, float width) {
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params == null) {
params = new ViewGroup.LayoutParams((int) width, view.getHeight());
} else {
params.width = (int) width;
}
view.setLayoutParams(params);
}
public static int tooltipGravityToArrowDirection(int tooltipGravity) {
switch (tooltipGravity) {
case Gravity.START:
return ArrowColorDrawable.RIGHT;
case Gravity.END:
return ArrowColorDrawable.LEFT;
case Gravity.TOP:
return ArrowColorDrawable.BOTTOM;
case Gravity.BOTTOM:
return ArrowColorDrawable.TOP;
case Gravity.CENTER:
return ArrowColorDrawable.TOP;
default:
throw new IllegalArgumentException(
"Gravity must have be CENTER, START, END, TOP or BOTTOM.");
}
}
private static ViewGroup.MarginLayoutParams getOrCreateMarginLayoutParams(View view) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp != null) {
if (lp instanceof ViewGroup.MarginLayoutParams) {
return (ViewGroup.MarginLayoutParams) lp;
} else {
return new ViewGroup.MarginLayoutParams(lp);
}
} else {
return new ViewGroup.MarginLayoutParams(view.getWidth(), view.getHeight());
}
}
public static int getColor(Context context, @ColorRes int colorRes) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return context.getColor(colorRes);
} else {
// noinspection deprecation
return context.getResources().getColor(colorRes);
}
}
public static ViewGroup findFrameLayout(View anchorView) {
ViewGroup rootView = (ViewGroup) anchorView.getRootView();
if (rootView.getChildCount() == 1 && rootView.getChildAt(0) instanceof FrameLayout) {
rootView = (ViewGroup) rootView.getChildAt(0);
}
return rootView;
}
}
@@ -911,7 +911,8 @@ public class BraveShieldsHandler implements BraveRewardsHelper.LargeIconReadyCal
@Override
public void run() {
ImageView iv = (ImageView) mPopupView.findViewById(R.id.site_favicon);
iv.setImageBitmap(BraveRewardsHelper.getCircularBitmap(bmp));
if (iv != null)
iv.setImageBitmap(BraveRewardsHelper.getCircularBitmap(bmp));
}
});
}
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.chromium.chrome.browser.shields;
import org.chromium.chrome.R;
public enum ShieldsTooltipEnum {
ONE_TIME_ADS_TRACKER_BLOCKED_TOOLTIP(
ShieldsTooltipEnumConstants.ONE_TIME_ADS_TRACKER_BLOCKED_TOOLTIP,
R.string.tooltip_title_1, R.string.tooltip_text_1),
VIDEO_ADS_BLOCKED_TOOLTIP(ShieldsTooltipEnumConstants.VIDEO_ADS_BLOCKED_TOOLTIP,
R.string.tooltip_title_2, R.string.tooltip_text_2),
ADS_TRACKER_BLOCKED_TOOLTIP(ShieldsTooltipEnumConstants.ADS_TRACKER_BLOCKED_TOOLTIP,
R.string.tooltip_title_3, R.string.tooltip_text_3),
HTTPS_UPGRADE_TOOLTIP(ShieldsTooltipEnumConstants.HTTPS_UPGRADE_TOOLTIP,
R.string.tooltip_title_4, R.string.tooltip_text_4);
private int id;
private int title;
private int text;
ShieldsTooltipEnum(int id, int title, int text) {
this.id = id;
this.title = title;
this.text = text;
}
public int getId() {
return id;
}
public int getTitle() {
return title;
}
public int getText() {
return text;
}
interface ShieldsTooltipEnumConstants {
static final int ONE_TIME_ADS_TRACKER_BLOCKED_TOOLTIP = 0;
static final int VIDEO_ADS_BLOCKED_TOOLTIP = 1;
static final int ADS_TRACKER_BLOCKED_TOOLTIP = 2;
static final int HTTPS_UPGRADE_TOOLTIP = 3;
}
}
@@ -16,14 +16,18 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -56,6 +60,8 @@ import org.chromium.chrome.browser.BraveRewardsObserver;
import org.chromium.chrome.browser.BraveRewardsPanelPopup;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.brave_stats.BraveStatsUtil;
import org.chromium.chrome.browser.custom_layout.popup_window_tooltip.PopupWindowTooltip;
import org.chromium.chrome.browser.custom_layout.popup_window_tooltip.PopupWindowTooltipUtils;
import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
import org.chromium.chrome.browser.dialogs.BraveAdsSignupDialog;
@@ -141,7 +147,7 @@ public abstract class BraveToolbarLayout extends ToolbarLayout
private boolean mIsNotificationPosted;
private boolean mIsInitialNotificationPosted; // initial red circle notification
private PopupWindow mShieldsTooltipPopupWindow;
private PopupWindowTooltip mShieldsPopupWindowTooltip;
private boolean mIsBottomToolbarVisible;
@@ -235,21 +241,6 @@ public abstract class BraveToolbarLayout extends ToolbarLayout
.RESOURCE_IDENTIFIER_TRACKERS))) {
addStatsToDb(block_type, subresource, currentTab.getUrlString());
}
if (!OnboardingPrefManager.getInstance().hasShieldsTooltipShown()
&& PackageUtils.isFirstInstall(getContext())) {
mShieldsTooltipPopupWindow =
mBraveShieldsHandler.showPopupMenu(mBraveShieldsButton, true);
OnboardingPrefManager.getInstance().setShieldsTooltipShown(true);
mShieldsTooltipPopupWindow.getContentView().setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
mShieldsTooltipPopupWindow.dismiss();
mShieldsTooltipPopupWindow = null;
showShieldsMenu(mBraveShieldsButton);
}
});
}
}
@Override
@@ -378,6 +369,12 @@ public abstract class BraveToolbarLayout extends ToolbarLayout
BraveRewardsHelper.updateBraveRewardsAppOpenCount();
BraveRewardsHelper.setShowBraveRewardsOnboardingModal(false);
}
if (mBraveShieldsButton != null
&& (mBraveShieldsHandler.getTackersBlockedCount(tab.getId())
+ mBraveShieldsHandler.getAdsBlockedCount(tab.getId()))
> 0) {
showTooltip();
}
}
@Override
@@ -398,9 +395,45 @@ public abstract class BraveToolbarLayout extends ToolbarLayout
};
}
private void showTooltip() {
if (!OnboardingPrefManager.getInstance().hasShieldsTooltipShown()
&& PackageUtils.isFirstInstall(getContext())) {
mShieldsPopupWindowTooltip = new PopupWindowTooltip.Builder(getContext())
.anchorView(mBraveShieldsButton)
.gravity(Gravity.BOTTOM)
.dismissOnOutsideTouch(true)
.dismissOnInsideTouch(false)
.modal(true)
.contentView(R.layout.brave_shields_tooltip_layout)
.build();
mShieldsPopupWindowTooltip.findViewById(R.id.btn_tooltip)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismissShieldsTooltip();
showShieldsMenu(mBraveShieldsButton);
}
});
TextView tooltipTitle = mShieldsPopupWindowTooltip.findViewById(R.id.txt_tooltip_title);
SpannableStringBuilder ssb = new SpannableStringBuilder(
new StringBuilder("\t\t")
.append(getContext().getResources().getString(R.string.tooltip_title_1))
.toString());
ssb.setSpan(new ImageSpan(getContext(), R.drawable.ic_shield_done_filled_20dp), 0, 1,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
tooltipTitle.setText(ssb, TextView.BufferType.SPANNABLE);
mShieldsPopupWindowTooltip.show();
OnboardingPrefManager.getInstance().setShieldsTooltipShown(true);
}
}
public void dismissShieldsTooltip() {
if (mShieldsTooltipPopupWindow != null) {
mShieldsTooltipPopupWindow.dismiss();
if (mShieldsPopupWindowTooltip != null && mShieldsPopupWindowTooltip.isShowing()) {
mShieldsPopupWindowTooltip.dismiss();
mShieldsPopupWindowTooltip = null;
}
}
@@ -414,6 +447,7 @@ public abstract class BraveToolbarLayout extends ToolbarLayout
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
dismissShieldsTooltip();
reopenShieldsPanel();
}
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M13.8373,6.8203C14.2076,7.0929 14.2876,7.615 14.0141,7.9852L10.3283,12.9886C10.1915,13.1746 9.9847,13.2955 9.7562,13.323C9.7229,13.3272 9.6895,13.3288 9.657,13.3288C9.4619,13.3288 9.2718,13.2604 9.1216,13.1337L6.1363,10.632C5.7827,10.3368 5.7369,9.8106 6.0321,9.457C6.3273,9.1051 6.8534,9.0568 7.207,9.3536L9.5119,11.2849L12.6715,6.997C12.9451,6.6268 13.4662,6.5467 13.8373,6.8203ZM16.6768,2.4882H15.8429C12.3405,2.4882 10.7636,0.4159 10.7011,0.3325C10.5243,0.0857 10.2374,-0.0202 9.9547,0.0032C9.7096,0.0132 9.4702,0.1166 9.3126,0.3284C9.2476,0.4159 7.6698,2.4882 4.1683,2.4882H3.3344C2.4146,2.4882 1.6666,3.2362 1.6666,4.156V6.6576C1.6666,7.118 1.6708,7.8735 1.6758,8.3338C1.6766,8.4213 1.8601,17.0897 9.7204,19.9491C9.7262,19.9508 9.7321,19.9508 9.7371,19.9525C9.823,19.9817 9.913,20 10.0056,20C10.0982,20 10.1874,19.9817 10.2733,19.9525C10.2791,19.9508 10.2849,19.9508 10.2908,19.9491C18.1511,17.0897 18.3346,8.4213 18.3354,8.3338C18.3404,7.8735 18.3446,7.118 18.3446,6.6576V4.156C18.3446,3.2362 17.5966,2.4882 16.6768,2.4882Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>
@@ -7,6 +7,7 @@
android:startColor="#F73A1C"
android:endColor="#BF14A2"
android:type="linear" />
<corners android:radius="6dp" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<!--border color and border width-->
<stroke
android:width="1dp"
android:color="@android:color/white" />
<!--border radius in dp-->
<corners android:radius="25dp"/>
</shape>
@@ -10,35 +10,40 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
android:background="@drawable/shields_tooltip_background">
<TextView
android:layout_width="wrap_content"
android:id="@+id/txt_tooltip_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:singleLine="true"
android:ellipsize="end"
android:fontFamily="sans-serif"
android:layout_marginBottom="8dp"
android:text="@string/nice"
android:text="@string/tooltip_title_1"
android:textColor="@android:color/white"/>
<TextView
android:layout_width="wrap_content"
android:id="@+id/txt_tooltip_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:fontFamily="sans-serif"
android:layout_marginBottom="16dp"
android:text="@string/you_just_blocked"
android:layout_marginBottom="8dp"
android:text="@string/tooltip_text_1"
android:textColor="@android:color/white"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:fontFamily="sans-serif"
android:text="@string/take_a_look"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/btn_tooltip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@drawable/white_rounded_holo_button"
android:text="@string/take_a_look"
android:fontFamily="sans-serif"
android:textAllCaps="false"
android:textSize="16sp"
android:padding="8dp"
android:textColor="@android:color/white"
style="?android:attr/borderlessButtonStyle"/>
</LinearLayout>
+2
View File
@@ -132,5 +132,7 @@
<color name="brave_rewards_opt_in_bg_color">#E7E9FE</color>
<color name="brave_rewards_opt_in_text_color">#474958</color>
<color name="brave_blue_tint_color">#4C54D2</color>
<color name="shields_tooltip_arrow_color_1">#DD295B</color>
</resources>
+5
View File
@@ -48,4 +48,9 @@
<dimen name="brave_tile_view_icon_size_modern">48dp</dimen>
<dimen name="brave_tile_view_icon_margin_top_modern">0dp</dimen>
<dimen name="shields_tooltip_margin">-10dp</dimen>
<dimen name="shields_tooltip_padding">32dp</dimen>
<dimen name="shields_tooltip_arrow_width">30dp</dimen>
<dimen name="shields_tooltip_arrow_height">15dp</dimen>
</resources>
@@ -1189,14 +1189,32 @@ until they verify, or until 90 days have passed.
<message name="IDS_UPDATE_NOTIFICATION_TEXT" desc="Text of notification on application update.">
Browse faster and block ads with Brave
</message>
<message name="IDS_YOU_JUST_BLOCKED" desc="Shields tootltip text">
You just blocked some trackers &amp; ads.
<message name="IDS_TOOLTIP_TITLE_1" desc="Shields tootltip title">
Trackers &amp; ads blocked on this page.
</message>
<message name="IDS_TAKE_A_LOOK" desc="Shields tootltip text">
<message name="IDS_TOOLTIP_TEXT_1" desc="Shields tootltip text">
Brave Shields just protected your privacy.
</message>
<message name="IDS_TAKE_A_LOOK" desc="Shields tootltip button text">
Take a look
</message>
<message name="IDS_NICE" desc="Shields tootltip title">
Nice!
<message name="IDS_TOOLTIP_TITLE_2" desc="Shields tootltip title">
Ads are blocked while watching videos on this website.
</message>
<message name="IDS_TOOLTIP_TEXT_2" desc="Shields tootltip text">
Videos without ads use less data.
</message>
<message name="IDS_TOOLTIP_TITLE_3" desc="Shields tootltip title">
10+ trackers &amp; ads blocked on this page.
</message>
<message name="IDS_TOOLTIP_TEXT_3" desc="Shields tootltip text">
Brave Shields protects your online privacy on every site.
</message>
<message name="IDS_TOOLTIP_TITLE_4" desc="Shields tootltip title">
Your connection is now encrypted.
</message>
<message name="IDS_TOOLTIP_TEXT_4" desc="Shields tootltip text">
If available, Brave upgrades you to a secure connection automatically.
</message>
<message name="IDS_BRAVE_WORKS_EVERYWHERE" desc="Cross promotional modal title text">
Brave works everywhere