Files
Lawnchair/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
T
Charlie Anderson 99147f53e0 Use DoubleShadowIconDrawable to draw shadow behind archived cloud icon
- Refactor Launcher3 ShadowInfo out of DoubleShadowBubbleTextView

Bug: 350758155
Test: locally verified + screenshot test
Flag: com.android.launcher3.use_new_icon_for_archived_apps
Change-Id: I8e5e5936296fafbfbf3caf80a936ca1038c125e3
2024-08-07 11:56:33 -04:00

164 lines
6.1 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.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 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));
}
}