Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3ed49d5 authored by Winson Chung's avatar Winson Chung
Browse files

Merging ub-launcher3-qt-dev, build 5633311

Test: Manual

Bug:119330044 P1 [STOPSHIP] Add back shape detection in Launcher icons
Bug:123900446 P1 App to home animation should zoom into the app icon
Bug:132298752 P1 Adding widget locks home screen page
Bug:132757019 P1 Swipe up twice quickly from app in 2 button mode; can't access all apps
Bug:133518678 P1 In 2 button mode, flinging up strongly favours quickswitch
Bug:133806285 P1 All apps causes overview to peek in
Bug:133844237 P1 Respect limited width Exclusion Rects in bottom area?
Bug:133867119 P2 Lab-only flake: want to switch from workspace to all apps; Swipe failed to receive an event for the swipe end
Bug:134062513 P1 Quickswitch sends lifecycle events to -1
Bug:134094839 P1 Launcher kept crashing on OTA update
Bug:134096917 P1 Launcher animation component gets stuck during swipe up
Bug:134164918 P1 STOPSHIP: Disable chips hard-coded value in qt_dev Launcher
Bug:134172603 P1 Tracing for lab-only flakes
Bug:134442147 P1 Sometimes All Apps won't update on app install/uninstall/update
Change-Id: Ia530fbf9bb5fa67b602ce44aef0cc4a1d1494e13
parents 0ef6fe00 8789aa05
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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.
    }

+14 −7
Original line number Diff line number Diff line
@@ -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;

@@ -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;
@@ -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;
    }
@@ -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;
+102 −3
Original line number Diff line number Diff line
@@ -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;

@@ -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.
@@ -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);
@@ -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) {
@@ -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.
@@ -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);
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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
+6 −16
Original line number Diff line number Diff line
@@ -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);
    }
@@ -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);

@@ -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);
@@ -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