Files
Lawnchair/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
T
Ana Salazar Maldonado 4ff68edea9 Fix contrast tile measurement calculation for folders
When creating a folder, the element name begins empty. Because of this,
while layout is happening, the paddings for the text and the bubble are
not considered. Fix the condition within onMeasure to add the respective
paddings when the bubble could be drawn.

Bug: 341217082
Flag: com.android.launcher3.enable_contrast_tiles
Test: Manual, visual change
Change-Id: Ie707102fa3d4827568a9db247ea5ebf5f8e1ae0d
2025-02-12 14:31:01 -08:00

168 lines
6.2 KiB
Java

/*
* Copyright (C) 2017 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.
*/
package com.android.launcher3.views;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
/**
* Extension of {@link BubbleTextView} which draws two shadows on the text (ambient and key shadows}
*/
public class DoubleShadowBubbleTextView extends BubbleTextView {
private final ShadowInfo mShadowInfo;
public DoubleShadowBubbleTextView(Context context) {
this(context, null);
}
public DoubleShadowBubbleTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mShadowInfo = ShadowInfo.Companion.fromContext(context, attrs, defStyle);
setShadowLayer(
mShadowInfo.getAmbientShadowBlur(),
0,
0,
mShadowInfo.getAmbientShadowColor()
);
}
@Override
public void setTextWithStartIcon(CharSequence text, @DrawableRes int drawableId) {
Drawable drawable = getContext().getDrawable(drawableId);
if (drawable == null) {
setText(text);
Log.w(TAG, "setTextWithStartIcon: start icon Drawable not found from resources"
+ ", will just set text instead.");
return;
}
drawable.setTint(getCurrentTextColor());
int textSize = Math.round(getTextSize());
ImageSpan imageSpan;
if (!skipDoubleShadow() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
drawable = getDoubleShadowDrawable(drawable, textSize);
}
drawable.setBounds(0, 0, textSize, textSize);
imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_CENTER);
// First space will be replaced with Drawable, second space is for space before text.
SpannableString spannable = new SpannableString(" " + text);
spannable.setSpan(imageSpan, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
setText(spannable);
}
@RequiresApi(Build.VERSION_CODES.S)
private DoubleShadowIconDrawable getDoubleShadowDrawable(
@NonNull Drawable drawable, int textSize
) {
// add some padding via inset to avoid shadow clipping
int iconInsetSize = getContext().getResources()
.getDimensionPixelSize(R.dimen.app_title_icon_shadow_inset);
return new DoubleShadowIconDrawable(
mShadowInfo,
drawable,
textSize,
iconInsetSize
);
}
@Override
public void onDraw(Canvas canvas) {
if (shouldDrawAppContrastTile() && !TextUtils.isEmpty(getText())) {
drawAppContrastTile(canvas);
}
// If text is transparent or shadow alpha is 0, don't draw any shadow
if (skipDoubleShadow()) {
super.onDraw(canvas);
return;
}
int alpha = Color.alpha(getCurrentTextColor());
// We enhance the shadow by drawing the shadow twice
getPaint().setShadowLayer(mShadowInfo.getAmbientShadowBlur(), 0, 0,
getTextShadowColor(mShadowInfo.getAmbientShadowColor(), alpha));
drawWithoutDot(canvas);
canvas.save();
canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
getScrollX() + getWidth(),
getScrollY() + getHeight());
getPaint().setShadowLayer(
mShadowInfo.getKeyShadowBlur(),
mShadowInfo.getKeyShadowOffsetX(),
mShadowInfo.getKeyShadowOffsetY(),
getTextShadowColor(mShadowInfo.getKeyShadowColor(), alpha));
drawWithoutDot(canvas);
canvas.restore();
drawDotIfNecessary(canvas);
drawRunningAppIndicatorIfNecessary(canvas);
}
private boolean skipDoubleShadow() {
int textAlpha = Color.alpha(getCurrentTextColor());
int keyShadowAlpha = Color.alpha(mShadowInfo.getKeyShadowColor());
int ambientShadowAlpha = Color.alpha(mShadowInfo.getAmbientShadowColor());
if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
getPaint().clearShadowLayer();
return true;
} else if (ambientShadowAlpha > 0 && keyShadowAlpha == 0) {
getPaint().setShadowLayer(mShadowInfo.getAmbientShadowBlur(), 0, 0,
getTextShadowColor(mShadowInfo.getAmbientShadowColor(), textAlpha));
return true;
} else if (keyShadowAlpha > 0 && ambientShadowAlpha == 0) {
getPaint().setShadowLayer(
mShadowInfo.getKeyShadowBlur(),
mShadowInfo.getKeyShadowOffsetX(),
mShadowInfo.getKeyShadowOffsetY(),
getTextShadowColor(mShadowInfo.getKeyShadowColor(), textAlpha));
return true;
} else {
return false;
}
}
// Multiplies the alpha of shadowColor by textAlpha.
private static int getTextShadowColor(int shadowColor, int textAlpha) {
return setColorAlphaBound(shadowColor,
Math.round(Color.alpha(shadowColor) * textAlpha / 255f));
}
}