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 }