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