1c12da4a53eee911765975f0d8afe62f749806b60Jin Cao/*
2c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * Copyright (C) 2014 The Android Open Source Project
3c12da4a53eee911765975f0d8afe62f749806b60Jin Cao *
4c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * Licensed under the Apache License, Version 2.0 (the "License");
5c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * you may not use this file except in compliance with the License.
6c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * You may obtain a copy of the License at
7c12da4a53eee911765975f0d8afe62f749806b60Jin Cao *
8c12da4a53eee911765975f0d8afe62f749806b60Jin Cao *      http://www.apache.org/licenses/LICENSE-2.0
9c12da4a53eee911765975f0d8afe62f749806b60Jin Cao *
10c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * Unless required by applicable law or agreed to in writing, software
11c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * distributed under the License is distributed on an "AS IS" BASIS,
12c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * See the License for the specific language governing permissions and
14c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * limitations under the License.
15c12da4a53eee911765975f0d8afe62f749806b60Jin Cao */
16c12da4a53eee911765975f0d8afe62f749806b60Jin Caopackage com.android.mail.bitmap;
17c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
18c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.content.res.Resources;
19c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Bitmap;
20c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.BitmapShader;
21c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Canvas;
22c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Color;
23c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.ColorFilter;
24c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Matrix;
25c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Paint;
26c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Rect;
27c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.Shader;
28c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport android.graphics.drawable.Drawable;
29c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
30c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport com.android.bitmap.BitmapCache;
31c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport com.android.bitmap.RequestKey;
32c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport com.android.bitmap.ReusableBitmap;
33c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
34c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport com.android.mail.R;
35c12da4a53eee911765975f0d8afe62f749806b60Jin Caoimport com.android.mail.bitmap.ContactResolver.ContactDrawableInterface;
36c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
37c12da4a53eee911765975f0d8afe62f749806b60Jin Cao/**
38c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * A drawable that encapsulates all the functionality needed to display a contact image,
39c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * including request creation/cancelling and data unbinding/re-binding.
40c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * <p>
41c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * The actual contact resolving and decoding is handled by {@link ContactResolver}.
42c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * <p>
43c12da4a53eee911765975f0d8afe62f749806b60Jin Cao * For better performance, you should define a cache with {@link #setBitmapCache(BitmapCache)}.
44c12da4a53eee911765975f0d8afe62f749806b60Jin Cao */
45c12da4a53eee911765975f0d8afe62f749806b60Jin Caopublic abstract class AbstractAvatarDrawable extends Drawable implements ContactDrawableInterface {
46c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected final Resources mResources;
47c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
48c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private BitmapCache mCache;
49c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private ContactResolver mContactResolver;
50c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
51c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected ContactRequest mContactRequest;
52c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected ReusableBitmap mBitmap;
53c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
54c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected final float mBorderWidth;
55c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected final Paint mBitmapPaint;
56c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected final Paint mBorderPaint;
57c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected final Matrix mMatrix;
58c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
59c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private int mDecodedWidth;
60c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private int mDecodedHeight;
61c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
62c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public AbstractAvatarDrawable(final Resources res) {
63c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mResources = res;
64c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
65c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint = new Paint();
66c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint.setAntiAlias(true);
67c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint.setFilterBitmap(true);
68c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint.setDither(true);
69c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
70c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBorderWidth = res.getDimensionPixelSize(R.dimen.avatar_border_width);
71c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
72c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBorderPaint = new Paint();
73c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBorderPaint.setColor(Color.TRANSPARENT);
74c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBorderPaint.setStyle(Paint.Style.STROKE);
75c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBorderPaint.setStrokeWidth(mBorderWidth);
76c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBorderPaint.setAntiAlias(true);
77c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
78c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mMatrix = new Matrix();
79c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
80c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
81c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void setBitmapCache(final BitmapCache cache) {
82c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mCache = cache;
83c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
84c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
85c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void setContactResolver(final ContactResolver contactResolver) {
86c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mContactResolver = contactResolver;
87c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
88c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
89c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
90c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void draw(final Canvas canvas) {
91c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final Rect bounds = getBounds();
92c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (!isVisible() || bounds.isEmpty()) {
93c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            return;
94c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
95c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
96c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mBitmap != null && mBitmap.bmp != null) {
97c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            // Draw sender image.
98c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            drawBitmap(mBitmap.bmp, mBitmap.getLogicalWidth(), mBitmap.getLogicalHeight(), canvas);
99c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        } else {
100c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            // Draw the default image
101c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            drawDefaultAvatar(canvas);
102c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
103c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
104c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
105c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected abstract void drawDefaultAvatar(Canvas canvas);
106c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
107c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    /**
108c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     * Draw the bitmap onto the canvas at the current bounds taking into account the current scale.
109c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     */
110c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected void drawBitmap(final Bitmap bitmap, final int width, final int height,
111c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            final Canvas canvas) {
112c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final Rect bounds = getBounds();
113c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        // Draw bitmap through shader first.
114c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
115c12da4a53eee911765975f0d8afe62f749806b60Jin Cao                Shader.TileMode.CLAMP);
116c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mMatrix.reset();
117c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
118c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        // Fit bitmap to bounds.
119c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final float boundsWidth = (float) bounds.width();
120c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final float boundsHeight = (float) bounds.height();
121c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final float scale = Math.max(boundsWidth / width, boundsHeight / height);
122c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mMatrix.postScale(scale, scale);
123c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
124c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        // Translate bitmap to dst bounds.
125c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mMatrix.postTranslate(bounds.left, bounds.top);
126c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
127c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        shader.setLocalMatrix(mMatrix);
128c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint.setShader(shader);
129c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        drawCircle(canvas, bounds, mBitmapPaint);
130c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
131c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        // Then draw the border.
132c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final float radius = bounds.width() / 2f - mBorderWidth / 2;
133c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius, mBorderPaint);
134c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
135c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
136c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    /**
137c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     * Draws the largest circle that fits within the given <code>bounds</code>.
138c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     *
139c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     * @param canvas the canvas on which to draw
140c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     * @param bounds the bounding box of the circle
141c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     * @param paint the paint with which to draw
142c12da4a53eee911765975f0d8afe62f749806b60Jin Cao     */
143c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    protected static void drawCircle(Canvas canvas, Rect bounds, Paint paint) {
144c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2, paint);
145c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
146c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
147c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
148c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public int getDecodeWidth() {
149c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        return mDecodedWidth;
150c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
151c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
152c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
153c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public int getDecodeHeight() {
154c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        return mDecodedHeight;
155c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
156c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
157c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void setDecodeDimensions(final int decodeWidth, final int decodeHeight) {
158c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mDecodedWidth = decodeWidth;
159c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mDecodedHeight = decodeHeight;
160c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
161c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
162c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void unbind() {
163c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        setImage(null);
164c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
165c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
166c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void bind(final String name, final String email) {
167c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        setImage(new ContactRequest(name, email));
168c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
169c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
170c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private void setImage(final ContactRequest contactRequest) {
171c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mContactRequest != null && mContactRequest.equals(contactRequest)) {
172c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            return;
173c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
174c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
175c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mBitmap != null) {
176c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            mBitmap.releaseReference();
177c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            mBitmap = null;
178c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
179c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
180c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mContactResolver != null) {
181c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            mContactResolver.remove(mContactRequest, this);
182c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
183c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
184c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mContactRequest = contactRequest;
185c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
186c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (contactRequest == null) {
187c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            invalidateSelf();
188c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            return;
189c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
190c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
191c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        ReusableBitmap cached = null;
192c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mCache != null) {
193c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            cached = mCache.get(contactRequest, true /* incrementRefCount */);
194c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
195c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
196c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (cached != null) {
197c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            setBitmap(cached);
198c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        } else {
199c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            decode();
200c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
201c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
202c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
203c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private void decode() {
204c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mContactRequest == null) {
205c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            return;
206c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
207c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        // Add to batch.
208c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mContactResolver.add(mContactRequest, this);
209c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
210c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
211c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private void setBitmap(final ReusableBitmap bmp) {
212c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (mBitmap != null && mBitmap != bmp) {
213c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            mBitmap.releaseReference();
214c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
215c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmap = bmp;
216c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        invalidateSelf();
217c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
218c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
219c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
220c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void onDecodeComplete(RequestKey key, ReusableBitmap result) {
221c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        final ContactRequest request = (ContactRequest) key;
222c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        // Remove from batch.
223c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mContactResolver.remove(request, this);
224c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        if (request.equals(mContactRequest)) {
225c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            setBitmap(result);
226c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        } else {
227c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            // if the requests don't match (i.e. this request is stale), decrement the
228c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            // ref count to allow the bitmap to be pooled
229c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            if (result != null) {
230c12da4a53eee911765975f0d8afe62f749806b60Jin Cao                result.releaseReference();
231c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            }
232c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        }
233c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
234c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
235c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
236c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void setAlpha(int alpha) {
237c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint.setAlpha(alpha);
238c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
239c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
240c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
241c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public void setColorFilter(ColorFilter cf) {
242c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        mBitmapPaint.setColorFilter(cf);
243c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
244c12da4a53eee911765975f0d8afe62f749806b60Jin Cao
245c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    @Override
246c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    public int getOpacity() {
247c12da4a53eee911765975f0d8afe62f749806b60Jin Cao        return 0;
248c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    }
249c12da4a53eee911765975f0d8afe62f749806b60Jin Cao}
250