1 /* 2 * Copyright 2016, 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 package com.android.managedprovisioning.preprovisioning.anim; 17 18 import static com.android.internal.util.Preconditions.checkNotNull; 19 20 import android.animation.Animator; 21 import android.animation.AnimatorInflater; 22 import android.animation.AnimatorSet; 23 import android.animation.ObjectAnimator; 24 import android.app.Activity; 25 import android.graphics.drawable.Animatable2; 26 import android.graphics.drawable.AnimatedVectorDrawable; 27 import android.graphics.drawable.Drawable; 28 import android.support.annotation.NonNull; 29 import android.widget.ImageView; 30 import android.widget.TextView; 31 32 import com.android.managedprovisioning.R; 33 34 import java.util.List; 35 36 /** 37 * <p>Drives the animation showing benefits of having a Managed Profile. 38 * <p>Tightly coupled with the {@link R.layout#intro_animation} layout. 39 */ 40 public class BenefitsAnimation { 41 /** Array of Id pairs: {{@link ObjectAnimator}, {@link TextView}} */ 42 private static final int[][] ID_ANIMATION_TARGET = { 43 {R.anim.text_scene_0_animation, R.id.text_0}, 44 {R.anim.text_scene_1_animation, R.id.text_1}, 45 {R.anim.text_scene_2_animation, R.id.text_2}, 46 {R.anim.text_scene_3_animation, R.id.text_3}, 47 {R.anim.text_scene_master_animation, R.id.text_master}}; 48 49 private static final int[] SLIDE_CAPTION_TEXT_VIEWS = { 50 R.id.text_0, R.id.text_1, R.id.text_2, R.id.text_3}; 51 52 /** Id of an {@link ImageView} containing the animated graphic */ 53 private static final int ID_ANIMATED_GRAPHIC = R.id.animated_info; 54 55 /** Id of an {@link ImageView} containing the animated pager dots */ 56 private static final int ID_ANIMATED_DOTS = R.id.animated_dots; 57 58 private static final int SLIDE_COUNT = 3; 59 60 private final AnimatedVectorDrawable mTopAnimation; 61 private final AnimatedVectorDrawable mDotsAnimation; 62 private final Animator mTextAnimation; 63 private final Activity mActivity; 64 65 private boolean mStopped; 66 67 /** 68 * @param captions slide captions for the animation 69 */ BenefitsAnimation(Activity activity, @NonNull List<Integer> captions)70 public BenefitsAnimation(Activity activity, @NonNull List<Integer> captions) { 71 if (captions.size() != SLIDE_COUNT) { 72 throw new IllegalArgumentException( 73 "Wrong number of slide captions. Expected: " + SLIDE_COUNT); 74 } 75 mActivity = checkNotNull(activity); 76 mTextAnimation = checkNotNull(assembleTextAnimation()); 77 applySlideCaptions(captions); 78 mDotsAnimation = checkNotNull(extractAnimationFromImageView(ID_ANIMATED_DOTS)); 79 mTopAnimation = checkNotNull(extractAnimationFromImageView(ID_ANIMATED_GRAPHIC)); 80 81 // chain all animations together 82 chainAnimations(); 83 } 84 85 /** Starts playing the animation in a loop. */ start()86 public void start() { 87 mStopped = false; 88 mTopAnimation.start(); 89 } 90 91 /** Stops the animation. */ stop()92 public void stop() { 93 mStopped = true; 94 mTopAnimation.stop(); 95 } 96 97 /** 98 * <p>Chains all three sub-animations, and configures them to play in sync in a loop. 99 * <p>Looping {@link AnimatedVectorDrawable} and {@link AnimatorSet} currently not possible in 100 * XML. 101 */ chainAnimations()102 private void chainAnimations() { 103 mTopAnimation.registerAnimationCallback(new Animatable2.AnimationCallback() { 104 @Override 105 public void onAnimationStart(Drawable drawable) { 106 super.onAnimationStart(drawable); 107 108 // starting the other animations at the same time 109 mDotsAnimation.start(); 110 mTextAnimation.start(); 111 } 112 113 @Override 114 public void onAnimationEnd(Drawable drawable) { 115 super.onAnimationEnd(drawable); 116 117 // without explicitly stopping them, sometimes they won't restart 118 mDotsAnimation.stop(); 119 mTextAnimation.cancel(); 120 121 // repeating the animation in loop 122 if (!mStopped) { 123 mTopAnimation.start(); 124 } 125 } 126 }); 127 } 128 129 /** 130 * <p>Inflates animators required to animate text headers' part of the whole animation. 131 * <p>This has to be done through code, as setting a target on {@link 132 * android.animation.ObjectAnimator} is not currently possible in XML. 133 * 134 * @return {@link AnimatorSet} responsible for the animated text 135 */ assembleTextAnimation()136 private AnimatorSet assembleTextAnimation() { 137 Animator[] animators = new Animator[ID_ANIMATION_TARGET.length]; 138 for (int i = 0; i < ID_ANIMATION_TARGET.length; i++) { 139 int[] instance = ID_ANIMATION_TARGET[i]; 140 animators[i] = AnimatorInflater.loadAnimator(mActivity, instance[0]); 141 animators[i].setTarget(mActivity.findViewById(instance[1])); 142 } 143 144 AnimatorSet animatorSet = new AnimatorSet(); 145 animatorSet.playTogether(animators); 146 return animatorSet; 147 } 148 149 /** 150 * @param captions slide titles 151 */ applySlideCaptions(List<Integer> captions)152 private void applySlideCaptions(List<Integer> captions) { 153 int slideIx = 0; 154 for (int viewId : SLIDE_CAPTION_TEXT_VIEWS) { 155 ((TextView) mActivity.findViewById(viewId)).setText( 156 captions.get(slideIx++ % captions.size())); 157 } 158 } 159 160 /** Extracts an {@link AnimatedVectorDrawable} from a containing {@link ImageView}. */ extractAnimationFromImageView(int id)161 private AnimatedVectorDrawable extractAnimationFromImageView(int id) { 162 ImageView imageView = (ImageView) mActivity.findViewById(id); 163 return (AnimatedVectorDrawable) imageView.getDrawable(); 164 } 165 }