14b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen/* 24b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * Copyright (C) 2014 The Android Open Source Project 34b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * 44b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * Licensed under the Apache License, Version 2.0 (the "License"); 54b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * you may not use this file except in compliance with the License. 64b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * You may obtain a copy of the License at 74b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * 84b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * http://www.apache.org/licenses/LICENSE-2.0 94b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * 104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * Unless required by applicable law or agreed to in writing, software 114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * distributed under the License is distributed on an "AS IS" BASIS, 124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * See the License for the specific language governing permissions and 144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * limitations under the License. 154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen */ 164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenpackage com.android.calculator2; 184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.Animator; 205f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassenimport android.animation.Animator.AnimatorListener; 214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.AnimatorListenerAdapter; 224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.AnimatorSet; 234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.ArgbEvaluator; 244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.ObjectAnimator; 254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.ValueAnimator; 264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.animation.ValueAnimator.AnimatorUpdateListener; 274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.app.Activity; 288fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassenimport android.graphics.Rect; 294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.os.Bundle; 30f79d6f699b04a735e1627b47a059760ff40c26b9Justin Klaassenimport android.support.annotation.NonNull; 313b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassenimport android.support.v4.view.ViewPager; 324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.Editable; 334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.TextUtils; 344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.TextWatcher; 35ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoroimport android.view.KeyEvent; 364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View; 37ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoroimport android.view.View.OnKeyListener; 384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View.OnLongClickListener; 395f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassenimport android.view.ViewAnimationUtils; 408fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassenimport android.view.ViewGroupOverlay; 414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.animation.AccelerateDecelerateInterpolator; 424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.widget.Button; 43fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport android.widget.TextView; 44fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 45fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorEditText.OnTextSizeChangeListener; 46fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorExpressionEvaluator.EvaluateCallback; 474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4804f79c7a5f46f6c2cf07a164ce352ab54dfe7f47Justin Klaassenpublic class Calculator extends Activity 49fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen implements OnTextSizeChangeListener, EvaluateCallback, OnLongClickListener { 504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 512be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private static final String NAME = Calculator.class.getName(); 522be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 532be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen // instance state keys 542be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private static final String KEY_CURRENT_STATE = NAME + "_currentState"; 552be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private static final String KEY_CURRENT_EXPRESSION = NAME + "_currentExpression"; 562be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 572be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen /** 582be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen * Constant for an invalid resource id. 592be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen */ 602be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen public static final int INVALID_RES_ID = -1; 614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private enum CalculatorState { 634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen INPUT, EVALUATE, RESULT, ERROR 644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private final TextWatcher mFormulaTextWatcher = new TextWatcher() { 674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { 694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onTextChanged(CharSequence charSequence, int start, int count, int after) { 734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void afterTextChanged(Editable editable) { 774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.INPUT); 7804f79c7a5f46f6c2cf07a164ce352ab54dfe7f47Justin Klaassen mEvaluator.evaluate(editable, Calculator.this); 794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }; 814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 82ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private final OnKeyListener mFormulaOnKeyListener = new OnKeyListener() { 83ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro @Override 84ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 85ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro switch (keyCode) { 86ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro case KeyEvent.KEYCODE_NUMPAD_ENTER: 87ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro case KeyEvent.KEYCODE_ENTER: 88ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (keyEvent.getAction() == KeyEvent.ACTION_UP) { 89ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onEquals(); 90ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 91ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro // ignore all other actions 92ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro return true; 93ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 94ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro return false; 95ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 96ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro }; 97ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 98741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen private final Editable.Factory mFormulaEditableFactory = new Editable.Factory() { 99741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen @Override 100741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen public Editable newEditable(CharSequence source) { 1012be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen final boolean isEdited = mCurrentState == CalculatorState.INPUT 1022be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen || mCurrentState == CalculatorState.ERROR; 1032be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen return new CalculatorExpressionBuilder(source, mTokenizer, isEdited); 104741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen } 105741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen }; 106741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 1074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorState mCurrentState; 1082be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private CalculatorExpressionTokenizer mTokenizer; 1094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorExpressionEvaluator mEvaluator; 1104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 11106360f9211fc2c6df4c5749bebb65202e1bb12a8Justin Klaassen private View mDisplayView; 1124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorEditText mFormulaEditText; 1134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorEditText mResultEditText; 1143b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen private ViewPager mPadViewPager; 1154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private View mDeleteButton; 1164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private View mClearButton; 1171283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen private View mEqualButton; 1184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private Animator mCurrentAnimator; 1204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen protected void onCreate(Bundle savedInstanceState) { 1234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onCreate(savedInstanceState); 1245f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen setContentView(R.layout.activity_calculator); 1254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 12606360f9211fc2c6df4c5749bebb65202e1bb12a8Justin Klaassen mDisplayView = findViewById(R.id.display); 1274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText = (CalculatorEditText) findViewById(R.id.formula); 1284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText = (CalculatorEditText) findViewById(R.id.result); 1293b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen mPadViewPager = (ViewPager) findViewById(R.id.pad_pager); 1304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton = findViewById(R.id.del); 1314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton = findViewById(R.id.clr); 1324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 133ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mEqualButton = findViewById(R.id.pad_numeric).findViewById(R.id.eq); 134ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (mEqualButton == null || mEqualButton.getVisibility() != View.VISIBLE) { 135ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mEqualButton = findViewById(R.id.pad_operator).findViewById(R.id.eq); 136ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 137ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 1382be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mTokenizer = new CalculatorExpressionTokenizer(this); 1392be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mEvaluator = new CalculatorExpressionEvaluator(mTokenizer); 1402be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 1415f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen savedInstanceState = savedInstanceState == null ? Bundle.EMPTY : savedInstanceState; 1422be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen setState(CalculatorState.values()[ 1432be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen savedInstanceState.getInt(KEY_CURRENT_STATE, CalculatorState.INPUT.ordinal())]); 1442be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mFormulaEditText.setText(mTokenizer.getLocalizedExpression( 1452be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen savedInstanceState.getString(KEY_CURRENT_EXPRESSION, ""))); 1462be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mEvaluator.evaluate(mFormulaEditText.getText(), this); 147741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 148741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen mFormulaEditText.setEditableFactory(mFormulaEditableFactory); 1494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.addTextChangedListener(mFormulaTextWatcher); 150ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mFormulaEditText.setOnKeyListener(mFormulaOnKeyListener); 151fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen mFormulaEditText.setOnTextSizeChangeListener(this); 1524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setOnLongClickListener(this); 1534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 156f79d6f699b04a735e1627b47a059760ff40c26b9Justin Klaassen protected void onSaveInstanceState(@NonNull Bundle outState) { 1571283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen // If there's an animation in progress, end it immediately to ensure the state is 1581283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen // up-to-date before it is serialized. 159f79d6f699b04a735e1627b47a059760ff40c26b9Justin Klaassen if (mCurrentAnimator != null) { 1601283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen mCurrentAnimator.end(); 161f79d6f699b04a735e1627b47a059760ff40c26b9Justin Klaassen } 162f79d6f699b04a735e1627b47a059760ff40c26b9Justin Klaassen 1634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onSaveInstanceState(outState); 164f79d6f699b04a735e1627b47a059760ff40c26b9Justin Klaassen 1652be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen outState.putInt(KEY_CURRENT_STATE, mCurrentState.ordinal()); 1662be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen outState.putString(KEY_CURRENT_EXPRESSION, 1672be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mTokenizer.getNormalizedExpression(mFormulaEditText.getText().toString())); 1684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private void setState(CalculatorState state) { 1714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentState != state) { 1724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentState = state; 1734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (state == CalculatorState.RESULT || state == CalculatorState.ERROR) { 1754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setVisibility(View.GONE); 1764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton.setVisibility(View.VISIBLE); 1774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else { 1784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setVisibility(View.VISIBLE); 1794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton.setVisibility(View.GONE); 1804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (state == CalculatorState.ERROR) { 1834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int errorColor = getResources().getColor(R.color.calculator_error_color); 1844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTextColor(errorColor); 1854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor(errorColor); 1868fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen getWindow().setStatusBarColor(errorColor); 1874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else { 1884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTextColor( 1894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.display_formula_text_color)); 1904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor( 1914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.display_result_text_color)); 1928fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen getWindow().setStatusBarColor( 1934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.calculator_accent_color)); 1944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1993b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen public void onBackPressed() { 2003b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen if (mPadViewPager == null || mPadViewPager.getCurrentItem() == 0) { 2013b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // If the user is currently looking at the first pad (or the pad is not paged), 2023b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // allow the system to handle the Back button. 2033b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen super.onBackPressed(); 2043b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } else { 2053b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // Otherwise, select the previous pad. 2063b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen mPadViewPager.setCurrentItem(mPadViewPager.getCurrentItem() - 1); 2073b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } 2083b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } 2093b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen 2103b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen @Override 2114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onUserInteraction() { 2124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onUserInteraction(); 2134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2141283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen // If there's an animation in progress, end it immediately to ensure the state is 2151283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen // up-to-date before the pending user interaction is handled. 2164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentAnimator != null) { 2171283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen mCurrentAnimator.end(); 2184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onButtonClick(View view) { 2224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen switch (view.getId()) { 2234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.eq: 224ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onEquals(); 2254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.del: 227ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onDelete(); 2284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.clr: 2305f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onClear(); 2314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_cos: 2334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_ln: 2344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_log: 2354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_sin: 2364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_tan: 2372be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen // Add left parenthesis after functions. 2384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.append(((Button) view).getText() + "("); 2394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen default: 2414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.append(((Button) view).getText()); 2424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 2474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public boolean onLongClick(View view) { 2484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (view.getId() == R.id.del) { 2495f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onClear(); 2504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return true; 2514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return false; 2534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 2562be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen public void onEvaluate(String expr, String result, int errorResourceId) { 2574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentState == CalculatorState.INPUT) { 2584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setText(result); 2592be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen } else if (errorResourceId != INVALID_RES_ID) { 2602be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen onError(errorResourceId); 2614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (!TextUtils.isEmpty(result)) { 2624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen onResult(result); 2634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (mCurrentState == CalculatorState.EVALUATE) { 2644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // The current expression cannot be evaluated -> return to the input state. 2654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.INPUT); 2664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 267ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 268ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mFormulaEditText.requestFocus(); 2694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 271fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen @Override 272fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen public void onTextSizeChanged(final TextView textView, float oldSize) { 273fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen if (mCurrentState != CalculatorState.INPUT) { 274fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // Only animate text changes that occur from user input. 275fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen return; 276fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen } 277fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 278fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // Calculate the values needed to perform the scale and translation animations, 279fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // maintaining the same apparent baseline for the displayed text. 280fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float textScale = oldSize / textView.getTextSize(); 281fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float translationX = (1.0f - textScale) * 282fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen (textView.getWidth() / 2.0f - textView.getPaddingEnd()); 283fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float translationY = (1.0f - textScale) * 284fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen (textView.getHeight() / 2.0f - textView.getPaddingBottom()); 285fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 286fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 287fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.playTogether( 288fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.SCALE_X, textScale, 1.0f), 289fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.SCALE_Y, textScale, 1.0f), 290fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, translationX, 0.0f), 291fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.TRANSLATION_Y, translationY, 0.0f)); 29294db720f7daf99923cc8e3d5ba8765b5529913f1Justin Klaassen animatorSet.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); 293fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 294fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.start(); 295fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen } 296fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 297ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private void onEquals() { 298ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (mCurrentState == CalculatorState.INPUT) { 299ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro setState(CalculatorState.EVALUATE); 300ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mEvaluator.evaluate(mFormulaEditText.getText(), this); 301ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 302ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 303ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 304ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private void onDelete() { 305ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro // Delete works like backspace; remove the last character from the expression. 306ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro final Editable formulaText = mFormulaEditText.getEditableText(); 307ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro final int formulaLength = formulaText.length(); 308ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (formulaLength > 0) { 309ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro formulaText.delete(formulaLength - 1, formulaLength); 310ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 311ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 312ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 3135f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void reveal(View sourceView, int colorRes, AnimatorListener listener) { 31406360f9211fc2c6df4c5749bebb65202e1bb12a8Justin Klaassen final ViewGroupOverlay groupOverlay = 31506360f9211fc2c6df4c5749bebb65202e1bb12a8Justin Klaassen (ViewGroupOverlay) getWindow().getDecorView().getOverlay(); 3168fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen 3178fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final Rect displayRect = new Rect(); 31806360f9211fc2c6df4c5749bebb65202e1bb12a8Justin Klaassen mDisplayView.getGlobalVisibleRect(displayRect); 3195f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3205f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen // Make reveal cover the display and status bar. 3215f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final View revealView = new View(this); 3228fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setBottom(displayRect.bottom); 3238fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setLeft(displayRect.left); 3248fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setRight(displayRect.right); 3255f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealView.setBackgroundColor(getResources().getColor(colorRes)); 32606360f9211fc2c6df4c5749bebb65202e1bb12a8Justin Klaassen groupOverlay.add(revealView); 3275f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int[] clearLocation = new int[2]; 3294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen sourceView.getLocationInWindow(clearLocation); 3304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen clearLocation[0] += sourceView.getWidth() / 2; 3314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen clearLocation[1] += sourceView.getHeight() / 2; 3324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3335f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final int revealCenterX = clearLocation[0] - revealView.getLeft(); 3345f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final int revealCenterY = clearLocation[1] - revealView.getTop(); 3354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3365f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final double x1_2 = Math.pow(revealView.getLeft() - revealCenterX, 2); 3375f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final double x2_2 = Math.pow(revealView.getRight() - revealCenterX, 2); 3385f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final double y_2 = Math.pow(revealView.getTop() - revealCenterY, 2); 3394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float revealRadius = (float) Math.max(Math.sqrt(x1_2 + y_2), Math.sqrt(x2_2 + y_2)); 3404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3415f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final Animator revealAnimator = 3425f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen ViewAnimationUtils.createCircularReveal(revealView, 3433d6ecaf4d3365eeaff75a4bedb57fbe136cf5f64ztenghui revealCenterX, revealCenterY, 0.0f, revealRadius); 3445f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealAnimator.setDuration( 3454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getInteger(android.R.integer.config_longAnimTime)); 3464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3475f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final Animator alphaAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f); 3484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen alphaAnimator.setDuration( 3495f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen getResources().getInteger(android.R.integer.config_mediumAnimTime)); 3501283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen alphaAnimator.addListener(listener); 3514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 3535f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen animatorSet.play(revealAnimator).before(alphaAnimator); 3544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 3554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.addListener(new AnimatorListenerAdapter() { 3564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationEnd(Animator animator) { 3588fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen groupOverlay.remove(revealView); 3594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = null; 3604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 3624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = animatorSet; 3644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.start(); 3654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3675f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void onClear() { 3685f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen if (TextUtils.isEmpty(mFormulaEditText.getText())) { 3695f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen return; 3705f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3715f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3721283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen final View sourceView = mClearButton.getVisibility() == View.VISIBLE 3731283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen ? mClearButton : mDeleteButton; 3741283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen reveal(sourceView, R.color.calculator_accent_color, new AnimatorListenerAdapter() { 3755f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen @Override 3761283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen public void onAnimationStart(Animator animation) { 3775f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mFormulaEditText.getEditableText().clear(); 3785f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3795f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen }); 3805f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3815f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3822be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private void onError(final int errorResourceId) { 3832be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen if (mCurrentState != CalculatorState.EVALUATE) { 3842be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen // Only animate error on evaluate. 3852be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mResultEditText.setText(errorResourceId); 3862be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen return; 3872be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen } 3882be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 3891283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen reveal(mEqualButton, R.color.calculator_error_color, new AnimatorListenerAdapter() { 3905f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen @Override 3911283ee748254cce69fda2d1a3d2af1cf881b2738Justin Klaassen public void onAnimationStart(Animator animation) { 3925f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen setState(CalculatorState.ERROR); 3932be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mResultEditText.setText(errorResourceId); 3945f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3955f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen }); 3965f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3975f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private void onResult(final String result) { 3994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Calculate the values needed to perform the scale and translation animations, 4004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // accounting for how the scale will affect the final position of the text. 4014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultScale = 4024b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.getVariableTextSize(result) / mResultEditText.getTextSize(); 4034b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultTranslationX = (1.0f - resultScale) * 4044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getWidth() / 2.0f - mResultEditText.getPaddingEnd()); 4054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultTranslationY = (1.0f - resultScale) * 4064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getHeight() / 2.0f - mResultEditText.getPaddingBottom()) + 4074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mFormulaEditText.getBottom() - mResultEditText.getBottom()) + 4084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getPaddingBottom() - mFormulaEditText.getPaddingBottom()); 4094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float formulaTranslationY = -mFormulaEditText.getBottom(); 4104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Use a value animator to fade to the final text color over the course of the animation. 4124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int resultTextColor = mResultEditText.getCurrentTextColor(); 4134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int formulaTextColor = mFormulaEditText.getCurrentTextColor(); 4144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final ValueAnimator textColorAnimator = 4154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ValueAnimator.ofObject(new ArgbEvaluator(), resultTextColor, formulaTextColor); 4164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen textColorAnimator.addUpdateListener(new AnimatorUpdateListener() { 4174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 4184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationUpdate(ValueAnimator valueAnimator) { 4194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor((int) valueAnimator.getAnimatedValue()); 4204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 4224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 4244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.playTogether( 4254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen textColorAnimator, 4264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.SCALE_X, resultScale), 4274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.SCALE_Y, resultScale), 4284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_X, resultTranslationX), 4294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_Y, resultTranslationY), 4304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, formulaTranslationY)); 4314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime)); 4324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 4334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.addListener(new AnimatorListenerAdapter() { 4344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 4354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationStart(Animator animation) { 4364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setText(result); 4374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 4404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationEnd(Animator animation) { 4414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Reset all of the values modified during the animation. 4424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor(resultTextColor); 4434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setScaleX(1.0f); 4444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setScaleY(1.0f); 4454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTranslationX(0.0f); 4464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTranslationY(0.0f); 4474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTranslationY(0.0f); 4484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Finally update the formula to use the current result. 4504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setText(result); 4514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.RESULT); 4524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = null; 4544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 4564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = animatorSet; 4584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.start(); 4594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen} 461