summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/PreloadIconDrawable.java
blob: d9365cc1fa8c46f331baa6c3c60c6eed1f9324db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package com.android.launcher3;

import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;

class PreloadIconDrawable extends Drawable {
    private static final float ANIMATION_PROGRESS_STOPPED = -1.0f;
    private static final float ANIMATION_PROGRESS_STARTED = 0f;
    private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f;

    private static final float ICON_SCALE_FACTOR = 0.6f;

    private static Bitmap sProgressBg, sProgressFill;

    private final Rect mCanvasClipRect = new Rect();
    private final RectF mRect = new RectF();
    private final Path mProgressPath = new Path();
    private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);

    final Drawable mIcon;

    /**
     * Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon
     * is shown with no progress bar.
     */
    private int mProgress = 0;
    private boolean mPathChanged;

    private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED;
    private ObjectAnimator mAnimator;

    public PreloadIconDrawable(Drawable icon, Resources res) {
        mIcon = icon;

        setBounds(icon.getBounds());
        mPathChanged = false;

        if (sProgressBg == null) {
            sProgressBg = BitmapFactory.decodeResource(res, R.drawable.bg_preloader);
        }
        if (sProgressFill == null) {
            sProgressFill = BitmapFactory.decodeResource(res, R.drawable.bg_preloader_progress);
        }
    }

    @Override
    public void draw(Canvas canvas) {
        final Rect r = getBounds();
        if (canvas.getClipBounds(mCanvasClipRect) && !Rect.intersects(mCanvasClipRect, r)) {
            // The draw region has been clipped.
            return;
        }
        final float iconScale;

        if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED)
                && (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) {
            mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255));
            canvas.drawBitmap(sProgressBg, null, r, mPaint);
            canvas.drawBitmap(sProgressFill, null, r, mPaint);
            iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress;

        } else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) {
            mPaint.setAlpha(255);
            iconScale = ICON_SCALE_FACTOR;
            canvas.drawBitmap(sProgressBg, null, r, mPaint);

            if (mProgress >= 100) {
                canvas.drawBitmap(sProgressFill, null, r, mPaint);
            } else if (mProgress > 0) {
                if (mPathChanged) {
                    mProgressPath.reset();
                    mProgressPath.moveTo(r.exactCenterX(), r.centerY());

                    mRect.set(r);
                    mProgressPath.arcTo(mRect, -90, mProgress * 3.6f);
                    mProgressPath.close();
                    mPathChanged = false;
                }

                canvas.save();
                canvas.clipPath(mProgressPath);
                canvas.drawBitmap(sProgressFill, null, r, mPaint);
                canvas.restore();
            }
        } else {
            iconScale = 1;
        }

        canvas.save();
        canvas.scale(iconScale, iconScale, r.exactCenterX(), r.exactCenterY());
        mIcon.draw(canvas);
        canvas.restore();
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        mIcon.setBounds(bounds);
        mPathChanged = true;
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    @Override
    public void setAlpha(int alpha) {
        mIcon.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        mIcon.setColorFilter(cf);
    }

    @Override
    protected boolean onLevelChange(int level) {
        mProgress = level;
        mPathChanged = true;

        // Stop Animation
        if (mAnimator != null) {
            mAnimator.cancel();
            mAnimator = null;
        }
        mAnimationProgress = ANIMATION_PROGRESS_STOPPED;

        invalidateSelf();
        return true;
    }

    /**
     * Runs the finish animation if it is has not been run after last level change.
     */
    public void maybePerformFinishedAnimation() {
        if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) {
            return;
        }
        if (mAnimator != null) {
            mAnimator.cancel();
        }
        setAnimationProgress(ANIMATION_PROGRESS_STARTED);
        mAnimator = ObjectAnimator.ofFloat(this, "animationProgress",
                ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED);
        mAnimator.start();
    }

    public void setAnimationProgress(float progress) {
        if (progress != mAnimationProgress) {
            mAnimationProgress = progress;
            invalidateSelf();
        }
    }

    public float getAnimationProgress() {
        return mAnimationProgress;
    }
}