Loading go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ public abstract class GoActivityControlHelper<T extends BaseDraggingActivity> im } @Override public void onSwipeUpComplete(T activity) { public void onSwipeUpToRecentsComplete(T activity) { // Go does not support swipe up gesture. } Loading iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +14 −7 Original line number Diff line number Diff line Loading @@ -46,13 +46,15 @@ public class BaseIconFactory implements AutoCloseable { private IconNormalizer mNormalizer; private ShadowGenerator mShadowGenerator; private final boolean mShapeDetection; private Drawable mWrapperIcon; private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND; protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) { protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize, boolean shapeDetection) { mContext = context.getApplicationContext(); mShapeDetection = shapeDetection; mFillResIconDpi = fillResIconDpi; mIconBitmapSize = iconBitmapSize; Loading @@ -64,6 +66,10 @@ public class BaseIconFactory implements AutoCloseable { clear(); } protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) { this(context, fillResIconDpi, iconBitmapSize, false); } protected void clear() { mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND; mDisableColorExtractor = false; Loading @@ -78,7 +84,7 @@ public class BaseIconFactory implements AutoCloseable { public IconNormalizer getNormalizer() { if (mNormalizer == null) { mNormalizer = new IconNormalizer(mIconBitmapSize); mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection); } return mNormalizer; } Loading Loading @@ -209,18 +215,19 @@ public class BaseIconFactory implements AutoCloseable { } AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon; dr.setBounds(0, 0, 1, 1); scale = getNormalizer().getScale(icon, outIconBounds); if (!(icon instanceof AdaptiveIconDrawable)) { boolean[] outShape = new boolean[1]; scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape); if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) { FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground()); fsd.setDrawable(icon); fsd.setScale(scale); icon = dr; scale = getNormalizer().getScale(icon, outIconBounds); scale = getNormalizer().getScale(icon, outIconBounds, null, null); ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor); } } else { scale = getNormalizer().getScale(icon, outIconBounds); scale = getNormalizer().getScale(icon, outIconBounds, null, null); } outScale[0] = scale; Loading iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java +102 −3 Original line number Diff line number Diff line Loading @@ -18,16 +18,22 @@ package com.android.launcher3.icons; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.Log; import java.nio.ByteBuffer; Loading @@ -51,6 +57,9 @@ public class IconNormalizer { private static final int MIN_VISIBLE_ALPHA = 40; // Shape detection related constants private static final float BOUND_RATIO_MARGIN = .05f; private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f; private static final float SCALE_NOT_INITIALIZED = 0; // Ratio of the diameter of an normalized circular icon to the actual icon size. Loading @@ -59,18 +68,24 @@ public class IconNormalizer { private final int mMaxSize; private final Bitmap mBitmap; private final Canvas mCanvas; private final Paint mPaintMaskShape; private final Paint mPaintMaskShapeOutline; private final byte[] mPixels; private final RectF mAdaptiveIconBounds; private float mAdaptiveIconScale; private boolean mEnableShapeDetection; // for each y, stores the position of the leftmost x and the rightmost x private final float[] mLeftBorder; private final float[] mRightBorder; private final Rect mBounds; private final Path mShapePath; private final Matrix mMatrix; /** package private **/ IconNormalizer(int iconBitmapSize) { IconNormalizer(Context context, int iconBitmapSize, boolean shapeDetection) { // Use twice the icon size as maximum size to avoid scaling down twice. mMaxSize = iconBitmapSize * 2; mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8); Loading @@ -81,7 +96,22 @@ public class IconNormalizer { mBounds = new Rect(); mAdaptiveIconBounds = new RectF(); mPaintMaskShape = new Paint(); mPaintMaskShape.setColor(Color.RED); mPaintMaskShape.setStyle(Paint.Style.FILL); mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); mPaintMaskShapeOutline = new Paint(); mPaintMaskShapeOutline.setStrokeWidth( 2 * context.getResources().getDisplayMetrics().density); mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE); mPaintMaskShapeOutline.setColor(Color.BLACK); mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); mShapePath = new Path(); mMatrix = new Matrix(); mAdaptiveIconScale = SCALE_NOT_INITIALIZED; mEnableShapeDetection = shapeDetection; } private static float getScale(float hullArea, float boundingArea, float fullArea) { Loading Loading @@ -126,6 +156,72 @@ public class IconNormalizer { return getScale(hullArea, hullArea, size * size); } /** * Returns if the shape of the icon is same as the path. * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds. */ private boolean isShape(Path maskPath) { // Condition1: // If width and height of the path not close to a square, then the icon shape is // not same as the mask shape. float iconRatio = ((float) mBounds.width()) / mBounds.height(); if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) { if (DEBUG) { Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio); } return false; } // Condition 2: // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation // should generate transparent image, if the actual icon is equivalent to the shape. // Fit the shape within the icon's bounding box mMatrix.reset(); mMatrix.setScale(mBounds.width(), mBounds.height()); mMatrix.postTranslate(mBounds.left, mBounds.top); maskPath.transform(mMatrix, mShapePath); // XOR operation mCanvas.drawPath(mShapePath, mPaintMaskShape); // DST_OUT operation around the mask path outline mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline); // Check if the result is almost transparent return isTransparentBitmap(); } /** * Used to determine if certain the bitmap is transparent. */ private boolean isTransparentBitmap() { ByteBuffer buffer = ByteBuffer.wrap(mPixels); buffer.rewind(); mBitmap.copyPixelsToBuffer(buffer); int y = mBounds.top; // buffer position int index = y * mMaxSize; // buffer shift after every row, width of buffer = mMaxSize int rowSizeDiff = mMaxSize - mBounds.right; int sum = 0; for (; y < mBounds.bottom; y++) { index += mBounds.left; for (int x = mBounds.left; x < mBounds.right; x++) { if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) { sum++; } index++; } index += rowSizeDiff; } float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height()); return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD; } /** * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it * matches the design guidelines for a launcher icon. Loading @@ -140,7 +236,8 @@ public class IconNormalizer { * * @param outBounds optional rect to receive the fraction distance from each edge. */ public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds) { public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds, @Nullable Path path, @Nullable boolean[] outMaskShape) { if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) { if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) { mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds); Loading Loading @@ -242,7 +339,9 @@ public class IconNormalizer { 1 - ((float) mBounds.right) / width, 1 - ((float) mBounds.bottom) / height); } if (outMaskShape != null && mEnableShapeDetection && outMaskShape.length > 0) { outMaskShape[0] = isShape(path); } // Area of the rectangle required to fit the convex hull float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX); return getScale(area, rectArea, width * height); Loading quickstep/recents_ui_overrides/res/values/dimens.xml +1 −1 Original line number Diff line number Diff line Loading @@ -27,5 +27,5 @@ <!-- Swipe up to home related --> <dimen name="swipe_up_fling_min_visible_change">18dp</dimen> <dimen name="swipe_up_y_overshoot">10dp</dimen> <dimen name="swipe_up_max_workspace_trans_y">-80dp</dimen> <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen> </resources> No newline at end of file quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +6 −16 Original line number Diff line number Diff line Loading @@ -164,13 +164,6 @@ public class PredictionRowView extends LinearLayout implements mParent = parent; } private void setPredictionsEnabled(boolean predictionsEnabled) { if (predictionsEnabled != mPredictionsEnabled) { mPredictionsEnabled = predictionsEnabled; updateVisibility(); } } private void updateVisibility() { setVisibility(mPredictionsEnabled ? VISIBLE : GONE); } Loading Loading @@ -220,8 +213,7 @@ public class PredictionRowView extends LinearLayout implements * If the number of predicted apps is the same as the previous list of predicted apps, * we can optimize by swapping them in place. */ public void setPredictedApps(boolean predictionsEnabled, List<ComponentKeyMapper> apps) { setPredictionsEnabled(predictionsEnabled); public void setPredictedApps(List<ComponentKeyMapper> apps) { mPredictedAppComponents.clear(); mPredictedAppComponents.addAll(apps); Loading @@ -237,11 +229,6 @@ public class PredictionRowView extends LinearLayout implements } private void applyPredictionApps() { if (!mPredictionsEnabled) { mParent.onHeightUpdated(); return; } if (getChildCount() != mNumPredictedAppsPerRow) { while (getChildCount() > mNumPredictedAppsPerRow) { removeViewAt(0); Loading Loading @@ -282,8 +269,11 @@ public class PredictionRowView extends LinearLayout implements } } if (predictionCount == 0) { setPredictionsEnabled(false); boolean predictionsEnabled = predictionCount > 0; if (predictionsEnabled != mPredictionsEnabled) { mPredictionsEnabled = predictionsEnabled; mLauncher.reapplyUi(); updateVisibility(); } mParent.onHeightUpdated(); } Loading Loading
go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ public abstract class GoActivityControlHelper<T extends BaseDraggingActivity> im } @Override public void onSwipeUpComplete(T activity) { public void onSwipeUpToRecentsComplete(T activity) { // Go does not support swipe up gesture. } Loading
iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +14 −7 Original line number Diff line number Diff line Loading @@ -46,13 +46,15 @@ public class BaseIconFactory implements AutoCloseable { private IconNormalizer mNormalizer; private ShadowGenerator mShadowGenerator; private final boolean mShapeDetection; private Drawable mWrapperIcon; private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND; protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) { protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize, boolean shapeDetection) { mContext = context.getApplicationContext(); mShapeDetection = shapeDetection; mFillResIconDpi = fillResIconDpi; mIconBitmapSize = iconBitmapSize; Loading @@ -64,6 +66,10 @@ public class BaseIconFactory implements AutoCloseable { clear(); } protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) { this(context, fillResIconDpi, iconBitmapSize, false); } protected void clear() { mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND; mDisableColorExtractor = false; Loading @@ -78,7 +84,7 @@ public class BaseIconFactory implements AutoCloseable { public IconNormalizer getNormalizer() { if (mNormalizer == null) { mNormalizer = new IconNormalizer(mIconBitmapSize); mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection); } return mNormalizer; } Loading Loading @@ -209,18 +215,19 @@ public class BaseIconFactory implements AutoCloseable { } AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon; dr.setBounds(0, 0, 1, 1); scale = getNormalizer().getScale(icon, outIconBounds); if (!(icon instanceof AdaptiveIconDrawable)) { boolean[] outShape = new boolean[1]; scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape); if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) { FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground()); fsd.setDrawable(icon); fsd.setScale(scale); icon = dr; scale = getNormalizer().getScale(icon, outIconBounds); scale = getNormalizer().getScale(icon, outIconBounds, null, null); ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor); } } else { scale = getNormalizer().getScale(icon, outIconBounds); scale = getNormalizer().getScale(icon, outIconBounds, null, null); } outScale[0] = scale; Loading
iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java +102 −3 Original line number Diff line number Diff line Loading @@ -18,16 +18,22 @@ package com.android.launcher3.icons; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.Log; import java.nio.ByteBuffer; Loading @@ -51,6 +57,9 @@ public class IconNormalizer { private static final int MIN_VISIBLE_ALPHA = 40; // Shape detection related constants private static final float BOUND_RATIO_MARGIN = .05f; private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f; private static final float SCALE_NOT_INITIALIZED = 0; // Ratio of the diameter of an normalized circular icon to the actual icon size. Loading @@ -59,18 +68,24 @@ public class IconNormalizer { private final int mMaxSize; private final Bitmap mBitmap; private final Canvas mCanvas; private final Paint mPaintMaskShape; private final Paint mPaintMaskShapeOutline; private final byte[] mPixels; private final RectF mAdaptiveIconBounds; private float mAdaptiveIconScale; private boolean mEnableShapeDetection; // for each y, stores the position of the leftmost x and the rightmost x private final float[] mLeftBorder; private final float[] mRightBorder; private final Rect mBounds; private final Path mShapePath; private final Matrix mMatrix; /** package private **/ IconNormalizer(int iconBitmapSize) { IconNormalizer(Context context, int iconBitmapSize, boolean shapeDetection) { // Use twice the icon size as maximum size to avoid scaling down twice. mMaxSize = iconBitmapSize * 2; mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8); Loading @@ -81,7 +96,22 @@ public class IconNormalizer { mBounds = new Rect(); mAdaptiveIconBounds = new RectF(); mPaintMaskShape = new Paint(); mPaintMaskShape.setColor(Color.RED); mPaintMaskShape.setStyle(Paint.Style.FILL); mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); mPaintMaskShapeOutline = new Paint(); mPaintMaskShapeOutline.setStrokeWidth( 2 * context.getResources().getDisplayMetrics().density); mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE); mPaintMaskShapeOutline.setColor(Color.BLACK); mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); mShapePath = new Path(); mMatrix = new Matrix(); mAdaptiveIconScale = SCALE_NOT_INITIALIZED; mEnableShapeDetection = shapeDetection; } private static float getScale(float hullArea, float boundingArea, float fullArea) { Loading Loading @@ -126,6 +156,72 @@ public class IconNormalizer { return getScale(hullArea, hullArea, size * size); } /** * Returns if the shape of the icon is same as the path. * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds. */ private boolean isShape(Path maskPath) { // Condition1: // If width and height of the path not close to a square, then the icon shape is // not same as the mask shape. float iconRatio = ((float) mBounds.width()) / mBounds.height(); if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) { if (DEBUG) { Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio); } return false; } // Condition 2: // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation // should generate transparent image, if the actual icon is equivalent to the shape. // Fit the shape within the icon's bounding box mMatrix.reset(); mMatrix.setScale(mBounds.width(), mBounds.height()); mMatrix.postTranslate(mBounds.left, mBounds.top); maskPath.transform(mMatrix, mShapePath); // XOR operation mCanvas.drawPath(mShapePath, mPaintMaskShape); // DST_OUT operation around the mask path outline mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline); // Check if the result is almost transparent return isTransparentBitmap(); } /** * Used to determine if certain the bitmap is transparent. */ private boolean isTransparentBitmap() { ByteBuffer buffer = ByteBuffer.wrap(mPixels); buffer.rewind(); mBitmap.copyPixelsToBuffer(buffer); int y = mBounds.top; // buffer position int index = y * mMaxSize; // buffer shift after every row, width of buffer = mMaxSize int rowSizeDiff = mMaxSize - mBounds.right; int sum = 0; for (; y < mBounds.bottom; y++) { index += mBounds.left; for (int x = mBounds.left; x < mBounds.right; x++) { if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) { sum++; } index++; } index += rowSizeDiff; } float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height()); return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD; } /** * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it * matches the design guidelines for a launcher icon. Loading @@ -140,7 +236,8 @@ public class IconNormalizer { * * @param outBounds optional rect to receive the fraction distance from each edge. */ public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds) { public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds, @Nullable Path path, @Nullable boolean[] outMaskShape) { if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) { if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) { mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds); Loading Loading @@ -242,7 +339,9 @@ public class IconNormalizer { 1 - ((float) mBounds.right) / width, 1 - ((float) mBounds.bottom) / height); } if (outMaskShape != null && mEnableShapeDetection && outMaskShape.length > 0) { outMaskShape[0] = isShape(path); } // Area of the rectangle required to fit the convex hull float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX); return getScale(area, rectArea, width * height); Loading
quickstep/recents_ui_overrides/res/values/dimens.xml +1 −1 Original line number Diff line number Diff line Loading @@ -27,5 +27,5 @@ <!-- Swipe up to home related --> <dimen name="swipe_up_fling_min_visible_change">18dp</dimen> <dimen name="swipe_up_y_overshoot">10dp</dimen> <dimen name="swipe_up_max_workspace_trans_y">-80dp</dimen> <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen> </resources> No newline at end of file
quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +6 −16 Original line number Diff line number Diff line Loading @@ -164,13 +164,6 @@ public class PredictionRowView extends LinearLayout implements mParent = parent; } private void setPredictionsEnabled(boolean predictionsEnabled) { if (predictionsEnabled != mPredictionsEnabled) { mPredictionsEnabled = predictionsEnabled; updateVisibility(); } } private void updateVisibility() { setVisibility(mPredictionsEnabled ? VISIBLE : GONE); } Loading Loading @@ -220,8 +213,7 @@ public class PredictionRowView extends LinearLayout implements * If the number of predicted apps is the same as the previous list of predicted apps, * we can optimize by swapping them in place. */ public void setPredictedApps(boolean predictionsEnabled, List<ComponentKeyMapper> apps) { setPredictionsEnabled(predictionsEnabled); public void setPredictedApps(List<ComponentKeyMapper> apps) { mPredictedAppComponents.clear(); mPredictedAppComponents.addAll(apps); Loading @@ -237,11 +229,6 @@ public class PredictionRowView extends LinearLayout implements } private void applyPredictionApps() { if (!mPredictionsEnabled) { mParent.onHeightUpdated(); return; } if (getChildCount() != mNumPredictedAppsPerRow) { while (getChildCount() > mNumPredictedAppsPerRow) { removeViewAt(0); Loading Loading @@ -282,8 +269,11 @@ public class PredictionRowView extends LinearLayout implements } } if (predictionCount == 0) { setPredictionsEnabled(false); boolean predictionsEnabled = predictionCount > 0; if (predictionsEnabled != mPredictionsEnabled) { mPredictionsEnabled = predictionsEnabled; mLauncher.reapplyUi(); updateVisibility(); } mParent.onHeightUpdated(); } Loading