mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
Moving folder shape logic definition to xml
Adding support for storing custom parameters in shape definition Change-Id: I06f04f1836b337f8cc0ab2ad8c893bb03ae9c794
This commit is contained in:
@@ -33,9 +33,11 @@
|
||||
<attr name="workspaceKeyShadowColor" format="color" />
|
||||
<attr name="workspaceStatusBarScrim" format="reference" />
|
||||
<attr name="widgetsTheme" format="reference" />
|
||||
<attr name="folderDotColor" format="color" />
|
||||
<attr name="loadingIconColor" format="color" />
|
||||
|
||||
<attr name="folderDotColor" format="color" />
|
||||
<attr name="folderIconRadius" format="float" />
|
||||
|
||||
<!-- BubbleTextView specific attributes. -->
|
||||
<declare-styleable name="BubbleTextView">
|
||||
<attr name="layoutHorizontal" format="boolean" />
|
||||
|
||||
33
res/xml/folder_shapes.xml
Normal file
33
res/xml/folder_shapes.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<shapes xmlns:launcher="http://schemas.android.com/apk/res-auto" >
|
||||
|
||||
<Circle launcher:folderIconRadius="1" />
|
||||
|
||||
<!-- Default icon for AOSP -->
|
||||
<RoundedSquare launcher:folderIconRadius="0.16" />
|
||||
|
||||
<!-- Rounded icon from RRO -->
|
||||
<RoundedSquare launcher:folderIconRadius="0.6" />
|
||||
|
||||
<!-- Square icon -->
|
||||
<RoundedSquare launcher:folderIconRadius="0" />
|
||||
|
||||
<TearDrop launcher:folderIconRadius="0.3" />
|
||||
<Squircle launcher:folderIconRadius="0.2" />
|
||||
|
||||
</shapes>
|
||||
@@ -38,6 +38,6 @@ public class MainProcessInitializer implements ResourceBasedOverride {
|
||||
FileLog.setDir(context.getApplicationContext().getFilesDir());
|
||||
FeatureFlags.initialize(context);
|
||||
SessionCommitReceiver.applyDefaultUserPrefs(context);
|
||||
FolderShape.init();
|
||||
FolderShape.init(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ import android.animation.FloatArrayEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
@@ -34,13 +37,28 @@ import android.graphics.RegionIterator;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.ViewOutlineProvider;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract representation of the shape of a folder icon
|
||||
@@ -53,15 +71,7 @@ public abstract class FolderShape {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private static FolderShape[] getAllShapes() {
|
||||
return new FolderShape[] {
|
||||
new Circle(),
|
||||
new RoundedSquare(8f / 50), // Ratios based on path defined in config_icon_mask
|
||||
new RoundedSquare(30f / 50),
|
||||
new Square(),
|
||||
new TearDrop(),
|
||||
new Squircle()};
|
||||
}
|
||||
private SparseArray<TypedValue> mAttrs;
|
||||
|
||||
public abstract void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
|
||||
Paint paint);
|
||||
@@ -71,6 +81,11 @@ public abstract class FolderShape {
|
||||
public abstract Animator createRevealAnimator(Folder target, Rect startRect, Rect endRect,
|
||||
float endRadius, boolean isReversed);
|
||||
|
||||
@Nullable
|
||||
public TypedValue getAttrValue(int attr) {
|
||||
return mAttrs == null ? null : mAttrs.get(attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract shape where the reveal animation is a derivative of a round rect animation
|
||||
*/
|
||||
@@ -163,44 +178,22 @@ public abstract class FolderShape {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Square extends SimpleRectShape {
|
||||
|
||||
@Override
|
||||
public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
|
||||
float cx = radius + offsetX;
|
||||
float cy = radius + offsetY;
|
||||
canvas.drawRect(cx - radius, cy - radius, cx + radius, cy + radius, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path path, float offsetX, float offsetY, float radius) {
|
||||
float cx = radius + offsetX;
|
||||
float cy = radius + offsetY;
|
||||
path.addRect(cx - radius, cy - radius, cx + radius, cy + radius, Path.Direction.CW);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getStartRadius(Rect startRect) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RoundedSquare extends SimpleRectShape {
|
||||
|
||||
/**
|
||||
* Ratio of corner radius to half size. Based on the
|
||||
* Ratio of corner radius to half size.
|
||||
*/
|
||||
private final float mRadiusFactor;
|
||||
private final float mRadiusRatio;
|
||||
|
||||
public RoundedSquare(float radiusFactor) {
|
||||
mRadiusFactor = radiusFactor;
|
||||
public RoundedSquare(float radiusRatio) {
|
||||
mRadiusRatio = radiusRatio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) {
|
||||
float cx = radius + offsetX;
|
||||
float cy = radius + offsetY;
|
||||
float cr = radius * mRadiusFactor;
|
||||
float cr = radius * mRadiusRatio;
|
||||
canvas.drawRoundRect(cx - radius, cy - radius, cx + radius, cy + radius, cr, cr, p);
|
||||
}
|
||||
|
||||
@@ -208,14 +201,14 @@ public abstract class FolderShape {
|
||||
public void addShape(Path path, float offsetX, float offsetY, float radius) {
|
||||
float cx = radius + offsetX;
|
||||
float cy = radius + offsetY;
|
||||
float cr = radius * mRadiusFactor;
|
||||
float cr = radius * mRadiusRatio;
|
||||
path.addRoundRect(cx - radius, cy - radius, cx + radius, cy + radius, cr, cr,
|
||||
Path.Direction.CW);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getStartRadius(Rect startRect) {
|
||||
return (startRect.width() / 2f) * mRadiusFactor;
|
||||
return (startRect.width() / 2f) * mRadiusRatio;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,13 +217,16 @@ public abstract class FolderShape {
|
||||
/**
|
||||
* Radio of short radius to large radius, based on the shape options defined in the config.
|
||||
*/
|
||||
private static final float RADIUS_RATIO = 15f / 50;
|
||||
|
||||
private final float mRadiusRatio;
|
||||
private final float[] mTempRadii = new float[8];
|
||||
|
||||
public TearDrop(float radiusRatio) {
|
||||
mRadiusRatio = radiusRatio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path p, float offsetX, float offsetY, float r1) {
|
||||
float r2 = r1 * RADIUS_RATIO;
|
||||
float r2 = r1 * mRadiusRatio;
|
||||
float cx = r1 + offsetX;
|
||||
float cy = r1 + offsetY;
|
||||
|
||||
@@ -249,7 +245,7 @@ public abstract class FolderShape {
|
||||
protected AnimatorUpdateListener newUpdateListener(Rect startRect, Rect endRect,
|
||||
float endRadius, Path outPath) {
|
||||
float r1 = startRect.width() / 2f;
|
||||
float r2 = r1 * RADIUS_RATIO;
|
||||
float r2 = r1 * mRadiusRatio;
|
||||
|
||||
float[] startValues = new float[] {
|
||||
startRect.left, startRect.top, startRect.right, startRect.bottom, r1, r2};
|
||||
@@ -273,13 +269,17 @@ public abstract class FolderShape {
|
||||
/**
|
||||
* Radio of radius to circle radius, based on the shape options defined in the config.
|
||||
*/
|
||||
private static final float RADIUS_RATIO = 10f / 50;
|
||||
private final float mRadiusRatio;
|
||||
|
||||
public Squircle(float radiusRatio) {
|
||||
mRadiusRatio = radiusRatio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addShape(Path p, float offsetX, float offsetY, float r) {
|
||||
float cx = r + offsetX;
|
||||
float cy = r + offsetY;
|
||||
float control = r - r * RADIUS_RATIO;
|
||||
float control = r - r * mRadiusRatio;
|
||||
|
||||
p.moveTo(cx, cy - r);
|
||||
addLeftCurve(cx, cy, r, control, p);
|
||||
@@ -310,7 +310,7 @@ public abstract class FolderShape {
|
||||
float startCX = startRect.exactCenterX();
|
||||
float startCY = startRect.exactCenterY();
|
||||
float startR = startRect.width() / 2f;
|
||||
float startControl = startR - startR * RADIUS_RATIO;
|
||||
float startControl = startR - startR * mRadiusRatio;
|
||||
float startHShift = 0;
|
||||
float startVShift = 0;
|
||||
|
||||
@@ -351,17 +351,63 @@ public abstract class FolderShape {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the shape which is closest to closest to the {@link AdaptiveIconDrawable}
|
||||
* Initializes the shape which is closest to the {@link AdaptiveIconDrawable}
|
||||
*/
|
||||
public static void init() {
|
||||
public static void init(Context context) {
|
||||
if (!Utilities.ATLEAST_OREO) {
|
||||
return;
|
||||
}
|
||||
new MainThreadExecutor().execute(FolderShape::pickShapeInBackground);
|
||||
new MainThreadExecutor().execute(() -> pickShapeInBackground(context));
|
||||
}
|
||||
|
||||
private static FolderShape getShapeDefinition(String type, float radius) {
|
||||
switch (type) {
|
||||
case "Circle":
|
||||
return new Circle();
|
||||
case "RoundedSquare":
|
||||
return new RoundedSquare(radius);
|
||||
case "TearDrop":
|
||||
return new TearDrop(radius);
|
||||
case "Squircle":
|
||||
return new Squircle(radius);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid shape type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<FolderShape> getAllShapes(Context context) {
|
||||
ArrayList<FolderShape> result = new ArrayList<>();
|
||||
try (XmlResourceParser parser = context.getResources().getXml(R.xml.folder_shapes)) {
|
||||
|
||||
// Find the root tag
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_TAG
|
||||
&& type != XmlPullParser.END_DOCUMENT
|
||||
&& !"shapes".equals(parser.getName()));
|
||||
|
||||
final int depth = parser.getDepth();
|
||||
int[] radiusAttr = new int[] {R.attr.folderIconRadius};
|
||||
while (((type = parser.next()) != XmlPullParser.END_TAG ||
|
||||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
|
||||
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, radiusAttr);
|
||||
FolderShape shape = getShapeDefinition(parser.getName(), a.getFloat(0, 1));
|
||||
a.recycle();
|
||||
|
||||
shape.mAttrs = Themes.createValueMap(context, attrs);
|
||||
result.add(shape);
|
||||
}
|
||||
}
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
protected static void pickShapeInBackground() {
|
||||
protected static void pickShapeInBackground(Context context) {
|
||||
// Pick any large size
|
||||
int size = 200;
|
||||
|
||||
@@ -379,7 +425,7 @@ public abstract class FolderShape {
|
||||
// Find the shape with minimum area of divergent region.
|
||||
int minArea = Integer.MAX_VALUE;
|
||||
FolderShape closestShape = null;
|
||||
for (FolderShape shape : getAllShapes()) {
|
||||
for (FolderShape shape : getAllShapes(context)) {
|
||||
shapePath.reset();
|
||||
shape.addShape(shapePath, 0, 0, size / 2f);
|
||||
shapeR.setPath(shapePath, full);
|
||||
|
||||
@@ -21,6 +21,9 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* Various utility methods associated with theming.
|
||||
@@ -104,4 +107,26 @@ public class Themes {
|
||||
target.getArray()[14] = Color.blue(dstColor) - Color.blue(srcColor);
|
||||
target.getArray()[19] = Color.alpha(dstColor) - Color.alpha(srcColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a map for attribute-name to value for all the values in {@param attrs} which can be
|
||||
* held in memory for later use.
|
||||
*/
|
||||
public static SparseArray<TypedValue> createValueMap(Context context, AttributeSet attrSet) {
|
||||
int count = attrSet.getAttributeCount();
|
||||
int[] attrNames = new int[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
attrNames[i] = attrSet.getAttributeNameResource(i);
|
||||
}
|
||||
|
||||
SparseArray<TypedValue> result = new SparseArray<>(count);
|
||||
TypedArray ta = context.obtainStyledAttributes(attrSet, attrNames);
|
||||
for (int i = 0; i < count; i++) {
|
||||
TypedValue tv = new TypedValue();
|
||||
ta.getValue(i, tv);
|
||||
result.put(attrNames[i], tv);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user