1 /*
2  * Copyright (C) 2013 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.example.android.toongame;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.AnimatorSet;
22 import android.animation.ObjectAnimator;
23 import android.animation.PropertyValuesHolder;
24 import android.animation.TimeInterpolator;
25 import android.animation.ValueAnimator;
26 import android.app.Activity;
27 import android.content.res.ColorStateList;
28 import android.graphics.Color;
29 import android.graphics.Typeface;
30 import android.graphics.drawable.ShapeDrawable;
31 import android.graphics.drawable.shapes.OvalShape;
32 import android.os.Bundle;
33 import android.util.TypedValue;
34 import android.view.MotionEvent;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.view.ViewTreeObserver;
38 import android.view.animation.AccelerateInterpolator;
39 import android.view.animation.DecelerateInterpolator;
40 import android.view.animation.LinearInterpolator;
41 import android.view.animation.OvershootInterpolator;
42 import android.widget.Button;
43 import android.widget.EditText;
44 import android.widget.RelativeLayout;
45 
46 /**
47  * This activity, launched from the ToonGame activity, takes the user between three
48  * different setup screens where they choose a name, choose a difficulty rating, and
49  * enter important financial information. All of the screens are meant to be
50  * simple, engaging, and fun.
51  */
52 public class PlayerSetupActivity extends Activity {
53 
54     private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
55     private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
56     ViewGroup mContainer;
57     EditText mEditText;
58 
59     private static final int NAME_STATE = 0;
60     private static final int DIFFICULTY_STATE = 1;
61     private static final int CREDIT_STATE = 2;
62     private int mEntryState = NAME_STATE;
63 
64     SkewableTextView mNameTV, mDifficultyTV, mCreditTV;
65 
66     ViewGroup mNameButtons, mDifficultyButtons, mCreditButtons1, mCreditButtons2;
67 
68     Button mBobButton, mJaneButton, mPatButton;
69 
70     private static final TimeInterpolator sOvershooter = new OvershootInterpolator();
71     private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
72 
73     @Override
onCreate(Bundle savedInstanceState)74     protected void onCreate(Bundle savedInstanceState) {
75         super.onCreate(savedInstanceState);
76         setContentView(R.layout.player_setup_layout);
77         overridePendingTransition(0, 0);
78 
79         mContainer = (ViewGroup) findViewById(R.id.container);
80         mContainer.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
81 
82         mNameTV = (SkewableTextView) findViewById(R.id.nameTV);
83         mDifficultyTV = (SkewableTextView) findViewById(R.id.ageTV);
84         mCreditTV = (SkewableTextView) findViewById(R.id.creditTV);
85 
86         mBobButton = setupButton(R.id.bobButton);
87         setupButton(R.id.janeButton);
88         setupButton(R.id.patButton);
89         setupButton(R.id.easyButton);
90         setupButton(R.id.hardButton);
91         setupButton(R.id.megaHardButton);
92 
93         mNameButtons = (ViewGroup) findViewById(R.id.nameButtons);
94         mDifficultyButtons = (ViewGroup) findViewById(R.id.difficultyButtons);
95         mCreditButtons1 = (ViewGroup) findViewById(R.id.creditButtons1);
96         mCreditButtons2 = (ViewGroup) findViewById(R.id.creditButtons2);
97     }
98 
99     @Override
finish()100     public void finish() {
101         super.finish();
102         overridePendingTransition(0, 0);
103     }
104 
setupButton(int resourceId)105     private Button setupButton(int resourceId) {
106         Button button = (Button) findViewById(resourceId);
107         button.setOnTouchListener(mButtonPressListener);
108         return button;
109     }
110 
111     private View.OnTouchListener mButtonPressListener =
112             new View.OnTouchListener() {
113                 public boolean onTouch(View v, MotionEvent event) {
114                     switch (event.getAction()) {
115                     case MotionEvent.ACTION_DOWN:
116                         v.animate().setDuration(ToonGame.SHORT_DURATION).
117                                 scaleX(.8f).scaleY(.8f).setInterpolator(sDecelerator);
118                         break;
119                     case MotionEvent.ACTION_UP:
120                         v.animate().setDuration(ToonGame.SHORT_DURATION).
121                                 scaleX(1).scaleY(1).setInterpolator(sAccelerator);
122                         break;
123                     default:
124                         break;
125                     }
126                     return false;
127                 }
128             };
129 
buttonClick(View clickedView, int alignmentRule)130     public void buttonClick(View clickedView, int alignmentRule) {
131         ViewGroup parent = (ViewGroup) clickedView.getParent();
132         for (int i = 0; i < parent.getChildCount(); ++i) {
133             Button child = (Button) parent.getChildAt(i);
134             if (child != clickedView) {
135                 child.animate().alpha(0);
136             } else {
137                 final Button buttonCopy = new Button(this);
138                 child.setVisibility(View.INVISIBLE);
139                 buttonCopy.setBackground(child.getBackground());
140                 buttonCopy.setText(((Button) child).getText());
141                 RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
142                         RelativeLayout.LayoutParams.WRAP_CONTENT,
143                         RelativeLayout.LayoutParams.WRAP_CONTENT);
144                 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
145                 params.addRule(alignmentRule);
146                 params.setMargins(25, 50, 25, 50);
147                 buttonCopy.setLayoutParams(params);
148                 buttonCopy.setPadding(child.getPaddingLeft(), child.getPaddingTop(),
149                         child.getPaddingRight(), child.getPaddingBottom());
150                 buttonCopy.setTextSize(TypedValue.COMPLEX_UNIT_PX, child.getTextSize());
151                 buttonCopy.setTypeface(child.getTypeface(), Typeface.BOLD);
152                 ColorStateList colors = child.getTextColors();
153                 buttonCopy.setTextColor(colors.getDefaultColor());
154                 final int[] oldLocationInWindow = new int[2];
155                 child.getLocationInWindow(oldLocationInWindow);
156                 mContainer.addView(buttonCopy);
157                 buttonCopy.getViewTreeObserver().addOnPreDrawListener(
158                         new ViewTreeObserver.OnPreDrawListener() {
159 
160                     @Override
161                     public boolean onPreDraw() {
162                         buttonCopy.getViewTreeObserver().removeOnPreDrawListener(this);
163                         int[] locationInWindow = new int[2];
164                         buttonCopy.getLocationInWindow(locationInWindow);
165                         float deltaX = oldLocationInWindow[0] - locationInWindow[0];
166                         float deltaY = oldLocationInWindow[1] - locationInWindow[1];
167 
168                         buttonCopy.setTranslationX(deltaX);
169                         buttonCopy.setTranslationY(deltaY);
170 
171                         PropertyValuesHolder pvhSX =
172                                 PropertyValuesHolder.ofFloat(View.SCALE_X, 3);
173                         PropertyValuesHolder pvhSY =
174                                 PropertyValuesHolder.ofFloat(View.SCALE_Y, 3);
175                         ObjectAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(
176                                 buttonCopy, pvhSX, pvhSY);
177                         bounceAnim.setRepeatCount(1);
178                         bounceAnim.setRepeatMode(ValueAnimator.REVERSE);
179                         bounceAnim.setInterpolator(sDecelerator);
180                         bounceAnim.setDuration(300);
181 
182                         PropertyValuesHolder pvhTX =
183                                 PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 0);
184                         PropertyValuesHolder pvhTY =
185                                 PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0);
186                         ObjectAnimator moveAnim = ObjectAnimator.ofPropertyValuesHolder(
187                                 buttonCopy, pvhTX, pvhTY);
188                         moveAnim.setDuration(600);
189                         bounceAnim.start();
190                         moveAnim.start();
191                         moveAnim.addListener(new AnimatorListenerAdapter() {
192                             public void onAnimationEnd(Animator animation) {
193                                 switch (mEntryState) {
194                                 case (NAME_STATE) :
195                                 {
196                                     Runnable runnable = new Runnable() {
197                                         public void run() {
198                                             mDifficultyButtons.setVisibility(View.VISIBLE);
199                                             mNameButtons.setVisibility(View.GONE);
200                                             popChildrenIn(mDifficultyButtons, null);
201                                         }
202                                     };
203                                     slideToNext(mNameTV, mDifficultyTV, runnable);
204                                     mEntryState = DIFFICULTY_STATE;
205                                     break;
206                                 }
207                                 case (DIFFICULTY_STATE) :
208                                 {
209                                     mDifficultyButtons.setVisibility(View.GONE);
210                                     for (int i = 0; i < 5; ++i) {
211                                         mCreditButtons1.addView(setupNumberButton(i));
212                                     }
213                                     for (int i = 5; i < 10; ++i) {
214                                         mCreditButtons2.addView(setupNumberButton(i));
215                                     }
216                                     Runnable runnable = new Runnable() {
217                                         public void run() {
218                                             mCreditButtons1.setVisibility(View.VISIBLE);
219                                             Runnable runnable = new Runnable() {
220                                                 public void run() {
221                                                     mCreditButtons2.setVisibility(View.VISIBLE);
222                                                     popChildrenIn(mCreditButtons2, null);
223                                                 }
224                                             };
225                                             popChildrenIn(mCreditButtons1, runnable);
226                                         }
227                                     };
228                                     slideToNext(mDifficultyTV, mCreditTV, runnable);
229                                     mEntryState = CREDIT_STATE;
230                                 }
231                                     break;
232                                 }
233                             }
234                         });
235                         return true;
236                     }
237                 });
238             }
239         }
240     }
241 
selectDifficulty(View clickedView)242     public void selectDifficulty(View clickedView) {
243         buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_RIGHT);
244     }
245 
selectName(View clickedView)246     public void selectName(View clickedView) {
247         buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_LEFT);
248     }
249 
setupNumberButton(int number)250     private Button setupNumberButton(int number) {
251         Button button = new Button(PlayerSetupActivity.this);
252         button.setTextSize(15);
253         button.setTextColor(Color.WHITE);
254         button.setTypeface(mBobButton.getTypeface(), Typeface.BOLD);
255         button.setText(Integer.toString(number));
256         button.setPadding(0, 0, 0, 0);
257 
258         OvalShape oval = new OvalShape();
259         ShapeDrawable drawable = new ShapeDrawable(oval);
260         drawable.getPaint().setColor(0xFF << 24 | (int) (50 + 150 * Math.random()) << 16 |
261                 (int) (50 + 150 * Math.random()) << 8 |  (int) (50 + 150 * Math.random()));
262         button.setBackground(drawable);
263 
264         button.setOnTouchListener(mButtonPressListener);
265 
266         return button;
267     }
268 
269     ViewTreeObserver.OnPreDrawListener mPreDrawListener =
270             new ViewTreeObserver.OnPreDrawListener() {
271 
272         @Override
273         public boolean onPreDraw() {
274             mContainer.getViewTreeObserver().removeOnPreDrawListener(this);
275             mContainer.setScaleX(0);
276             mContainer.setScaleY(0);
277             mContainer.animate().scaleX(1).scaleY(1).setInterpolator(new OvershootInterpolator());
278             mContainer.animate().setDuration(ToonGame.LONG_DURATION).withEndAction(new Runnable() {
279 
280                 @Override
281                 public void run() {
282                     ViewGroup buttonsParent = (ViewGroup) findViewById(R.id.nameButtons);
283                     buttonsParent.setVisibility(View.VISIBLE);
284                     popChildrenIn(buttonsParent, null);
285                 }
286             });
287             return false;
288         }
289     };
290 
popChildrenIn(ViewGroup parent, final Runnable endAction)291     private void popChildrenIn(ViewGroup parent, final Runnable endAction) {
292         // for all children, scale in one at a time
293         TimeInterpolator overshooter = new OvershootInterpolator();
294         int childCount = parent.getChildCount();
295         ObjectAnimator[] childAnims = new ObjectAnimator[childCount];
296         for (int i = 0; i < childCount; ++i) {
297             View child = parent.getChildAt(i);
298             child.setScaleX(0);
299             child.setScaleY(0);
300             PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
301             PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
302             ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(child, pvhSX, pvhSY);
303             anim.setDuration(150);
304             anim.setInterpolator(overshooter);
305             childAnims[i] = anim;
306         }
307         AnimatorSet set = new AnimatorSet();
308         set.playSequentially(childAnims);
309         set.start();
310         if (endAction != null) {
311             set.addListener(new AnimatorListenerAdapter() {
312                 public void onAnimationEnd(Animator animation) {
313                     endAction.run();
314                 }
315             });
316         }
317     }
318 
slideToNext(final SkewableTextView currentView, final SkewableTextView nextView, final Runnable endAction)319     private void slideToNext(final SkewableTextView currentView,
320             final SkewableTextView nextView, final Runnable endAction) {
321         // skew/anticipate current view, slide off, set GONE, restore translation
322         ObjectAnimator currentSkewer = ObjectAnimator.ofFloat(currentView, "skewX", -.5f);
323         currentSkewer.setInterpolator(sDecelerator);
324         ObjectAnimator currentMover = ObjectAnimator.ofFloat(currentView, View.TRANSLATION_X,
325                 -mContainer.getWidth());
326         currentMover.setInterpolator(sLinearInterpolator);
327         currentMover.setDuration(ToonGame.MEDIUM_DURATION);
328 
329         // set next view visible, translate off to right, skew,
330         // slide on in parallel, overshoot/wobble, unskew
331         nextView.setVisibility(View.VISIBLE);
332         nextView.setSkewX(-.5f);
333         nextView.setTranslationX(mContainer.getWidth());
334 
335         ObjectAnimator nextMover = ObjectAnimator.ofFloat(nextView, View.TRANSLATION_X, 0);
336         nextMover.setInterpolator(sAccelerator);
337         nextMover.setDuration(ToonGame.MEDIUM_DURATION);
338         ObjectAnimator nextSkewer = ObjectAnimator.ofFloat(nextView, "skewX", 0);
339         nextSkewer.setInterpolator(sOvershooter);
340 
341         AnimatorSet moverSet = new AnimatorSet();
342         moverSet.playTogether(currentMover, nextMover);
343         AnimatorSet fullSet = new AnimatorSet();
344         fullSet.playSequentially(currentSkewer, moverSet, nextSkewer);
345         fullSet.addListener(new AnimatorListenerAdapter() {
346             @Override
347             public void onAnimationEnd(Animator animation) {
348                 currentView.setSkewX(0);
349                 currentView.setVisibility(View.GONE);
350                 currentView.setTranslationX(0);
351                 if (endAction != null) {
352                     endAction.run();
353                 }
354             }
355         });
356 
357         fullSet.start();
358     }
359 
360 }
361