• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.graphics;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.Bitmap.Config;
21 import android.graphics.BlurMaskFilter;
22 import android.graphics.BlurMaskFilter.Blur;
23 import android.graphics.Canvas;
24 import android.graphics.Paint;
25 import android.graphics.RectF;
26 
27 import com.android.launcher3.LauncherAppState;
28 import com.android.launcher3.util.Preconditions;
29 
30 /**
31  * Utility class to add shadows to bitmaps.
32  */
33 public class ShadowGenerator {
34 
35     // Percent of actual icon size
36     private static final float HALF_DISTANCE = 0.5f;
37     private static final float BLUR_FACTOR = 0.5f/48;
38 
39     // Percent of actual icon size
40     private static final float KEY_SHADOW_DISTANCE = 1f/48;
41     private static final int KEY_SHADOW_ALPHA = 61;
42 
43     private static final int AMBIENT_SHADOW_ALPHA = 30;
44 
45     private static final Object LOCK = new Object();
46     // Singleton object guarded by {@link #LOCK}
47     private static ShadowGenerator sShadowGenerator;
48 
49     private final int mIconSize;
50 
51     private final Canvas mCanvas;
52     private final Paint mBlurPaint;
53     private final Paint mDrawPaint;
54 
ShadowGenerator()55     private ShadowGenerator() {
56         mIconSize = LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
57         mCanvas = new Canvas();
58         mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
59         mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL));
60         mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
61     }
62 
recreateIcon(Bitmap icon)63     public synchronized Bitmap recreateIcon(Bitmap icon) {
64         int[] offset = new int[2];
65         Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
66         Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888);
67         mCanvas.setBitmap(result);
68 
69         // Draw ambient shadow
70         mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
71         mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
72 
73         // Draw key shadow
74         mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
75         mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
76 
77         // Draw the icon
78         mDrawPaint.setAlpha(255);
79         mCanvas.drawBitmap(icon, 0, 0, mDrawPaint);
80 
81         mCanvas.setBitmap(null);
82         return result;
83     }
84 
getInstance()85     public static ShadowGenerator getInstance() {
86         Preconditions.assertNonUiThread();
87         synchronized (LOCK) {
88             if (sShadowGenerator == null) {
89                 sShadowGenerator = new ShadowGenerator();
90             }
91         }
92         return sShadowGenerator;
93     }
94 
95     /**
96      * Returns the minimum amount by which an icon with {@param bounds} should be scaled
97      * so that the shadows do not get clipped.
98      */
getScaleForBounds(RectF bounds)99     public static float getScaleForBounds(RectF bounds) {
100         float scale = 1;
101 
102         // For top, left & right, we need same space.
103         float minSide = Math.min(Math.min(bounds.left, bounds.right), bounds.top);
104         if (minSide < BLUR_FACTOR) {
105             scale = (HALF_DISTANCE - BLUR_FACTOR) / (HALF_DISTANCE - minSide);
106         }
107 
108         float bottomSpace = BLUR_FACTOR + KEY_SHADOW_DISTANCE;
109         if (bounds.bottom < bottomSpace) {
110             scale = Math.min(scale, (HALF_DISTANCE - bottomSpace) / (HALF_DISTANCE - bounds.bottom));
111         }
112         return scale;
113     }
114 }
115