Calculator.java revision ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360
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; 303b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassenimport android.support.v4.view.ViewPager; 314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.Editable; 324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.TextUtils; 334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.TextWatcher; 34ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoroimport android.view.KeyEvent; 354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View; 36ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoroimport android.view.View.OnKeyListener; 374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View.OnLongClickListener; 385f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassenimport android.view.ViewAnimationUtils; 398fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassenimport android.view.ViewGroupOverlay; 404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.animation.AccelerateDecelerateInterpolator; 414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.widget.Button; 42fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport android.widget.TextView; 43fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 44fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorEditText.OnTextSizeChangeListener; 45fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorExpressionEvaluator.EvaluateCallback; 464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 47ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoroimport java.lang.Override; 48ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 4904f79c7a5f46f6c2cf07a164ce352ab54dfe7f47Justin Klaassenpublic class Calculator extends Activity 50fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen implements OnTextSizeChangeListener, EvaluateCallback, OnLongClickListener { 514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 522be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private static final String NAME = Calculator.class.getName(); 532be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 542be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen // instance state keys 552be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private static final String KEY_CURRENT_STATE = NAME + "_currentState"; 562be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private static final String KEY_CURRENT_EXPRESSION = NAME + "_currentExpression"; 572be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 582be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen /** 592be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen * Constant for an invalid resource id. 602be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen */ 612be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen public static final int INVALID_RES_ID = -1; 624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private enum CalculatorState { 644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen INPUT, EVALUATE, RESULT, ERROR 654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private final TextWatcher mFormulaTextWatcher = new TextWatcher() { 684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { 704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onTextChanged(CharSequence charSequence, int start, int count, int after) { 744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void afterTextChanged(Editable editable) { 784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.INPUT); 7904f79c7a5f46f6c2cf07a164ce352ab54dfe7f47Justin Klaassen mEvaluator.evaluate(editable, Calculator.this); 804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }; 824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 83ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private final OnKeyListener mFormulaOnKeyListener = new OnKeyListener() { 84ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro @Override 85ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 86ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro switch (keyCode) { 87ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro case KeyEvent.KEYCODE_NUMPAD_ENTER: 88ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro case KeyEvent.KEYCODE_ENTER: 89ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (keyEvent.getAction() == KeyEvent.ACTION_UP) { 90ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mCurrentButton = mEqualButton; 91ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onEquals(); 92ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 93ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro // ignore all other actions 94ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro return true; 95ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro case KeyEvent.KEYCODE_DEL: 96ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onDelete(); 97ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro return true; 98ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 99ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro return false; 100ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 101ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro }; 102ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 103741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen private final Editable.Factory mFormulaEditableFactory = new Editable.Factory() { 104741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen @Override 105741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen public Editable newEditable(CharSequence source) { 1062be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen final boolean isEdited = mCurrentState == CalculatorState.INPUT 1072be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen || mCurrentState == CalculatorState.ERROR; 1082be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen return new CalculatorExpressionBuilder(source, mTokenizer, isEdited); 109741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen } 110741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen }; 111741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 1124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorState mCurrentState; 1132be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private CalculatorExpressionTokenizer mTokenizer; 1144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorExpressionEvaluator mEvaluator; 1154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorEditText mFormulaEditText; 1174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorEditText mResultEditText; 1183b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen private ViewPager mPadViewPager; 1194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private View mDeleteButton; 120ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private View mEqualButton; 1214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private View mClearButton; 1224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1235f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private View mCurrentButton; 1244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private Animator mCurrentAnimator; 1254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen protected void onCreate(Bundle savedInstanceState) { 1284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onCreate(savedInstanceState); 1295f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen setContentView(R.layout.activity_calculator); 1304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText = (CalculatorEditText) findViewById(R.id.formula); 1324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText = (CalculatorEditText) findViewById(R.id.result); 1333b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen mPadViewPager = (ViewPager) findViewById(R.id.pad_pager); 1344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton = findViewById(R.id.del); 1354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton = findViewById(R.id.clr); 1364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 137ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mEqualButton = findViewById(R.id.pad_numeric).findViewById(R.id.eq); 138ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (mEqualButton == null || mEqualButton.getVisibility() != View.VISIBLE) { 139ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mEqualButton = findViewById(R.id.pad_operator).findViewById(R.id.eq); 140ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 141ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 1422be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mTokenizer = new CalculatorExpressionTokenizer(this); 1432be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mEvaluator = new CalculatorExpressionEvaluator(mTokenizer); 1442be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 1455f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen savedInstanceState = savedInstanceState == null ? Bundle.EMPTY : savedInstanceState; 1462be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen setState(CalculatorState.values()[ 1472be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen savedInstanceState.getInt(KEY_CURRENT_STATE, CalculatorState.INPUT.ordinal())]); 1482be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mFormulaEditText.setText(mTokenizer.getLocalizedExpression( 1492be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen savedInstanceState.getString(KEY_CURRENT_EXPRESSION, ""))); 1502be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mEvaluator.evaluate(mFormulaEditText.getText(), this); 151741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 152741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen mFormulaEditText.setEditableFactory(mFormulaEditableFactory); 1534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.addTextChangedListener(mFormulaTextWatcher); 154ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mFormulaEditText.setOnKeyListener(mFormulaOnKeyListener); 155fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen mFormulaEditText.setOnTextSizeChangeListener(this); 1564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setOnLongClickListener(this); 1574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen protected void onSaveInstanceState(Bundle outState) { 1614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onSaveInstanceState(outState); 1622be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen outState.putInt(KEY_CURRENT_STATE, mCurrentState.ordinal()); 1632be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen outState.putString(KEY_CURRENT_EXPRESSION, 1642be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mTokenizer.getNormalizedExpression(mFormulaEditText.getText().toString())); 1654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private void setState(CalculatorState state) { 1684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentState != state) { 1694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentState = state; 1704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (state == CalculatorState.RESULT || state == CalculatorState.ERROR) { 1724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setVisibility(View.GONE); 1734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton.setVisibility(View.VISIBLE); 1744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else { 1754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setVisibility(View.VISIBLE); 1764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton.setVisibility(View.GONE); 1774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (state == CalculatorState.ERROR) { 1804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int errorColor = getResources().getColor(R.color.calculator_error_color); 1814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTextColor(errorColor); 1824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor(errorColor); 1838fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen getWindow().setStatusBarColor(errorColor); 1844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else { 1854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTextColor( 1864b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.display_formula_text_color)); 1874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor( 1884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.display_result_text_color)); 1898fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen getWindow().setStatusBarColor( 1904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.calculator_accent_color)); 1914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1963b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen public void onBackPressed() { 1973b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen if (mPadViewPager == null || mPadViewPager.getCurrentItem() == 0) { 1983b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // If the user is currently looking at the first pad (or the pad is not paged), 1993b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // allow the system to handle the Back button. 2003b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen super.onBackPressed(); 2013b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } else { 2023b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // Otherwise, select the previous pad. 2033b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen mPadViewPager.setCurrentItem(mPadViewPager.getCurrentItem() - 1); 2043b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } 2053b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } 2063b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen 2073b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen @Override 2084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onUserInteraction() { 2094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onUserInteraction(); 2104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // If there's an animation in progress, cancel it so the user interaction can be handled 2124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // immediately. 2134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentAnimator != null) { 2144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator.cancel(); 2154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onButtonClick(View view) { 2195f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mCurrentButton = view; 2205f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 2214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen switch (view.getId()) { 2224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.eq: 223ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onEquals(); 2244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.del: 226ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro onDelete(); 2274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.clr: 2295f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onClear(); 2304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_cos: 2324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_ln: 2334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_log: 2344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_sin: 2354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_tan: 2362be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen // Add left parenthesis after functions. 2374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.append(((Button) view).getText() + "("); 2384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen default: 2404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.append(((Button) view).getText()); 2414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 2464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public boolean onLongClick(View view) { 2475f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mCurrentButton = view; 2485f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 2494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (view.getId() == R.id.del) { 2505f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onClear(); 2514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return true; 2524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return false; 2544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 2572be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen public void onEvaluate(String expr, String result, int errorResourceId) { 2584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentState == CalculatorState.INPUT) { 2594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setText(result); 2602be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen } else if (errorResourceId != INVALID_RES_ID) { 2612be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen onError(errorResourceId); 2624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (!TextUtils.isEmpty(result)) { 2634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen onResult(result); 2644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (mCurrentState == CalculatorState.EVALUATE) { 2654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // The current expression cannot be evaluated -> return to the input state. 2664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.INPUT); 2674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 268ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 269ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mFormulaEditText.requestFocus(); 2704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 272fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen @Override 273fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen public void onTextSizeChanged(final TextView textView, float oldSize) { 274fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen if (mCurrentState != CalculatorState.INPUT) { 275fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // Only animate text changes that occur from user input. 276fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen return; 277fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen } 278fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 279fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // Calculate the values needed to perform the scale and translation animations, 280fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // maintaining the same apparent baseline for the displayed text. 281fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float textScale = oldSize / textView.getTextSize(); 282fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float translationX = (1.0f - textScale) * 283fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen (textView.getWidth() / 2.0f - textView.getPaddingEnd()); 284fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float translationY = (1.0f - textScale) * 285fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen (textView.getHeight() / 2.0f - textView.getPaddingBottom()); 286fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 287fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 288fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.playTogether( 289fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.SCALE_X, textScale, 1.0f), 290fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.SCALE_Y, textScale, 1.0f), 291fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, translationX, 0.0f), 292fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.TRANSLATION_Y, translationY, 0.0f)); 29394db720f7daf99923cc8e3d5ba8765b5529913f1Justin Klaassen animatorSet.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); 294fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 295fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.start(); 296fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen } 297fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 298ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private void onEquals() { 299ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (mCurrentState == CalculatorState.INPUT) { 300ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro setState(CalculatorState.EVALUATE); 301ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro mEvaluator.evaluate(mFormulaEditText.getText(), this); 302ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 303ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 304ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 305ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro private void onDelete() { 306ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro // Delete works like backspace; remove the last character from the expression. 307ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro final Editable formulaText = mFormulaEditText.getEditableText(); 308ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro final int formulaLength = formulaText.length(); 309ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro if (formulaLength > 0) { 310ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro formulaText.delete(formulaLength - 1, formulaLength); 311ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 312ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro } 313ad8e88a5d28ba7f5b8dfa63f92b00b3b96ada360Budi Kusmiantoro 3145f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void reveal(View sourceView, int colorRes, AnimatorListener listener) { 3158fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final View displayView = findViewById(R.id.display); 3168fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final View decorView = getWindow().getDecorView(); 3178fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen 3188fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final Rect displayRect = new Rect(); 3198fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen displayView.getGlobalVisibleRect(displayRect); 3205f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3215f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen // Make reveal cover the display and status bar. 3225f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final View revealView = new View(this); 3238fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setBottom(displayRect.bottom); 3248fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setLeft(displayRect.left); 3258fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setRight(displayRect.right); 3265f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealView.setBackgroundColor(getResources().getColor(colorRes)); 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)); 3465f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealAnimator.addListener(listener); 3474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3485f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final Animator alphaAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f); 3494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen alphaAnimator.setDuration( 3505f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen getResources().getInteger(android.R.integer.config_mediumAnimTime)); 3514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3528fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final ViewGroupOverlay groupOverlay = (ViewGroupOverlay) decorView.getOverlay(); 3534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 3545f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen animatorSet.play(revealAnimator).before(alphaAnimator); 3554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 3564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.addListener(new AnimatorListenerAdapter() { 3574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3585f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen public void onAnimationStart(Animator animation) { 3598fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen groupOverlay.add(revealView); 3604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationEnd(Animator animator) { 3648fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen groupOverlay.remove(revealView); 3654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = null; 3664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 3684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = animatorSet; 3704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.start(); 3714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3735f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void onClear() { 3745f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen if (TextUtils.isEmpty(mFormulaEditText.getText())) { 3755f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen return; 3765f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3775f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3785f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen reveal(mCurrentButton, R.color.calculator_accent_color, new AnimatorListenerAdapter() { 3795f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen @Override 3805f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen public void onAnimationEnd(Animator animation) { 3815f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mFormulaEditText.getEditableText().clear(); 3825f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3835f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen }); 3845f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3855f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3862be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen private void onError(final int errorResourceId) { 3872be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen if (mCurrentState != CalculatorState.EVALUATE) { 3882be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen // Only animate error on evaluate. 3892be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mResultEditText.setText(errorResourceId); 3902be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen return; 3912be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen } 3922be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen 3935f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen reveal(mCurrentButton, R.color.calculator_error_color, new AnimatorListenerAdapter() { 3945f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen @Override 3955f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen public void onAnimationEnd(Animator animation) { 3965f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen setState(CalculatorState.ERROR); 3972be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mResultEditText.setText(errorResourceId); 3985f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3995f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen }); 4005f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 4015f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 4024b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private void onResult(final String result) { 4034b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Calculate the values needed to perform the scale and translation animations, 4044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // accounting for how the scale will affect the final position of the text. 4054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultScale = 4064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.getVariableTextSize(result) / mResultEditText.getTextSize(); 4074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultTranslationX = (1.0f - resultScale) * 4084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getWidth() / 2.0f - mResultEditText.getPaddingEnd()); 4094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultTranslationY = (1.0f - resultScale) * 4104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getHeight() / 2.0f - mResultEditText.getPaddingBottom()) + 4114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mFormulaEditText.getBottom() - mResultEditText.getBottom()) + 4124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getPaddingBottom() - mFormulaEditText.getPaddingBottom()); 4134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float formulaTranslationY = -mFormulaEditText.getBottom(); 4144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Use a value animator to fade to the final text color over the course of the animation. 4164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int resultTextColor = mResultEditText.getCurrentTextColor(); 4174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int formulaTextColor = mFormulaEditText.getCurrentTextColor(); 4184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final ValueAnimator textColorAnimator = 4194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ValueAnimator.ofObject(new ArgbEvaluator(), resultTextColor, formulaTextColor); 4204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen textColorAnimator.addUpdateListener(new AnimatorUpdateListener() { 4214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 4224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationUpdate(ValueAnimator valueAnimator) { 4234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor((int) valueAnimator.getAnimatedValue()); 4244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 4264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 4284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.playTogether( 4294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen textColorAnimator, 4304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.SCALE_X, resultScale), 4314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.SCALE_Y, resultScale), 4324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_X, resultTranslationX), 4334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_Y, resultTranslationY), 4344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, formulaTranslationY)); 4354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime)); 4364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 4374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.addListener(new AnimatorListenerAdapter() { 4384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 4394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationStart(Animator animation) { 4404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setText(result); 4414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 4444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationEnd(Animator animation) { 4454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Reset all of the values modified during the animation. 4464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor(resultTextColor); 4474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setScaleX(1.0f); 4484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setScaleY(1.0f); 4494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTranslationX(0.0f); 4504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTranslationY(0.0f); 4514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTranslationY(0.0f); 4524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Finally update the formula to use the current result. 4544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setText(result); 4554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.RESULT); 4564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = null; 4584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 4604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 4614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = animatorSet; 4624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.start(); 4634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen} 465