Merge "Always place notification dots directly on adaptive icon path" into ub-launcher3-qt-dev

This commit is contained in:
Tony Wickham 2019-05-06 21:57:34 +00:00 committed by Android (Google) Code Review
commit 3acd837949
4 changed files with 59 additions and 34 deletions

View File

@ -23,8 +23,10 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.ViewDebug;
@ -36,33 +38,51 @@ public class DotRenderer {
private static final String TAG = "DotRenderer";
// The dot size is defined as a percentage of the app icon size.
private static final float SIZE_PERCENTAGE = 0.38f;
private static final float SIZE_PERCENTAGE = 0.228f;
// Extra scale down of the dot
private static final float DOT_SCALE = 0.6f;
// Offset the dot slightly away from the icon if there's space.
private static final float OFFSET_PERCENTAGE = 0.02f;
private final float mDotCenterOffset;
private final int mOffset;
private final float mCircleRadius;
private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);
private final Bitmap mBackgroundWithShadow;
private final float mBitmapOffset;
public DotRenderer(int iconSizePx) {
mDotCenterOffset = SIZE_PERCENTAGE * iconSizePx;
mOffset = (int) (OFFSET_PERCENTAGE * iconSizePx);
// Stores the center x and y position as a percentage (0 to 1) of the icon size
private final float[] mRightDotPosition;
private final float[] mLeftDotPosition;
int size = (int) (DOT_SCALE * mDotCenterOffset);
public DotRenderer(int iconSizePx, Path iconShapePath, int pathSize) {
int size = Math.round(SIZE_PERCENTAGE * iconSizePx);
ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
builder.ambientShadowAlpha = 88;
mBackgroundWithShadow = builder.setupBlurForSize(size).createPill(size, size);
mCircleRadius = builder.radius;
mBitmapOffset = -mBackgroundWithShadow.getHeight() * 0.5f; // Same as width.
// Find the points on the path that are closest to the top left and right corners.
mLeftDotPosition = getPathPoint(iconShapePath, pathSize, -1);
mRightDotPosition = getPathPoint(iconShapePath, pathSize, 1);
}
private static float[] getPathPoint(Path path, float size, float direction) {
float halfSize = size / 2;
// Small delta so that we don't get a zero size triangle
float delta = 1;
float x = halfSize + direction * halfSize;
Path trianglePath = new Path();
trianglePath.moveTo(halfSize, halfSize);
trianglePath.lineTo(x + delta * direction, 0);
trianglePath.lineTo(x, -delta);
trianglePath.close();
trianglePath.op(path, Path.Op.INTERSECT);
float[] pos = new float[2];
new PathMeasure(trianglePath, false).getPosTan(0, pos, null);
pos[0] = pos[0] / size;
pos[1] = pos[1] / size;
return pos;
}
/**
@ -74,15 +94,21 @@ public class DotRenderer {
return;
}
canvas.save();
// We draw the dot relative to its center.
float dotCenterX = params.leftAlign
? params.iconBounds.left + mDotCenterOffset / 2
: params.iconBounds.right - mDotCenterOffset / 2;
float dotCenterY = params.iconBounds.top + mDotCenterOffset / 2;
int offsetX = Math.min(mOffset, params.spaceForOffset.x);
int offsetY = Math.min(mOffset, params.spaceForOffset.y);
canvas.translate(dotCenterX + offsetX, dotCenterY - offsetY);
Rect iconBounds = params.iconBounds;
float[] dotPosition = params.leftAlign ? mLeftDotPosition : mRightDotPosition;
float dotCenterX = iconBounds.left + iconBounds.width() * dotPosition[0];
float dotCenterY = iconBounds.top + iconBounds.height() * dotPosition[1];
// Ensure dot fits entirely in canvas clip bounds.
Rect canvasBounds = canvas.getClipBounds();
float offsetX = params.leftAlign
? Math.max(0, canvasBounds.left - (dotCenterX + mBitmapOffset))
: Math.min(0, canvasBounds.right - (dotCenterX - mBitmapOffset));
float offsetY = Math.max(0, canvasBounds.top - (dotCenterY + mBitmapOffset));
// We draw the dot relative to its center.
canvas.translate(dotCenterX + offsetX, dotCenterY + offsetY);
canvas.scale(params.scale, params.scale);
mCirclePaint.setColor(Color.BLACK);
@ -102,9 +128,6 @@ public class DotRenderer {
/** The progress of the animation, from 0 to 1. */
@ViewDebug.ExportedProperty(category = "notification dot")
public float scale;
/** Overrides internally calculated offset if specified value is smaller. */
@ViewDebug.ExportedProperty(category = "notification dot")
public Point spaceForOffset = new Point();
/** Whether the dot should align to the top left of the icon rather than the top right. */
@ViewDebug.ExportedProperty(category = "notification dot")
public boolean leftAlign;

View File

@ -46,10 +46,12 @@ import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconCache.IconLoadRequest;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.views.ActivityContext;
@ -388,7 +390,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
protected void drawDotIfNecessary(Canvas canvas) {
if (!mForceHideDot && (hasDot() || mDotParams.scale > 0)) {
getIconBounds(mDotParams.iconBounds);
mDotParams.spaceForOffset.set((getWidth() - mIconSize) / 2, getPaddingTop());
Utilities.scaleRectAboutCenter(mDotParams.iconBounds, IconShape.getNormalizationScale());
final int scrollX = getScrollX();
final int scrollY = getScrollY();
canvas.translate(scrollX, scrollY);

View File

@ -24,15 +24,13 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
public class DeviceProfile {
public final InvariantDeviceProfile inv;
@ -240,7 +238,8 @@ public class DeviceProfile {
updateWorkspacePadding();
// This is done last, after iconSizePx is calculated above.
mDotRenderer = new DotRenderer(iconSizePx);
mDotRenderer = new DotRenderer(iconSizePx, IconShape.getShapePath(),
IconShape.DEFAULT_PATH_SIZE);
}
public DeviceProfile copy(Context context) {

View File

@ -36,6 +36,8 @@ import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import com.android.launcher3.Alarm;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
@ -50,11 +52,11 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.SimpleOnStylusPressListener;
import com.android.launcher3.StylusEventHelper;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.dragndrop.BaseItemDragListener;
@ -68,8 +70,6 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
@ -510,10 +510,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
Rect iconBounds = mDotParams.iconBounds;
BubbleTextView.getIconBounds(this, iconBounds,
mLauncher.getWallpaperDeviceProfile().iconSizePx);
float iconScale = (float) mBackground.previewSize / iconBounds.width();
Utilities.scaleRectAboutCenter(iconBounds, iconScale);
// If we are animating to the accepting state, animate the dot out.
mDotParams.scale = Math.max(0, mDotScale - mBackground.getScaleProgress());
mDotParams.spaceForOffset.set(getWidth() - iconBounds.right, iconBounds.top);
mDotParams.color = mBackground.getDotColor();
mDotRenderer.draw(canvas, mDotParams);
}