1987ee64612e2510004fdf08536746c87234d01c1Paul Rohde/*
2987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Copyright (C) 2014 The Android Open Source Project
3987ee64612e2510004fdf08536746c87234d01c1Paul Rohde *
4987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Licensed under the Apache License, Version 2.0 (the "License");
5987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * you may not use this file except in compliance with the License.
6987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * You may obtain a copy of the License at
7987ee64612e2510004fdf08536746c87234d01c1Paul Rohde *
8987ee64612e2510004fdf08536746c87234d01c1Paul Rohde *      http://www.apache.org/licenses/LICENSE-2.0
9987ee64612e2510004fdf08536746c87234d01c1Paul Rohde *
10987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Unless required by applicable law or agreed to in writing, software
11987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * distributed under the License is distributed on an "AS IS" BASIS,
12987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * See the License for the specific language governing permissions and
14987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * limitations under the License.
15987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */
16987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
17987ee64612e2510004fdf08536746c87234d01c1Paul Rohdepackage com.android.camera.ui.motion;
18987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
19987ee64612e2510004fdf08536746c87234d01c1Paul Rohdeimport android.graphics.Canvas;
20987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
21987ee64612e2510004fdf08536746c87234d01c1Paul Rohdeimport java.util.ArrayList;
22987ee64612e2510004fdf08536746c87234d01c1Paul Rohdeimport java.util.List;
23987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
24987ee64612e2510004fdf08536746c87234d01c1Paul Rohde/**
25987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Designed to handle the lifecycle of a view that needs a continuous update /
26987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * redraw cycle that does not have a defined start / end time.
27987ee64612e2510004fdf08536746c87234d01c1Paul Rohde *
28987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Fixed length animations should NOT use this class.
29987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */
30987ee64612e2510004fdf08536746c87234d01c1Paul Rohdepublic class DynamicAnimator implements Invalidator {
31987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
32987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    public final List<DynamicAnimation> animations = new ArrayList<>();
33987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
34987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private final Invalidator mInvalidator;
35987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private final AnimationClock mClock;
36987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
37987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private boolean mUpdateRequested = false;
38987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private boolean mIsDrawing = false;
39987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private long mLastDrawTimeMillis = 0;
40987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private long mDrawTimeMillis = 0;
41987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
42987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    public DynamicAnimator(Invalidator invalidator, AnimationClock clock) {
43987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mInvalidator = invalidator;
44987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mClock = clock;
45987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    }
46987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
47987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    public void draw(Canvas canvas) {
48987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mIsDrawing = true;
49987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mUpdateRequested = false;
50987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
51987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mDrawTimeMillis = mClock.getTimeMillis();
52987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
53987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        if (mLastDrawTimeMillis <= 0) {
54987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            mLastDrawTimeMillis = mDrawTimeMillis; // On the initial draw, dt is zero.
55987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        }
56987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
57987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        long dt = mDrawTimeMillis - mLastDrawTimeMillis;
58987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mLastDrawTimeMillis = mDrawTimeMillis;
59987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
60987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        // Run the animation
61987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        for (DynamicAnimation renderer : animations) {
62987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            if (renderer.isActive()) {
63987ee64612e2510004fdf08536746c87234d01c1Paul Rohde                renderer.draw(mDrawTimeMillis, dt, canvas);
64987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            }
65987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        }
66987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
67987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        // If either the update or the draw methods requested new frames, then
68987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        // invalidate the view which should give us another frame to work with.
69987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        // Otherwise, stopAt the last update time.
70987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        if (mUpdateRequested) {
71987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            mInvalidator.invalidate();
72987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        } else {
73987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            mLastDrawTimeMillis = -1;
74987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        }
75987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
76987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mIsDrawing = false;
77987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    }
78987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
79987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    /**
80987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * If a scheduleNewFrame request comes in outside of the animation loop,
81987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * and we didn't schedule a frame after the previous loop (or it's the
82987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * first time we've used this instance), invalidate the view and set the
83987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * last update time to the current time. Theoretically, a few milliseconds
84987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * have elapsed before the view gets updated.
85987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     */
86987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    @Override
87987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    public void invalidate() {
88987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        if (!mIsDrawing && !mUpdateRequested) {
89987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            mInvalidator.invalidate();
90987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            mLastDrawTimeMillis = mClock.getTimeMillis();
91987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        }
92987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
93987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mUpdateRequested = true;
94987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    }
95987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
96987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    /**
97987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * This will return the "best guess" for the most current animation frame
98987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * time.  If the loop is currently drawing, then it will return the time the
99987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * draw began, and if an update is currently requested it will return the
100987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * time that the update was requested at, and if neither of these are true
101987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * it will return the current system clock time.
102987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     *
103987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     * This method will not trigger a new update.
104987ee64612e2510004fdf08536746c87234d01c1Paul Rohde     */
105987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    public long getTimeMillis() {
106987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        if (mIsDrawing) {
107987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            return mDrawTimeMillis;
108987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        }
109987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
110987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        if (mUpdateRequested) {
111987ee64612e2510004fdf08536746c87234d01c1Paul Rohde            return mLastDrawTimeMillis;
112987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        }
113987ee64612e2510004fdf08536746c87234d01c1Paul Rohde
114987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        return mClock.getTimeMillis();
115987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    }
116987ee64612e2510004fdf08536746c87234d01c1Paul Rohde}
117