Merge "Deleting any ghost widget from system service:" into ub-launcher3-dorval
diff --git a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
index 7ad8e2c..2d78b69 100644
--- a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
+++ b/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
- <background android:color="#FFE0E0E0"/>
+ <background android:drawable="@color/legacy_icon_background"/>
<foreground>
<com.android.launcher3.graphics.FixedScaleDrawable />
</foreground>
diff --git a/res/layout/widgets_and_more.xml b/res/layout/widgets_bottom_sheet.xml
similarity index 94%
rename from res/layout/widgets_and_more.xml
rename to res/layout/widgets_bottom_sheet.xml
index 6764aa7..826235b 100644
--- a/res/layout/widgets_and_more.xml
+++ b/res/layout/widgets_bottom_sheet.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<com.android.launcher3.widget.WidgetsAndMore
+<com.android.launcher3.widget.WidgetsBottomSheet
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
@@ -51,4 +51,4 @@
android:layout_marginTop="45dp"
android:layout_marginBottom="40dp"/>
-</com.android.launcher3.widget.WidgetsAndMore>
\ No newline at end of file
+</com.android.launcher3.widget.WidgetsBottomSheet>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 3ce7baa..f148cf2 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -45,5 +45,6 @@
<!-- System shortcuts -->
<color name="system_shortcuts_icon_color">@android:color/tertiary_text_light</color>
+ <color name="legacy_icon_background">#FFFFFF</color>
<color name="icon_background">#E0E0E0</color> <!-- Gray 300 -->
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0b6100f..dd8c313 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -170,6 +170,7 @@
<dimen name="popup_arrow_horizontal_center">24dp</dimen>
<!-- popup_arrow_center - popup_arrow_width / 2-->
<dimen name="popup_arrow_horizontal_offset">19dp</dimen>
+ <dimen name="popup_arrow_corner_radius">2dp</dimen>
<!-- popup_item_width - icon_size - padding_start - drawable_padding -->
<dimen name="deep_shortcuts_divider_width">158dp</dimen>
<dimen name="system_shortcut_icon_size">24dp</dimen>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 1f12034..597e937 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -37,13 +37,13 @@
@IntDef(flag = true, value = {
TYPE_FOLDER,
TYPE_POPUP_CONTAINER_WITH_ARROW,
- TYPE_WIDGETS_AND_MORE
+ TYPE_WIDGETS_BOTTOM_SHEET
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
public static final int TYPE_FOLDER = 1 << 0;
public static final int TYPE_POPUP_CONTAINER_WITH_ARROW = 1 << 1;
- public static final int TYPE_WIDGETS_AND_MORE = 1 << 2;
+ public static final int TYPE_WIDGETS_BOTTOM_SHEET = 1 << 2;
protected boolean mIsOpen;
@@ -139,7 +139,7 @@
public static AbstractFloatingView getTopOpenView(Launcher launcher) {
return getOpenView(launcher, TYPE_FOLDER | TYPE_POPUP_CONTAINER_WITH_ARROW
- | TYPE_WIDGETS_AND_MORE);
+ | TYPE_WIDGETS_BOTTOM_SHEET);
}
public abstract int getLogContainerType();
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 924b79b..2a8397c 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -767,7 +767,7 @@
}
private static final class IconDB extends SQLiteCacheHelper {
- private final static int DB_VERSION = 11;
+ private final static int DB_VERSION = 12;
private final static int RELEASE_VERSION = DB_VERSION +
(FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index b04d5b7..14f4e6c 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -58,10 +58,9 @@
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.LoggerUtils;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.TouchController;
-import com.android.launcher3.widget.WidgetsAndMore;
+import com.android.launcher3.widget.WidgetsBottomSheet;
import java.util.ArrayList;
@@ -247,9 +246,9 @@
return true;
}
- WidgetsAndMore widgetsAndMore = WidgetsAndMore.getOpen(mLauncher);
- if (widgetsAndMore != null && widgetsAndMore.onControllerInterceptTouchEvent(ev)) {
- mActiveController = widgetsAndMore;
+ WidgetsBottomSheet widgetsBottomSheet = WidgetsBottomSheet.getOpen(mLauncher);
+ if (widgetsBottomSheet != null && widgetsBottomSheet.onControllerInterceptTouchEvent(ev)) {
+ mActiveController = widgetsBottomSheet;
return true;
}
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index 4b402f4..df0c47c 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -236,6 +236,10 @@
mLauncher.exitSpringLoadedDragModeDelayed(true,
Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
}
+
+ if (!success) {
+ d.deferDragViewCleanupPostAnimation = false;
+ }
postCleanup();
}
diff --git a/src/com/android/launcher3/graphics/FixedScaleDrawable.java b/src/com/android/launcher3/graphics/FixedScaleDrawable.java
index 4be4bd5..7ee3d80 100644
--- a/src/com/android/launcher3/graphics/FixedScaleDrawable.java
+++ b/src/com/android/launcher3/graphics/FixedScaleDrawable.java
@@ -19,15 +19,17 @@
// TODO b/33553066 use the constant defined in MaskableIconDrawable
private static final float LEGACY_ICON_SCALE = .7f * .6667f;
+ private float mScale;
public FixedScaleDrawable() {
super(new ColorDrawable());
+ mScale = LEGACY_ICON_SCALE;
}
@Override
public void draw(Canvas canvas) {
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- canvas.scale(LEGACY_ICON_SCALE, LEGACY_ICON_SCALE,
+ canvas.scale(mScale, mScale,
getBounds().exactCenterX(), getBounds().exactCenterY());
super.draw(canvas);
canvas.restoreToCount(saveCount);
@@ -38,4 +40,8 @@
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { }
+
+ public void setScale(float scale) {
+ mScale = scale * LEGACY_ICON_SCALE;
+ }
}
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 70b3dd6..34d0b72 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -20,15 +20,31 @@
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.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
+import java.io.File;
+import java.io.FileOutputStream;
import java.nio.ByteBuffer;
+import java.util.Random;
public class IconNormalizer {
+ private static final String TAG = "IconNormalizer";
+ private static final boolean DEBUG = false;
// Ratio of icon visible area to full icon size for a square shaped icon
private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576;
// Ratio of icon visible area to full icon size for a circular shaped icon
@@ -42,17 +58,38 @@
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;
+
private static final Object LOCK = new Object();
private static IconNormalizer sIconNormalizer;
private final int mMaxSize;
private final Bitmap mBitmap;
+ private final Bitmap mBitmapARGB;
private final Canvas mCanvas;
+ private final Paint mPaintMaskShape;
+ private final Paint mPaintMaskShapeOutline;
private final byte[] mPixels;
+ private final int[] mPixelsARGB;
+
+ private final Rect mAdaptiveIconBounds;
+ private float mAdaptiveIconScale;
// 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 Matrix mMatrix;
+
+ private Paint mPaintIcon;
+ private Canvas mCanvasARGB;
+
+ private File mDir;
+ private int mFileId;
+ private Random mRandom;
private IconNormalizer(Context context) {
// Use twice the icon size as maximum size to avoid scaling down twice.
@@ -60,9 +97,122 @@
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
mCanvas = new Canvas(mBitmap);
mPixels = new byte[mMaxSize * mMaxSize];
-
+ mPixelsARGB = new int[mMaxSize * mMaxSize];
mLeftBorder = new float[mMaxSize];
mRightBorder = new float[mMaxSize];
+ mBounds = new Rect();
+ mAdaptiveIconBounds = new Rect();
+
+ // Needed for isShape() method
+ mBitmapARGB = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ARGB_8888);
+ mCanvasARGB = new Canvas(mBitmapARGB);
+
+ mPaintIcon = new Paint();
+ mPaintIcon.setColor(Color.WHITE);
+
+ 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.DST_OUT));
+
+ mMatrix = new Matrix();
+ int[] mPixels = new int[mMaxSize * mMaxSize];
+ mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
+
+ mDir = context.getExternalFilesDir(null);
+ mRandom = new Random();
+ }
+
+ /**
+ * 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.
+ mFileId = mRandom.nextInt();
+ mBitmapARGB.eraseColor(Color.TRANSPARENT);
+ mCanvasARGB.drawBitmap(mBitmap, 0, 0, mPaintIcon);
+
+ if (DEBUG) {
+ final File beforeFile = new File(mDir, "isShape" + mFileId + "_before.png");
+ try {
+ mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(beforeFile));
+ } catch (Exception e) {}
+ }
+
+ // 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);
+
+ // XOR operation
+ mCanvasARGB.drawPath(maskPath, mPaintMaskShape);
+
+ // DST_OUT operation around the mask path outline
+ mCanvasARGB.drawPath(maskPath, mPaintMaskShapeOutline);
+
+ boolean isTrans = isTransparentBitmap(mBitmapARGB);
+ if (DEBUG) {
+ final File afterFile = new File(mDir, "isShape" + mFileId + "_after_" + isTrans + ".png");
+ try {
+ mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(afterFile));
+ } catch (Exception e) {}
+ }
+
+ // Check if the result is almost transparent
+ if (!isTrans) {
+ if (DEBUG) {
+ Log.d(TAG, "Not same as mask shape");
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Used to determine if certain the bitmap is transparent.
+ */
+ private boolean isTransparentBitmap(Bitmap bitmap) {
+ int w = mBounds.width();
+ int h = mBounds.height();
+ bitmap.getPixels(mPixelsARGB, 0 /* the first index to write into the array */,
+ w /* stride */,
+ mBounds.left, mBounds.top,
+ w, h);
+ int sum = 0;
+ for (int i = 0; i < w * h; i++) {
+ if(Color.alpha(mPixelsARGB[i]) > MIN_VISIBLE_ALPHA) {
+ sum++;
+ }
+ }
+ float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
+ boolean transparentImage = percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
+ if (DEBUG) {
+ Log.d(TAG, "Total # pixel that is different (id="+ mFileId + "):" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height());
+ }
+ return transparentImage;
}
/**
@@ -79,7 +229,15 @@
*
* @param outBounds optional rect to receive the fraction distance from each edge.
*/
- public synchronized float getScale(Drawable d, RectF outBounds) {
+ public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
+ @Nullable Path path, @Nullable boolean[] outMaskShape) {
+ if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
+ mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
+ if (outBounds != null) {
+ outBounds.set(mAdaptiveIconBounds);
+ }
+ return mAdaptiveIconScale;
+ }
int width = d.getIntrinsicWidth();
int height = d.getIntrinsicHeight();
if (width <= 0 || height <= 0) {
@@ -169,20 +327,31 @@
if (hullByRect < CIRCLE_AREA_BY_RECT) {
scaleRequired = MAX_CIRCLE_AREA_FACTOR;
} else {
- scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
+ scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
}
+ mBounds.left = leftX;
+ mBounds.right = rightX;
+
+ mBounds.top = topY;
+ mBounds.bottom = bottomY;
if (outBounds != null) {
- outBounds.left = ((float) leftX) / width;
- outBounds.right = 1 - ((float) rightX) / width;
-
- outBounds.top = ((float) topY) / height;
- outBounds.bottom = 1 - ((float) bottomY) / height;
+ outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top),
+ 1 - ((float) mBounds.right) / width,
+ 1 - ((float) mBounds.bottom) / height);
}
+ if (outMaskShape != null && outMaskShape.length > 0) {
+ outMaskShape[0] = isShape(path);
+ }
float areaScale = area / (width * height);
// Use sqrt of the final ratio as the images is scaled across both width and height.
float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
+ if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
+ mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
+ mAdaptiveIconScale = scale;
+ mAdaptiveIconBounds.set(mBounds);
+ }
return scale;
}
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 2d987cc..f652a5c 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -95,8 +95,29 @@
*/
public static Bitmap createBadgedIconBitmap(
Drawable icon, UserHandle user, Context context) {
- float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance(context).getScale(icon, null);
+
+ IconNormalizer normalizer;
+ float scale = 1f;
+ if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
+ normalizer = IconNormalizer.getInstance(context);
+ if (Utilities.isAtLeastO()) {
+ boolean[] outShape = new boolean[1];
+ AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
+ context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+ dr.setBounds(0, 0, 1, 1);
+ scale = normalizer.getScale(icon, null, dr.getIconMask(), outShape);
+ if (FeatureFlags.LEGACY_ICON_TREATMENT &&
+ !outShape[0]){
+ Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
+ if (wrappedIcon != icon) {
+ icon = wrappedIcon;
+ scale = normalizer.getScale(icon, null, null, null);
+ }
+ }
+ } else {
+ scale = normalizer.getScale(icon, null, null, null);
+ }
+ }
Bitmap bitmap = createIconBitmap(icon, context, scale);
if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
icon instanceof AdaptiveIconDrawable) {
@@ -129,8 +150,29 @@
*/
public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
RectF iconBounds = new RectF();
- float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance(context).getScale(icon, iconBounds);
+ IconNormalizer normalizer;
+ float scale = 1f;
+ if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
+ normalizer = IconNormalizer.getInstance(context);
+ if (Utilities.isAtLeastO()) {
+ boolean[] outShape = new boolean[1];
+ AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
+ context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+ dr.setBounds(0, 0, 1, 1);
+ scale = normalizer.getScale(icon, iconBounds, dr.getIconMask(), outShape);
+ if (Utilities.isAtLeastO() && FeatureFlags.LEGACY_ICON_TREATMENT &&
+ !outShape[0]) {
+ Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
+ if (wrappedIcon != icon) {
+ icon = wrappedIcon;
+ scale = normalizer.getScale(icon, iconBounds, null, null);
+ }
+ }
+ } else {
+ scale = normalizer.getScale(icon, iconBounds, null, null);
+ }
+
+ }
scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
return createIconBitmap(icon, context, scale);
}
@@ -180,10 +222,8 @@
* @param scale the scale to apply before drawing {@param icon} on the canvas
*/
public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
- icon = wrapToAdaptiveIconDrawable(context, icon);
synchronized (sCanvas) {
final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
-
int width = iconBitmapSize;
int height = iconBitmapSize;
@@ -242,7 +282,7 @@
* shrink the legacy icon and set it as foreground. Use color drawable as background to
* create AdaptiveIconDrawable.
*/
- static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable) {
+ static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable, float scale) {
if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.isAtLeastO())) {
return drawable;
}
@@ -252,8 +292,10 @@
if (!clazz.isAssignableFrom(drawable.getClass())) {
Drawable iconWrapper =
context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
- ((FixedScaleDrawable) clazz.getMethod("getForeground").invoke(iconWrapper))
- .setDrawable(drawable);
+ FixedScaleDrawable fsd = ((FixedScaleDrawable) clazz.getMethod("getForeground")
+ .invoke(iconWrapper));
+ fsd.setDrawable(drawable);
+ fsd.setScale(scale);
return iconWrapper;
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index d2512de..5891085 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -26,6 +26,8 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
@@ -486,7 +488,11 @@
} else {
ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
width, height, !mIsAboveIcon));
- arrowDrawable.getPaint().setColor(Color.WHITE);
+ Paint arrowPaint = arrowDrawable.getPaint();
+ arrowPaint.setColor(Color.WHITE);
+ // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
+ int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
+ arrowPaint.setPathEffect(new CornerPathEffect(radius));
arrowView.setBackground(arrowDrawable);
arrowView.setElevation(getElevation());
}
diff --git a/src/com/android/launcher3/popup/PopupItemView.java b/src/com/android/launcher3/popup/PopupItemView.java
index 0853c13..a18f650 100644
--- a/src/com/android/launcher3/popup/PopupItemView.java
+++ b/src/com/android/launcher3/popup/PopupItemView.java
@@ -120,8 +120,9 @@
*/
public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) {
Point center = getIconCenter();
+ int arrowCenter = getResources().getDimensionPixelSize(R.dimen.popup_arrow_horizontal_center);
ValueAnimator openAnimator = new ZoomRevealOutlineProvider(center.x, center.y,
- mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft)
+ mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft, arrowCenter)
.createRevealAnimator(this, false);
mOpenAnimationProgress = 0f;
openAnimator.addUpdateListener(this);
@@ -143,8 +144,9 @@
public Animator createCloseAnimation(boolean isContainerAboveIcon, boolean pivotLeft,
long duration) {
Point center = getIconCenter();
+ int arrowCenter = getResources().getDimensionPixelSize(R.dimen.popup_arrow_horizontal_center);
ValueAnimator closeAnimator = new ZoomRevealOutlineProvider(center.x, center.y,
- mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft)
+ mPillRect, this, mIconView, isContainerAboveIcon, pivotLeft, arrowCenter)
.createRevealAnimator(this, true);
// Scale down the duration and interpolator according to the progress
// that the open animation was at when the close started.
@@ -188,9 +190,10 @@
private final boolean mPivotLeft;
private final float mTranslateX;
+ private final float mArrowCenter;
public ZoomRevealOutlineProvider(int x, int y, Rect pillRect, PopupItemView translateView,
- View zoomView, boolean isContainerAboveIcon, boolean pivotLeft) {
+ View zoomView, boolean isContainerAboveIcon, boolean pivotLeft, float arrowCenter) {
super(x, y, pillRect, translateView.getBackgroundRadius());
mTranslateView = translateView;
mZoomView = zoomView;
@@ -199,7 +202,8 @@
mTranslateYMultiplier = isContainerAboveIcon ? 0.5f : -0.5f;
mPivotLeft = pivotLeft;
- mTranslateX = pivotLeft ? pillRect.height() / 2 : pillRect.right - pillRect.height() / 2;
+ mTranslateX = pivotLeft ? arrowCenter : pillRect.right - arrowCenter;
+ mArrowCenter = arrowCenter;
}
@Override
@@ -214,7 +218,8 @@
float height = mOutline.height();
mTranslateView.setTranslationY(mTranslateYMultiplier * (mFullHeight - height));
- float pivotX = mPivotLeft ? (mOutline.left + height / 2) : (mOutline.right - height / 2);
+ float offsetX = Math.min(mOutline.width(), mArrowCenter);
+ float pivotX = mPivotLeft ? (mOutline.left + offsetX) : (mOutline.right - offsetX);
mTranslateView.setTranslationX(mTranslateX - pivotX);
}
}
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index fa70de9..de88499 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -11,7 +11,7 @@
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.widget.WidgetsAndMore;
+import com.android.launcher3.widget.WidgetsBottomSheet;
import java.util.List;
@@ -62,10 +62,10 @@
@Override
public void onClick(View view) {
PopupContainerWithArrow.getOpen(launcher).close(true);
- WidgetsAndMore widgetsAndMore =
- (WidgetsAndMore) launcher.getLayoutInflater().inflate(
- R.layout.widgets_and_more, launcher.getDragLayer(), false);
- widgetsAndMore.populateAndShow(itemInfo);
+ WidgetsBottomSheet widgetsBottomSheet =
+ (WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
+ R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
+ widgetsBottomSheet.populateAndShow(itemInfo);
}
};
}
diff --git a/src/com/android/launcher3/widget/WidgetsAndMore.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
similarity index 93%
rename from src/com/android/launcher3/widget/WidgetsAndMore.java
rename to src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 401337b..a423154 100644
--- a/src/com/android/launcher3/widget/WidgetsAndMore.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -53,9 +53,9 @@
import java.util.List;
/**
- * Bottom sheet for the "Widgets & more" long-press option.
+ * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
*/
-public class WidgetsAndMore extends AbstractFloatingView implements Insettable, TouchController,
+public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable, TouchController,
VerticalPullDetector.Listener, View.OnClickListener, View.OnLongClickListener,
DragController.DragListener {
@@ -72,11 +72,11 @@
private boolean mWasNavBarLight;
private VerticalPullDetector mVerticalPullDetector;
- public WidgetsAndMore(Context context, AttributeSet attrs) {
+ public WidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public WidgetsAndMore(Context context, AttributeSet attrs, int defStyleAttr) {
+ public WidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme), attrs, defStyleAttr);
setWillNotDraw(false);
mLauncher = Launcher.getLauncher(context);
@@ -134,7 +134,8 @@
}
// If there is only one widget, we want to center it instead of left-align.
- WidgetsAndMore.LayoutParams params = (WidgetsAndMore.LayoutParams) widgetRow.getLayoutParams();
+ WidgetsBottomSheet.LayoutParams params = (WidgetsBottomSheet.LayoutParams)
+ widgetRow.getLayoutParams();
params.gravity = widgets.size() == 1 ? Gravity.CENTER_HORIZONTAL : Gravity.START;
}
@@ -200,7 +201,7 @@
public void onAnimationEnd(Animator animation) {
mIsOpen = false;
mVerticalPullDetector.finishedScrolling();
- ((ViewGroup) getParent()).removeView(WidgetsAndMore.this);
+ ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this);
setLightNavBar(mWasNavBarLight);
}
});
@@ -220,7 +221,7 @@
@Override
protected boolean isOfType(@FloatingViewType int type) {
- return (type & TYPE_WIDGETS_AND_MORE) != 0;
+ return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0;
}
@Override
@@ -229,10 +230,10 @@
}
/**
- * Returns a WidgetsAndMore which is already open or null
+ * Returns a {@link WidgetsBottomSheet} which is already open or null
*/
- public static WidgetsAndMore getOpen(Launcher launcher) {
- return getOpenView(launcher, TYPE_WIDGETS_AND_MORE);
+ public static WidgetsBottomSheet getOpen(Launcher launcher) {
+ return getOpenView(launcher, TYPE_WIDGETS_BOTTOM_SHEET);
}
@Override
diff --git a/src_config/com/android/launcher3/config/FeatureFlags.java b/src_config/com/android/launcher3/config/FeatureFlags.java
index 80eebec..4e337a2 100644
--- a/src_config/com/android/launcher3/config/FeatureFlags.java
+++ b/src_config/com/android/launcher3/config/FeatureFlags.java
@@ -45,8 +45,8 @@
public static final boolean LIGHT_STATUS_BAR = false;
// When enabled icons are badged with the number of notifications associated with that app.
public static final boolean BADGE_ICONS = true;
- // When enabled, icons not supporting {@link MaskableIconDrawable} will be wrapped in this class.
- public static final boolean LEGACY_ICON_TREATMENT = false;
+ // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in this class.
+ public static final boolean LEGACY_ICON_TREATMENT = true;
// When enabled, adaptive icons would have shadows baked when being stored to icon cache.
public static final boolean ADAPTIVE_ICON_SHADOW = true;
// When enabled, app discovery will be enabled if service is implemented