1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.views;
18 
19 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
20 
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.graphics.Canvas;
24 import android.graphics.Color;
25 import android.util.AttributeSet;
26 import android.widget.TextView;
27 
28 import com.android.launcher3.BubbleTextView;
29 import com.android.launcher3.R;
30 
31 /**
32  * Extension of {@link BubbleTextView} which draws two shadows on the text (ambient and key shadows}
33  */
34 public class DoubleShadowBubbleTextView extends BubbleTextView {
35 
36     private final ShadowInfo mShadowInfo;
37 
DoubleShadowBubbleTextView(Context context)38     public DoubleShadowBubbleTextView(Context context) {
39         this(context, null);
40     }
41 
DoubleShadowBubbleTextView(Context context, AttributeSet attrs)42     public DoubleShadowBubbleTextView(Context context, AttributeSet attrs) {
43         this(context, attrs, 0);
44     }
45 
DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle)46     public DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
47         super(context, attrs, defStyle);
48         mShadowInfo = new ShadowInfo(context, attrs, defStyle);
49         setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
50     }
51 
52     @Override
onDraw(Canvas canvas)53     public void onDraw(Canvas canvas) {
54         // If text is transparent or shadow alpha is 0, don't draw any shadow
55         if (mShadowInfo.skipDoubleShadow(this)) {
56             super.onDraw(canvas);
57             return;
58         }
59         int alpha = Color.alpha(getCurrentTextColor());
60 
61         // We enhance the shadow by drawing the shadow twice
62         getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0,
63                 getTextShadowColor(mShadowInfo.ambientShadowColor, alpha));
64 
65         drawWithoutDot(canvas);
66         canvas.save();
67         canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
68                 getScrollX() + getWidth(),
69                 getScrollY() + getHeight());
70 
71         getPaint().setShadowLayer(
72                 mShadowInfo.keyShadowBlur,
73                 mShadowInfo.keyShadowOffsetX,
74                 mShadowInfo.keyShadowOffsetY,
75                 getTextShadowColor(mShadowInfo.keyShadowColor, alpha));
76         drawWithoutDot(canvas);
77         canvas.restore();
78 
79         drawDotIfNecessary(canvas);
80         drawRunningAppIndicatorIfNecessary(canvas);
81     }
82 
83     public static class ShadowInfo {
84         public final float ambientShadowBlur;
85         public final int ambientShadowColor;
86 
87         public final float keyShadowBlur;
88         public final float keyShadowOffsetX;
89         public final float keyShadowOffsetY;
90         public final int keyShadowColor;
91 
ShadowInfo(Context c, AttributeSet attrs, int defStyle)92         public ShadowInfo(Context c, AttributeSet attrs, int defStyle) {
93 
94             TypedArray a = c.obtainStyledAttributes(
95                     attrs, R.styleable.ShadowInfo, defStyle, 0);
96 
97             ambientShadowBlur = a.getDimensionPixelSize(
98                     R.styleable.ShadowInfo_ambientShadowBlur, 0);
99             ambientShadowColor = a.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0);
100 
101             keyShadowBlur = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowBlur, 0);
102             keyShadowOffsetX = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetX, 0);
103             keyShadowOffsetY = a.getDimensionPixelSize(R.styleable.ShadowInfo_keyShadowOffsetY, 0);
104             keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
105             a.recycle();
106         }
107 
skipDoubleShadow(TextView textView)108         public boolean skipDoubleShadow(TextView textView) {
109             int textAlpha = Color.alpha(textView.getCurrentTextColor());
110             int keyShadowAlpha = Color.alpha(keyShadowColor);
111             int ambientShadowAlpha = Color.alpha(ambientShadowColor);
112             if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
113                 textView.getPaint().clearShadowLayer();
114                 return true;
115             } else if (ambientShadowAlpha > 0 && keyShadowAlpha == 0) {
116                 textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
117                         getTextShadowColor(ambientShadowColor, textAlpha));
118                 return true;
119             } else if (keyShadowAlpha > 0 && ambientShadowAlpha == 0) {
120                 textView.getPaint().setShadowLayer(
121                         keyShadowBlur,
122                         keyShadowOffsetX,
123                         keyShadowOffsetY,
124                         getTextShadowColor(keyShadowColor, textAlpha));
125                 return true;
126             } else {
127                 return false;
128             }
129         }
130     }
131 
132     // Multiplies the alpha of shadowColor by textAlpha.
getTextShadowColor(int shadowColor, int textAlpha)133     private static int getTextShadowColor(int shadowColor, int textAlpha) {
134         return setColorAlphaBound(shadowColor,
135                 Math.round(Color.alpha(shadowColor) * textAlpha / 255f));
136     }
137 }
138