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