1 /* 2 * Copyright (C) 2010 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.photoeditor.animation; 18 19 import android.graphics.Camera; 20 import android.graphics.Matrix; 21 import android.view.animation.AccelerateInterpolator; 22 import android.view.animation.Animation; 23 import android.view.animation.DecelerateInterpolator; 24 import android.view.animation.Transformation; 25 26 /** 27 * Rotation animation that rotates a 2D view 90 degrees on either X or Y axis in 3D space. The 28 * rotation is performed around the view center point by its defined rotation direction and position 29 * it will start from or end to. The rotation duration can be specified as well as whether the 30 * rotation should be accelerated or decelerated in time. 31 */ 32 public class Rotate3DAnimation extends Animation { 33 34 public enum Rotate { 35 UP, DOWN, LEFT, RIGHT 36 } 37 38 private enum Angle { 39 FROM_DEGREES_0, TO_DEGREES_0 40 } 41 42 private static final float DEPTH_Z = 250.0f; 43 private static final float ROTATE_DEGREES = 90f; 44 45 private final Rotate rotate; 46 private final Angle angle; 47 private final int duration; 48 private final boolean accelerate; 49 50 private Camera camera; 51 private float centerX; 52 private float centerY; 53 private float fromDegrees; 54 private float toDegrees; 55 56 /** 57 * Gets animations that flip the view by 3D rotations. 58 */ 59 public static AnimationPair getFlipAnimations(Rotate rotate, int duration) { 60 return new AnimationPair( 61 new Rotate3DAnimation(rotate, Angle.FROM_DEGREES_0, duration, true), 62 new Rotate3DAnimation(rotate, Angle.TO_DEGREES_0, duration, false)); 63 } 64 65 private Rotate3DAnimation(Rotate rotate, Angle angle, int duration, boolean accelerate) { 66 this.rotate = rotate; 67 this.angle = angle; 68 this.duration = duration; 69 this.accelerate = accelerate; 70 } 71 72 @Override 73 public void initialize(int width, int height, int parentWidth, int parentHeight) { 74 super.initialize(width, height, parentWidth, parentHeight); 75 super.setDuration(duration); 76 super.setInterpolator( 77 accelerate ? new AccelerateInterpolator() : new DecelerateInterpolator()); 78 79 camera = new Camera(); 80 centerX = width / 2.0f; 81 centerY = height / 2.0f; 82 83 if (angle == Angle.FROM_DEGREES_0) { 84 fromDegrees = 0; 85 86 switch (rotate) { 87 case RIGHT: 88 case UP: 89 toDegrees = ROTATE_DEGREES; 90 break; 91 92 case LEFT: 93 case DOWN: 94 toDegrees = -ROTATE_DEGREES; 95 break; 96 } 97 } else if (angle == Angle.TO_DEGREES_0) { 98 toDegrees = 0; 99 100 switch (rotate) { 101 case RIGHT: 102 case UP: 103 fromDegrees = -ROTATE_DEGREES; 104 break; 105 106 case LEFT: 107 case DOWN: 108 fromDegrees = ROTATE_DEGREES; 109 break; 110 } 111 } 112 } 113 114 @Override 115 protected void applyTransformation(float interpolatedTime, Transformation t) { 116 camera.save(); 117 118 if (angle == Angle.FROM_DEGREES_0) { 119 camera.translate(0.0f, 0.0f, DEPTH_Z * interpolatedTime); 120 } else if (angle == Angle.TO_DEGREES_0) { 121 camera.translate(0.0f, 0.0f, DEPTH_Z * (1.0f - interpolatedTime)); 122 } 123 124 float degrees = fromDegrees + ((toDegrees - fromDegrees) * interpolatedTime); 125 switch (rotate) { 126 case RIGHT: 127 case LEFT: 128 camera.rotateY(degrees); 129 break; 130 131 case UP: 132 case DOWN: 133 camera.rotateX(degrees); 134 break; 135 } 136 137 final Matrix matrix = t.getMatrix(); 138 camera.getMatrix(matrix); 139 camera.restore(); 140 141 matrix.preTranslate(-centerX, -centerY); 142 matrix.postTranslate(centerX, centerY); 143 } 144 } 145