Merge "Always place notification dots directly on adaptive icon path" into ub-launcher3-qt-dev
This commit is contained in:
commit
3acd837949
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue