1package com.bumptech.glide.load.resource.bitmap;
2
3import android.content.res.Resources;
4import android.graphics.Bitmap;
5import android.graphics.Canvas;
6import android.graphics.ColorFilter;
7import android.graphics.Paint;
8import android.graphics.PixelFormat;
9import android.graphics.Rect;
10import android.graphics.drawable.Drawable;
11import android.util.DisplayMetrics;
12import android.view.Gravity;
13
14import com.bumptech.glide.load.resource.drawable.GlideDrawable;
15
16/**
17 * A static {@link com.bumptech.glide.load.resource.drawable.GlideDrawable} for displaying a single image.
18 */
19public class GlideBitmapDrawable extends GlideDrawable {
20    private final Rect destRect = new Rect();
21    private int width;
22    private int height;
23    private boolean applyGravity;
24    private boolean mutated;
25    private BitmapState state;
26
27    public GlideBitmapDrawable(Resources res, Bitmap bitmap) {
28        this(res, new BitmapState(bitmap));
29    }
30
31    GlideBitmapDrawable(Resources res, BitmapState state) {
32        if (state == null) {
33            throw new NullPointerException("BitmapState must not be null");
34        }
35
36        this.state = state;
37        final int targetDensity;
38        if (res != null) {
39            final int density = res.getDisplayMetrics().densityDpi;
40            targetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
41            state.targetDensity = targetDensity;
42        } else {
43            targetDensity = state.targetDensity;
44        }
45        width = state.bitmap.getScaledWidth(targetDensity);
46        height = state.bitmap.getScaledHeight(targetDensity);
47    }
48
49    @Override
50    public int getIntrinsicWidth() {
51        return width;
52    }
53
54    @Override
55    public int getIntrinsicHeight() {
56        return height;
57    }
58
59    @Override
60    public boolean isAnimated() {
61        return false;
62    }
63
64    @Override
65    public void setLoopCount(int loopCount) {
66        // Do nothing.
67    }
68
69    @Override
70    public void start() {
71        // Do nothing.
72    }
73
74    @Override
75    public void stop() {
76        // Do nothing.
77    }
78
79    @Override
80    public boolean isRunning() {
81        return false;
82    }
83
84    @Override
85    protected void onBoundsChange(Rect bounds) {
86        super.onBoundsChange(bounds);
87        applyGravity = true;
88    }
89
90    @Override
91    public ConstantState getConstantState() {
92        return state;
93    }
94
95    @Override
96    public void draw(Canvas canvas) {
97        if (applyGravity) {
98            Gravity.apply(BitmapState.GRAVITY, width, height, getBounds(), destRect);
99            applyGravity = false;
100        }
101        canvas.drawBitmap(state.bitmap, null, destRect, state.paint);
102    }
103
104    @Override
105    public void setAlpha(int alpha) {
106        int currentAlpha = state.paint.getAlpha();
107        if (currentAlpha != alpha) {
108            state.setAlpha(alpha);
109            invalidateSelf();
110        }
111    }
112
113    @Override
114    public void setColorFilter(ColorFilter colorFilter) {
115        state.setColorFilter(colorFilter);
116        invalidateSelf();
117    }
118
119    @Override
120    public int getOpacity() {
121        Bitmap bm = state.bitmap;
122        return bm == null || bm.hasAlpha() || state.paint.getAlpha() < 255
123                ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
124    }
125
126    @Override
127    public Drawable mutate() {
128        if (!mutated && super.mutate() == this) {
129            state = new BitmapState(state);
130            mutated = true;
131        }
132        return this;
133    }
134
135    public Bitmap getBitmap() {
136        return state.bitmap;
137    }
138
139    static class BitmapState extends ConstantState {
140        private static final int DEFAULT_PAINT_FLAGS = Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
141        private static final Paint DEFAULT_PAINT = new Paint(DEFAULT_PAINT_FLAGS);
142        private static final int GRAVITY = Gravity.FILL;
143
144        final Bitmap bitmap;
145
146        int targetDensity;
147        Paint paint = DEFAULT_PAINT;
148
149        public BitmapState(Bitmap bitmap) {
150            this.bitmap = bitmap;
151        }
152
153
154        BitmapState(BitmapState other) {
155            this(other.bitmap);
156            targetDensity = other.targetDensity;
157        }
158
159        void setColorFilter(ColorFilter colorFilter) {
160            mutatePaint();
161            paint.setColorFilter(colorFilter);
162        }
163
164        void setAlpha(int alpha) {
165            mutatePaint();
166            paint.setAlpha(alpha);
167        }
168
169        // We want to create a new Paint object so we can mutate it safely.
170        @SuppressWarnings("PMD.CompareObjectsWithEquals")
171        void mutatePaint() {
172            if (DEFAULT_PAINT == paint) {
173                paint = new Paint(DEFAULT_PAINT_FLAGS);
174            }
175        }
176
177        @Override
178        public Drawable newDrawable() {
179            return new GlideBitmapDrawable(null, this);
180        }
181
182        @Override
183        public Drawable newDrawable(Resources res) {
184            return new GlideBitmapDrawable(res, this);
185        }
186
187        @Override
188        public int getChangingConfigurations() {
189            return 0;
190        }
191    }
192}
193