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                 setColorAlphaBound(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(mShadowInfo.keyShadowBlur, 0.0f, mShadowInfo.keyShadowOffset,
72                 setColorAlphaBound(mShadowInfo.keyShadowColor, alpha));
73         drawWithoutDot(canvas);
74         canvas.restore();
75 
76         drawDotIfNecessary(canvas);
77     }
78 
79     public static class ShadowInfo {
80         public final float ambientShadowBlur;
81         public final int ambientShadowColor;
82 
83         public final float keyShadowBlur;
84         public final float keyShadowOffset;
85         public final int keyShadowColor;
86 
ShadowInfo(Context c, AttributeSet attrs, int defStyle)87         public ShadowInfo(Context c, AttributeSet attrs, int defStyle) {
88 
89             TypedArray a = c.obtainStyledAttributes(
90                     attrs, R.styleable.ShadowInfo, defStyle, 0);
91 
92             ambientShadowBlur = a.getDimension(R.styleable.ShadowInfo_ambientShadowBlur, 0);
93             ambientShadowColor = a.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0);
94 
95             keyShadowBlur = a.getDimension(R.styleable.ShadowInfo_keyShadowBlur, 0);
96             keyShadowOffset = a.getDimension(R.styleable.ShadowInfo_keyShadowOffset, 0);
97             keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
98             a.recycle();
99         }
100 
skipDoubleShadow(TextView textView)101         public boolean skipDoubleShadow(TextView textView) {
102             int textAlpha = Color.alpha(textView.getCurrentTextColor());
103             int keyShadowAlpha = Color.alpha(keyShadowColor);
104             int ambientShadowAlpha = Color.alpha(ambientShadowColor);
105             if (textAlpha == 0 || (keyShadowAlpha == 0 && ambientShadowAlpha == 0)) {
106                 textView.getPaint().clearShadowLayer();
107                 return true;
108             } else if (ambientShadowAlpha > 0) {
109                 textView.getPaint().setShadowLayer(ambientShadowBlur, 0, 0,
110                         setColorAlphaBound(ambientShadowColor, textAlpha));
111                 return true;
112             } else if (keyShadowAlpha > 0) {
113                 textView.getPaint().setShadowLayer(keyShadowBlur, 0.0f, keyShadowOffset,
114                         setColorAlphaBound(keyShadowColor, textAlpha));
115                 return true;
116             } else {
117                 return false;
118             }
119         }
120     }
121 }
122