Merge "First pass at new FolderIcon visual treatment" into ub-launcher3-calgary
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.Folder xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.android.launcher3.folder.Folder xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -34,7 +34,7 @@
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp" />
|
||||
|
||||
<com.android.launcher3.FolderPagedView
|
||||
<com.android.launcher3.folder.FolderPagedView
|
||||
android:id="@+id/folder_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@@ -82,4 +82,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.launcher3.Folder>
|
||||
</com.android.launcher3.folder.Folder>
|
||||
|
||||
@@ -138,8 +138,8 @@
|
||||
<dimen name="quantum_panel_outer_padding">4dp</dimen>
|
||||
|
||||
<!-- Folders -->
|
||||
<!-- The amount that the preview contents are inset from the preview background -->
|
||||
<dimen name="folder_preview_padding">4dp</dimen>
|
||||
<!-- The size of the padding on the preview background drawable -->
|
||||
<dimen name="folder_preview_padding">6dp</dimen>
|
||||
|
||||
<!-- Sizes for managed profile badges -->
|
||||
<dimen name="profile_badge_size">24dp</dimen>
|
||||
|
||||
@@ -93,7 +93,7 @@ public class FastBitmapDrawable extends Drawable {
|
||||
private static final ColorMatrix sTempBrightnessMatrix = new ColorMatrix();
|
||||
private static final ColorMatrix sTempFilterMatrix = new ColorMatrix();
|
||||
|
||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
private final Bitmap mBitmap;
|
||||
private State mState = State.NORMAL;
|
||||
|
||||
|
||||
@@ -40,13 +40,13 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherTransitionable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
@@ -31,7 +31,8 @@ public final class FeatureFlags {
|
||||
public static boolean IS_RELEASE_BUILD = true;
|
||||
|
||||
// Custom flags go below this
|
||||
public static boolean LAUNCHER3_ICON_NORMALIZATION = false;
|
||||
// As opposed to the new spring-loaded workspace.
|
||||
public static boolean LAUNCHER3_LEGACY_WORKSPACE_DND = false;
|
||||
public static boolean LAUNCHER3_ICON_NORMALIZATION = true;
|
||||
public static boolean LAUNCHER3_CLIPPED_FOLDER_ICON = false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
|
||||
|
||||
static final int MAX_NUM_ITEMS_IN_PREVIEW = 4;
|
||||
private static final int MIN_NUM_ITEMS_IN_PREVIEW = 2;
|
||||
|
||||
final float MIN_SCALE = 0.48f;
|
||||
final float MAX_SCALE = 0.58f;
|
||||
final float MAX_RADIUS_DILATION = 0.15f;
|
||||
|
||||
private float[] mTmpPoint = new float[2];
|
||||
|
||||
private float mAvailableSpace;
|
||||
private float mRadius;
|
||||
private float mIconSize;
|
||||
private boolean mIsRtl;
|
||||
private Path mClipPath = new Path();
|
||||
|
||||
@Override
|
||||
public void init(int availableSpace, int intrinsicIconSize, boolean rtl) {
|
||||
mAvailableSpace = availableSpace;
|
||||
mRadius = 0.66f * availableSpace;
|
||||
mIconSize = intrinsicIconSize;
|
||||
mIsRtl = rtl;
|
||||
|
||||
// We make the clip radius just slightly smaller than the background drawable
|
||||
// TODO(adamcohen): this is hacky, needs cleanup (likely through programmatic drawing).
|
||||
int clipRadius = (int) mAvailableSpace / 2 - 1;
|
||||
|
||||
mClipPath.addCircle(mAvailableSpace / 2, mAvailableSpace / 2, clipRadius, Path.Direction.CW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FolderIcon.PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
|
||||
int curNumItems, FolderIcon.PreviewItemDrawingParams params) {
|
||||
|
||||
getPosition(index, curNumItems, mTmpPoint);
|
||||
|
||||
float transX = mTmpPoint[0];
|
||||
float transY = mTmpPoint[1];
|
||||
float totalScale = scaleForNumItems(curNumItems);
|
||||
float overlayAlpha = 0;
|
||||
|
||||
if (params == null) {
|
||||
params = new FolderIcon.PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
|
||||
} else {
|
||||
params.transX = transX;
|
||||
params.transY = transY;
|
||||
params.scale = totalScale;
|
||||
params.overlayAlpha = overlayAlpha;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private void getPosition(int index, int curNumItems, float[] result) {
|
||||
// The case of two items is homomorphic to the case of one.
|
||||
curNumItems = Math.max(curNumItems, 2);
|
||||
|
||||
|
||||
// We model the preview as a circle of items starting in the appropriate piece of the
|
||||
// upper left quadrant (to achieve horizontal and vertical symmetry).
|
||||
double theta0 = mIsRtl ? 0 : Math.PI;
|
||||
|
||||
// In RTL we go counterclockwise
|
||||
int direction = mIsRtl ? 1 : -1;
|
||||
|
||||
double thetaShift = 0;
|
||||
if (curNumItems == 3) {
|
||||
thetaShift = Math.PI / 6;
|
||||
} else if (curNumItems == 4) {
|
||||
thetaShift = Math.PI / 4;
|
||||
}
|
||||
theta0 += direction * thetaShift;
|
||||
|
||||
// We want the items to appear in reading order. For the case of 1, 2 and 3 items, this
|
||||
// is natural for the circular model. With 4 items, however, we need to swap the 3rd and
|
||||
// 4th indices to achieve reading order.
|
||||
if (curNumItems == 4 && index == 3) {
|
||||
index = 2;
|
||||
} else if (curNumItems == 4 && index == 2) {
|
||||
index = 3;
|
||||
}
|
||||
|
||||
// We bump the radius up between 0 and MAX_RADIUS_DILATION % as the number of items increase
|
||||
float radius = mRadius * (1 + MAX_RADIUS_DILATION * (curNumItems -
|
||||
MIN_NUM_ITEMS_IN_PREVIEW) / (MAX_NUM_ITEMS_IN_PREVIEW - MIN_NUM_ITEMS_IN_PREVIEW));
|
||||
double theta = theta0 + index * (2 * Math.PI / curNumItems) * direction;
|
||||
|
||||
float halfIconSize = (mIconSize * scaleForNumItems(curNumItems)) / 2;
|
||||
|
||||
// Map the location along the circle, and offset the coordinates to represent the center
|
||||
// of the icon, and to be based from the top / left of the preview area. The y component
|
||||
// is inverted to match the coordinate system.
|
||||
result[0] = mAvailableSpace / 2 + (float) (radius * Math.cos(theta) / 2) - halfIconSize;
|
||||
result[1] = mAvailableSpace / 2 + (float) (- radius * Math.sin(theta) / 2) - halfIconSize;
|
||||
|
||||
}
|
||||
|
||||
private float scaleForNumItems(int numItems) {
|
||||
if (numItems <= 2) {
|
||||
return MAX_SCALE;
|
||||
} else if (numItems == 3) {
|
||||
return (MAX_SCALE + MIN_SCALE) / 2;
|
||||
} else {
|
||||
return MIN_SCALE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numItems() {
|
||||
return MAX_NUM_ITEMS_IN_PREVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getClipPath() {
|
||||
return mClipPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -65,6 +66,7 @@ import com.android.launcher3.SimpleOnStylusPressListener;
|
||||
import com.android.launcher3.StylusEventHelper;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.dragndrop.DragView;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
@@ -81,8 +83,9 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
private FolderInfo mInfo;
|
||||
@Thunk static boolean sStaticValuesDirty = true;
|
||||
|
||||
// TODO(adamcohen): remove this
|
||||
public static final int NUM_ITEMS_IN_PREVIEW = 3;
|
||||
public static final int NUM_ITEMS_IN_PREVIEW = FeatureFlags.LAUNCHER3_CLIPPED_FOLDER_ICON ?
|
||||
ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW :
|
||||
StackFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
|
||||
|
||||
private CheckLongPressHelper mLongPressHelper;
|
||||
private StylusEventHelper mStylusEventHelper;
|
||||
@@ -152,7 +155,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
private void init() {
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
|
||||
mPreviewLayoutRule = new StackFolderIconLayoutRule();
|
||||
mPreviewLayoutRule = FeatureFlags.LAUNCHER3_CLIPPED_FOLDER_ICON ?
|
||||
new ClippedFolderIconLayoutRule() :
|
||||
new StackFolderIconLayoutRule();
|
||||
|
||||
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
|
||||
}
|
||||
|
||||
@@ -468,7 +474,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
}
|
||||
|
||||
int[] center = new int[2];
|
||||
float scale = getLocalCenterForIndex(index, center);
|
||||
float scale = getLocalCenterForIndex(index, index + 1, center);
|
||||
center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
|
||||
center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
|
||||
|
||||
@@ -516,7 +522,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
mIntrinsicIconSize = drawableSize;
|
||||
mTotalWidth = totalSize;
|
||||
|
||||
final int previewSize = mPreviewBackground.getLayoutParams().height;
|
||||
final int previewSize = FolderRingAnimator.sPreviewSize;
|
||||
final int previewPadding = FolderRingAnimator.sPreviewPadding;
|
||||
|
||||
mAvailableSpaceInPreview = (previewSize - 2 * previewPadding);
|
||||
@@ -524,8 +530,8 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
|
||||
mPreviewOffsetY = previewPadding + grid.folderBackgroundOffset + getPaddingTop();
|
||||
|
||||
// Initialize the preview layout rule
|
||||
mPreviewLayoutRule.init(mAvailableSpaceInPreview, mIntrinsicIconSize);
|
||||
mPreviewLayoutRule.init(mAvailableSpaceInPreview, mIntrinsicIconSize,
|
||||
Utilities.isRtl(getResources()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,9 +553,9 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
Drawable drawable;
|
||||
}
|
||||
|
||||
private float getLocalCenterForIndex(int index, int[] center) {
|
||||
private float getLocalCenterForIndex(int index, int curNumItems, int[] center) {
|
||||
mParams = computePreviewItemDrawingParams(Math.min(mPreviewLayoutRule.numItems(), index),
|
||||
mParams);
|
||||
curNumItems, mParams);
|
||||
|
||||
mParams.transX += mPreviewOffsetX;
|
||||
mParams.transY += mPreviewOffsetY;
|
||||
@@ -561,14 +567,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
return mParams.scale;
|
||||
}
|
||||
|
||||
private PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
|
||||
private PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
|
||||
PreviewItemDrawingParams params) {
|
||||
return mPreviewLayoutRule.computePreviewItemDrawingParams(index, params);
|
||||
return mPreviewLayoutRule.computePreviewItemDrawingParams(index, curNumItems, params);
|
||||
}
|
||||
|
||||
private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
|
||||
canvas.save();
|
||||
canvas.translate(params.transX + mPreviewOffsetX, params.transY + mPreviewOffsetY);
|
||||
canvas.translate(params.transX, params.transY);
|
||||
canvas.scale(params.scale, params.scale);
|
||||
Drawable d = params.drawable;
|
||||
|
||||
@@ -612,13 +618,20 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
computePreviewDrawingParams(d);
|
||||
}
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(mPreviewOffsetX, mPreviewOffsetY);
|
||||
Path clipPath = mPreviewLayoutRule.getClipPath();
|
||||
if (clipPath != null) {
|
||||
canvas.clipPath(clipPath);
|
||||
}
|
||||
|
||||
int nItemsInPreview = Math.min(items.size(), mPreviewLayoutRule.numItems());
|
||||
if (!mAnimating) {
|
||||
for (int i = nItemsInPreview - 1; i >= 0; i--) {
|
||||
v = (TextView) items.get(i);
|
||||
if (!mHiddenItems.contains(v.getTag())) {
|
||||
d = getTopDrawable(v);
|
||||
mParams = computePreviewItemDrawingParams(i, mParams);
|
||||
mParams = computePreviewItemDrawingParams(i, nItemsInPreview, mParams);
|
||||
mParams.drawable = d;
|
||||
drawPreviewItem(canvas, mParams);
|
||||
}
|
||||
@@ -626,6 +639,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
} else {
|
||||
drawPreviewItem(canvas, mAnimParams);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
private Drawable getTopDrawable(TextView v) {
|
||||
@@ -635,7 +649,9 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
|
||||
private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
|
||||
final Runnable onCompleteRunnable) {
|
||||
final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
|
||||
|
||||
final PreviewItemDrawingParams finalParams =
|
||||
computePreviewItemDrawingParams(0, reverse ? 1 : 2, null);
|
||||
|
||||
float iconSize = mLauncher.getDeviceProfile().iconSizePx;
|
||||
final float scale0 = iconSize / d.getIntrinsicWidth() ;
|
||||
@@ -749,11 +765,12 @@ public class FolderIcon extends FrameLayout implements FolderListener {
|
||||
}
|
||||
|
||||
public interface PreviewLayoutRule {
|
||||
public PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
|
||||
public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
|
||||
PreviewItemDrawingParams params);
|
||||
|
||||
public void init(int availableSpace, int intrinsicIconSize);
|
||||
public void init(int availableSpace, int intrinsicIconSize, boolean rtl);
|
||||
|
||||
public int numItems();
|
||||
public Path getClipPath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import android.graphics.Path;
|
||||
|
||||
import com.android.launcher3.folder.FolderIcon.PreviewItemDrawingParams;
|
||||
|
||||
public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
|
||||
|
||||
public static final int NUM_ITEMS_IN_PREVIEW = 3;
|
||||
static final int MAX_NUM_ITEMS_IN_PREVIEW = 3;
|
||||
|
||||
// The degree to which the item in the back of the stack is scaled [0...1]
|
||||
// (0 means it's not scaled at all, 1 means it's scaled to nothing)
|
||||
@@ -29,13 +31,13 @@ public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
|
||||
// The amount of vertical spread between items in the stack [0...1]
|
||||
private static final float PERSPECTIVE_SHIFT_FACTOR = 0.18f;
|
||||
|
||||
//private int mIntrinsicIconSize;
|
||||
private float mBaselineIconScale;
|
||||
private int mBaselineIconSize;
|
||||
private int mAvailableSpaceInPreview;
|
||||
private float mMaxPerspectiveShift;
|
||||
|
||||
public void init(int availableSpace, int intrinsicIconSize) {
|
||||
@Override
|
||||
public void init(int availableSpace, int intrinsicIconSize, boolean rtl) {
|
||||
mAvailableSpaceInPreview = availableSpace;
|
||||
|
||||
// cos(45) = 0.707 + ~= 0.1) = 0.8f
|
||||
@@ -50,11 +52,11 @@ public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
|
||||
public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
|
||||
PreviewItemDrawingParams params) {
|
||||
|
||||
index = NUM_ITEMS_IN_PREVIEW - index - 1;
|
||||
float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1);
|
||||
index = MAX_NUM_ITEMS_IN_PREVIEW - index - 1;
|
||||
float r = (index * 1.0f) / (MAX_NUM_ITEMS_IN_PREVIEW - 1);
|
||||
float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r));
|
||||
|
||||
float offset = (1 - r) * mMaxPerspectiveShift;
|
||||
@@ -81,6 +83,11 @@ public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
|
||||
|
||||
@Override
|
||||
public int numItems() {
|
||||
return NUM_ITEMS_IN_PREVIEW;
|
||||
return MAX_NUM_ITEMS_IN_PREVIEW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getClipPath() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user