1 /*
2  * Copyright (C) 2015 Google Inc. All Rights Reserved.
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.example.android.wearable.speaker;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.AnimatorSet;
22 import android.animation.ObjectAnimator;
23 import android.graphics.Point;
24 import android.graphics.Rect;
25 import android.view.View;
26 import android.view.animation.DecelerateInterpolator;
27 import android.widget.ImageView;
28 
29 /**
30  * A helper class to provide a simple animation when user selects any of the three icons on the
31  * main UI.
32  */
33 public class UIAnimation {
34 
35     private AnimatorSet mCurrentAnimator;
36     private final int[] mLargeDrawables = new int[]{R.drawable.ic_mic_120dp,
37             R.drawable.ic_play_arrow_120dp, R.drawable.ic_audiotrack_120dp};
38     private final ImageView[] mThumbs;
39     private ImageView expandedImageView;
40     private final View mContainerView;
41     private final int mAnimationDurationTime;
42 
43     private UIStateListener mListener;
44     private UIState mState = UIState.HOME;
45 
UIAnimation(View containerView, ImageView[] thumbs, ImageView expandedView, int animationDuration, UIStateListener listener)46     public UIAnimation(View containerView, ImageView[] thumbs, ImageView expandedView,
47             int animationDuration, UIStateListener listener) {
48         mContainerView = containerView;
49         mThumbs = thumbs;
50         expandedImageView = expandedView;
51         mAnimationDurationTime = animationDuration;
52         mListener = listener;
53 
54         mThumbs[0].setOnClickListener(new View.OnClickListener() {
55             @Override
56             public void onClick(View view) {
57                 zoomImageFromThumb(0);
58             }
59         });
60 
61         mThumbs[1].setOnClickListener(new View.OnClickListener() {
62             @Override
63             public void onClick(View view) {
64                 zoomImageFromThumb(1);
65             }
66         });
67 
68         mThumbs[2].setOnClickListener(new View.OnClickListener() {
69             @Override
70             public void onClick(View view) {
71                 zoomImageFromThumb(2);
72             }
73         });
74     }
75 
zoomImageFromThumb(final int index)76     private void zoomImageFromThumb(final int index) {
77         int imageResId = mLargeDrawables[index];
78         final ImageView thumbView = mThumbs[index];
79         if (mCurrentAnimator != null) {
80             return;
81         }
82 
83         expandedImageView.setImageResource(imageResId);
84 
85         final Rect startBounds = new Rect();
86         final Rect finalBounds = new Rect();
87         final Point globalOffset = new Point();
88         thumbView.getGlobalVisibleRect(startBounds);
89         mContainerView.getGlobalVisibleRect(finalBounds, globalOffset);
90         startBounds.offset(-globalOffset.x, -globalOffset.y);
91         finalBounds.offset(-globalOffset.x, -globalOffset.y);
92         float startScale;
93         if ((float) finalBounds.width() / finalBounds.height()
94                 > (float) startBounds.width() / startBounds.height()) {
95             startScale = (float) startBounds.height() / finalBounds.height();
96             float startWidth = startScale * finalBounds.width();
97             float deltaWidth = (startWidth - startBounds.width()) / 2;
98             startBounds.left -= deltaWidth;
99             startBounds.right += deltaWidth;
100         } else {
101             startScale = (float) startBounds.width() / finalBounds.width();
102             float startHeight = startScale * finalBounds.height();
103             float deltaHeight = (startHeight - startBounds.height()) / 2;
104             startBounds.top -= deltaHeight;
105             startBounds.bottom += deltaHeight;
106         }
107 
108         for(int k=0; k < 3; k++) {
109             mThumbs[k].setAlpha(0f);
110         }
111         expandedImageView.setVisibility(View.VISIBLE);
112 
113         expandedImageView.setPivotX(0f);
114         expandedImageView.setPivotY(0f);
115 
116         AnimatorSet zommInAnimator = new AnimatorSet();
117         zommInAnimator.play(ObjectAnimator
118                 .ofFloat(expandedImageView, View.X, startBounds.left, finalBounds.left)).with(
119                 ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top, finalBounds
120                         .top)).with(
121                 ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
122                 .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
123         zommInAnimator.setDuration(mAnimationDurationTime);
124         zommInAnimator.setInterpolator(new DecelerateInterpolator());
125         zommInAnimator.addListener(new AnimatorListenerAdapter() {
126             @Override
127             public void onAnimationEnd(Animator animation) {
128                 mCurrentAnimator = null;
129                 if (mListener != null) {
130                     mState = UIState.getUIState(index);
131                     mListener.onUIStateChanged(mState);
132                 }
133             }
134 
135             @Override
136             public void onAnimationCancel(Animator animation) {
137                 mCurrentAnimator = null;
138             }
139         });
140         zommInAnimator.start();
141         mCurrentAnimator = zommInAnimator;
142 
143         final float startScaleFinal = startScale;
144         expandedImageView.setOnClickListener(new View.OnClickListener() {
145             @Override
146             public void onClick(View view) {
147                 if (mCurrentAnimator != null) {
148                     return;
149                 }
150                 AnimatorSet zoomOutAnimator = new AnimatorSet();
151                 zoomOutAnimator.play(ObjectAnimator
152                         .ofFloat(expandedImageView, View.X, startBounds.left))
153                         .with(ObjectAnimator
154                                 .ofFloat(expandedImageView,
155                                         View.Y, startBounds.top))
156                         .with(ObjectAnimator
157                                 .ofFloat(expandedImageView,
158                                         View.SCALE_X, startScaleFinal))
159                         .with(ObjectAnimator
160                                 .ofFloat(expandedImageView,
161                                         View.SCALE_Y, startScaleFinal));
162                 zoomOutAnimator.setDuration(mAnimationDurationTime);
163                 zoomOutAnimator.setInterpolator(new DecelerateInterpolator());
164                 zoomOutAnimator.addListener(new AnimatorListenerAdapter() {
165                     @Override
166                     public void onAnimationEnd(Animator animation) {
167                         for (int k = 0; k < 3; k++) {
168                             mThumbs[k].setAlpha(1f);
169                         }
170                         expandedImageView.setVisibility(View.GONE);
171                         mCurrentAnimator = null;
172                         if (mListener != null) {
173                             mState = UIState.HOME;
174                             mListener.onUIStateChanged(mState);
175                         }
176                     }
177 
178                     @Override
179                     public void onAnimationCancel(Animator animation) {
180                         thumbView.setAlpha(1f);
181                         expandedImageView.setVisibility(View.GONE);
182                         mCurrentAnimator = null;
183                     }
184                 });
185                 zoomOutAnimator.start();
186                 mCurrentAnimator = zoomOutAnimator;
187             }
188         });
189     }
190 
191     public enum UIState {
192         MIC_UP(0), SOUND_UP(1), MUSIC_UP(2), HOME(3);
193         private int mState;
194 
UIState(int state)195         UIState(int state) {
196             mState = state;
197         }
198 
getUIState(int state)199         static UIState getUIState(int state) {
200             for(UIState uiState : values()) {
201                 if (uiState.mState == state) {
202                     return uiState;
203                 }
204             }
205            return null;
206         }
207     }
208 
209     public interface UIStateListener {
onUIStateChanged(UIState state)210         void onUIStateChanged(UIState state);
211     }
212 
transitionToHome()213     public void transitionToHome() {
214         if (mState == UIState.HOME) {
215             return;
216         }
217         expandedImageView.callOnClick();
218 
219     }
220 }
221