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 
33 namespace android {
34 
35 class OnAnimationEndListener {
36 public:
~OnAnimationEndListener()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  */
47 class ANDROID_API AnimatedImageDrawable : public SkDrawable {
48 public:
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 
getStagingAlpha()64     int getStagingAlpha() const { return mStagingProperties.mAlpha; }
setStagingAlpha(int alpha)65     void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; }
setStagingColorFilter(sk_sp<SkColorFilter> filter)66     void setStagingColorFilter(sk_sp<SkColorFilter> filter) {
67         mStagingProperties.mColorFilter = filter;
68     }
setStagingMirrored(bool mirrored)69     void setStagingMirrored(bool mirrored) { mStagingProperties.mMirrored = mirrored; }
70     void syncProperties();
71 
onGetBounds()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();
getRepetitionCount()86     int getRepetitionCount() const { return mSkAnimatedImage->getRepetitionCount(); }
setRepetitionCount(int count)87     void setRepetitionCount(int count) { mSkAnimatedImage->setRepetitionCount(count); }
88 
setOnAnimationEndListener(std::unique_ptr<OnAnimationEndListener> listener)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 
byteSize()109     size_t byteSize() const { return sizeof(*this) + mBytesUsed; }
110 
111 protected:
112     virtual void onDraw(SkCanvas* canvas) override;
113 
114 private:
115     sk_sp<SkAnimatedImage> mSkAnimatedImage;
116     const size_t mBytesUsed;
117 
118     bool mRunning = false;
119     bool mStarting = false;
120 
121     // A snapshot of the current frame to draw.
122     Snapshot mSnapshot;
123 
124     std::future<Snapshot> mNextSnapshot;
125 
126     bool nextSnapshotReady() const;
127 
128     // When to switch from mSnapshot to mNextSnapshot.
129     nsecs_t mTimeToShowNextSnapshot = 0;
130 
131     // The current time for the drawable itself.
132     nsecs_t mCurrentTime = 0;
133 
134     // The wall clock of the last time we called isDirty.
135     nsecs_t mLastWallTime = 0;
136 
137     // Locked when assigning snapshots and times. Operations while this is held
138     // should be short.
139     std::mutex mSwapLock;
140 
141     // Locked when mSkAnimatedImage is being updated or drawn.
142     std::mutex mImageLock;
143 
144     struct Properties {
145         int mAlpha = SK_AlphaOPAQUE;
146         sk_sp<SkColorFilter> mColorFilter;
147         bool mMirrored = false;
148 
149         Properties() = default;
150         Properties(Properties&) = default;
151         Properties& operator=(Properties&) = default;
152     };
153 
154     Properties mStagingProperties;
155     Properties mProperties;
156 
157     std::unique_ptr<OnAnimationEndListener> mEndListener;
158 };
159 
160 }  // namespace android
161