1 /*
2  * Copyright (C) 2014 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 package com.android.camera.ui.motion;
18 
19 import android.graphics.Canvas;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 /**
25  * Designed to handle the lifecycle of a view that needs a continuous update /
26  * redraw cycle that does not have a defined start / end time.
27  *
28  * Fixed length animations should NOT use this class.
29  */
30 public class DynamicAnimator implements Invalidator {
31 
32     public final List<DynamicAnimation> animations = new ArrayList<>();
33 
34     private final Invalidator mInvalidator;
35     private final AnimationClock mClock;
36 
37     private boolean mUpdateRequested = false;
38     private boolean mIsDrawing = false;
39     private long mLastDrawTimeMillis = 0;
40     private long mDrawTimeMillis = 0;
41 
DynamicAnimator(Invalidator invalidator, AnimationClock clock)42     public DynamicAnimator(Invalidator invalidator, AnimationClock clock) {
43         mInvalidator = invalidator;
44         mClock = clock;
45     }
46 
draw(Canvas canvas)47     public void draw(Canvas canvas) {
48         mIsDrawing = true;
49         mUpdateRequested = false;
50 
51         mDrawTimeMillis = mClock.getTimeMillis();
52 
53         if (mLastDrawTimeMillis <= 0) {
54             mLastDrawTimeMillis = mDrawTimeMillis; // On the initial draw, dt is zero.
55         }
56 
57         long dt = mDrawTimeMillis - mLastDrawTimeMillis;
58         mLastDrawTimeMillis = mDrawTimeMillis;
59 
60         // Run the animation
61         for (DynamicAnimation renderer : animations) {
62             if (renderer.isActive()) {
63                 renderer.draw(mDrawTimeMillis, dt, canvas);
64             }
65         }
66 
67         // If either the update or the draw methods requested new frames, then
68         // invalidate the view which should give us another frame to work with.
69         // Otherwise, stopAt the last update time.
70         if (mUpdateRequested) {
71             mInvalidator.invalidate();
72         } else {
73             mLastDrawTimeMillis = -1;
74         }
75 
76         mIsDrawing = false;
77     }
78 
79     /**
80      * If a scheduleNewFrame request comes in outside of the animation loop,
81      * and we didn't schedule a frame after the previous loop (or it's the
82      * first time we've used this instance), invalidate the view and set the
83      * last update time to the current time. Theoretically, a few milliseconds
84      * have elapsed before the view gets updated.
85      */
86     @Override
invalidate()87     public void invalidate() {
88         if (!mIsDrawing && !mUpdateRequested) {
89             mInvalidator.invalidate();
90             mLastDrawTimeMillis = mClock.getTimeMillis();
91         }
92 
93         mUpdateRequested = true;
94     }
95 
96     /**
97      * This will return the "best guess" for the most current animation frame
98      * time.  If the loop is currently drawing, then it will return the time the
99      * draw began, and if an update is currently requested it will return the
100      * time that the update was requested at, and if neither of these are true
101      * it will return the current system clock time.
102      *
103      * This method will not trigger a new update.
104      */
getTimeMillis()105     public long getTimeMillis() {
106         if (mIsDrawing) {
107             return mDrawTimeMillis;
108         }
109 
110         if (mUpdateRequested) {
111             return mLastDrawTimeMillis;
112         }
113 
114         return mClock.getTimeMillis();
115     }
116 }
117