Home | History | Annotate | Download | only in motion
      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 
     42     public DynamicAnimator(Invalidator invalidator, AnimationClock clock) {
     43         mInvalidator = invalidator;
     44         mClock = clock;
     45     }
     46 
     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
     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      */
    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