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