1/*
2 * Copyright (C) 2018 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#pragma once
18
19#include <cutils/compiler.h>
20#include <utils/Macros.h>
21#include <utils/RefBase.h>
22#include <utils/Timers.h>
23
24#include <SkAnimatedImage.h>
25#include <SkCanvas.h>
26#include <SkColorFilter.h>
27#include <SkDrawable.h>
28#include <SkPicture.h>
29
30#include <future>
31#include <mutex>
32
33namespace android {
34
35class OnAnimationEndListener {
36public:
37    virtual ~OnAnimationEndListener() {}
38
39    virtual void onAnimationEnd() = 0;
40};
41
42/**
43 * Native component of android.graphics.drawable.AnimatedImageDrawables.java.
44 * This class can be drawn into Canvas.h and maintains the state needed to drive
45 * the animation from the RenderThread.
46 */
47class ANDROID_API AnimatedImageDrawable : public SkDrawable {
48public:
49    // bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the
50    // Snapshots.
51    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);
52
53    /**
54     * This updates the internal time and returns true if the image needs
55     * to be redrawn this frame.
56     *
57     * This is called on RenderThread, while the UI thread is locked.
58     *
59     * @param outDelay Nanoseconds in the future when the following frame
60     *      will need to be drawn. 0 if not running.
61     */
62    bool isDirty(nsecs_t* outDelay);
63
64    int getStagingAlpha() const { return mStagingProperties.mAlpha; }
65    void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; }
66    void setStagingColorFilter(sk_sp<SkColorFilter> filter) {
67        mStagingProperties.mColorFilter = filter;
68    }
69    void setStagingMirrored(bool mirrored) { mStagingProperties.mMirrored = mirrored; }
70    void syncProperties();
71
72    virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); }
73
74    // Draw to software canvas, and return time to next draw.
75    // 0 means the animation is not running.
76    // -1 means the animation advanced to the final frame.
77    int drawStaging(SkCanvas* canvas);
78
79    // Returns true if the animation was started; false otherwise (e.g. it was
80    // already running)
81    bool start();
82    // Returns true if the animation was stopped; false otherwise (e.g. it was
83    // already stopped)
84    bool stop();
85    bool isRunning();
86    int getRepetitionCount() const { return mSkAnimatedImage->getRepetitionCount(); }
87    void setRepetitionCount(int count) { mSkAnimatedImage->setRepetitionCount(count); }
88
89    void setOnAnimationEndListener(std::unique_ptr<OnAnimationEndListener> listener) {
90        mEndListener = std::move(listener);
91    }
92
93    struct Snapshot {
94        sk_sp<SkPicture> mPic;
95        int mDurationMS;
96
97        Snapshot() = default;
98
99        Snapshot(Snapshot&&) = default;
100        Snapshot& operator=(Snapshot&&) = default;
101
102        PREVENT_COPY_AND_ASSIGN(Snapshot);
103    };
104
105    // These are only called on AnimatedImageThread.
106    Snapshot decodeNextFrame();
107    Snapshot reset();
108
109    size_t byteSize() const {
110        return sizeof(this) + mBytesUsed;
111    }
112
113protected:
114    virtual void onDraw(SkCanvas* canvas) override;
115
116private:
117    sk_sp<SkAnimatedImage> mSkAnimatedImage;
118    const size_t mBytesUsed;
119
120    bool mRunning = false;
121    bool mStarting = false;
122
123    // A snapshot of the current frame to draw.
124    Snapshot mSnapshot;
125
126    std::future<Snapshot> mNextSnapshot;
127
128    bool nextSnapshotReady() const;
129
130    // When to switch from mSnapshot to mNextSnapshot.
131    nsecs_t mTimeToShowNextSnapshot = 0;
132
133    // The current time for the drawable itself.
134    nsecs_t mCurrentTime = 0;
135
136    // The wall clock of the last time we called isDirty.
137    nsecs_t mLastWallTime = 0;
138
139    // Locked when assigning snapshots and times. Operations while this is held
140    // should be short.
141    std::mutex mSwapLock;
142
143    // Locked when mSkAnimatedImage is being updated or drawn.
144    std::mutex mImageLock;
145
146    struct Properties {
147        int mAlpha = SK_AlphaOPAQUE;
148        sk_sp<SkColorFilter> mColorFilter;
149        bool mMirrored = false;
150
151        Properties() = default;
152        Properties(Properties&) = default;
153        Properties& operator=(Properties&) = default;
154    };
155
156    Properties mStagingProperties;
157    Properties mProperties;
158
159    std::unique_ptr<OnAnimationEndListener> mEndListener;
160};
161
162}  // namespace android
163