Calculator.java revision 8fff144d6cf5d44b2a8e00b3468334019aa4f8b8
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; 344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.KeyEvent; 354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View; 364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View.OnLongClickListener; 375f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassenimport android.view.ViewAnimationUtils; 388fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassenimport android.view.ViewGroupOverlay; 394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.animation.AccelerateDecelerateInterpolator; 404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.widget.Button; 41fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport android.widget.TextView; 42fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 43fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorEditText.OnTextSizeChangeListener; 44fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorExpressionEvaluator.EvaluateCallback; 454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenpublic class CalculatorActivity extends Activity 47fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen implements OnTextSizeChangeListener, EvaluateCallback, OnLongClickListener { 484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public static final String CALCULATOR_ACTIVITY_CURRENT_STATE = 504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen CalculatorActivity.class.getSimpleName() + "_currentState"; 514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private enum CalculatorState { 534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen INPUT, EVALUATE, RESULT, ERROR 544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private final TextWatcher mFormulaTextWatcher = new TextWatcher() { 574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { 594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onTextChanged(CharSequence charSequence, int start, int count, int after) { 634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void afterTextChanged(Editable editable) { 674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.INPUT); 684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mEvaluator.evaluate(editable, CalculatorActivity.this); 694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }; 714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 72741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen private final Editable.Factory mFormulaEditableFactory = new Editable.Factory() { 73741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen @Override 74741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen public Editable newEditable(CharSequence source) { 75741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen return new CalculatorExpressionBuilder(CalculatorActivity.this, source, 76741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen mCurrentState == CalculatorState.INPUT); 77741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen } 78741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen }; 79741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorState mCurrentState; 814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorExpressionEvaluator mEvaluator; 824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorEditText mFormulaEditText; 844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private CalculatorEditText mResultEditText; 854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 863b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen private ViewPager mPadViewPager; 873b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen 884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private View mDeleteButton; 894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private View mClearButton; 904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 915f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private View mCurrentButton; 924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private Animator mCurrentAnimator; 934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen protected void onCreate(Bundle savedInstanceState) { 964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onCreate(savedInstanceState); 975f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen setContentView(R.layout.activity_calculator); 984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText = (CalculatorEditText) findViewById(R.id.formula); 1004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText = (CalculatorEditText) findViewById(R.id.result); 1014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1023b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen mPadViewPager = (ViewPager) findViewById(R.id.pad_pager); 1033b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen 1044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton = findViewById(R.id.del); 1054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton = findViewById(R.id.clr); 1064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1075f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen savedInstanceState = savedInstanceState == null ? Bundle.EMPTY : savedInstanceState; 108741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen setState(CalculatorState.values()[savedInstanceState.getInt( 109741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen CALCULATOR_ACTIVITY_CURRENT_STATE, CalculatorState.INPUT.ordinal())]); 110741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen mEvaluator = new CalculatorExpressionEvaluator(this); 111741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 112741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen mFormulaEditText.setEditableFactory(mFormulaEditableFactory); 1134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.addTextChangedListener(mFormulaTextWatcher); 114fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen mFormulaEditText.setOnTextSizeChangeListener(this); 115fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 1164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setOnLongClickListener(this); 1174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen protected void onSaveInstanceState(Bundle outState) { 1214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onSaveInstanceState(outState); 1224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen outState.putInt(CALCULATOR_ACTIVITY_CURRENT_STATE, mCurrentState.ordinal()); 1234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private void setState(CalculatorState state) { 1264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentState != state) { 1274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentState = state; 1284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (state == CalculatorState.RESULT || state == CalculatorState.ERROR) { 1304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setVisibility(View.GONE); 1314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton.setVisibility(View.VISIBLE); 1324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else { 1334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mDeleteButton.setVisibility(View.VISIBLE); 1344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mClearButton.setVisibility(View.GONE); 1354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (state == CalculatorState.ERROR) { 1384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int errorColor = getResources().getColor(R.color.calculator_error_color); 1394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTextColor(errorColor); 1404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor(errorColor); 1418fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen getWindow().setStatusBarColor(errorColor); 1424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else { 1434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTextColor( 1444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.display_formula_text_color)); 1454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor( 1464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.display_result_text_color)); 1478fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen getWindow().setStatusBarColor( 1484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getColor(R.color.calculator_accent_color)); 1494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 1543b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen public void onBackPressed() { 1553b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen if (mPadViewPager == null || mPadViewPager.getCurrentItem() == 0) { 1563b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // If the user is currently looking at the first pad (or the pad is not paged), 1573b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // allow the system to handle the Back button. 1583b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen super.onBackPressed(); 1593b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } else { 1603b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen // Otherwise, select the previous pad. 1613b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen mPadViewPager.setCurrentItem(mPadViewPager.getCurrentItem() - 1); 1623b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } 1633b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen } 1643b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen 1653b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen @Override 1664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onUserInteraction() { 1674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super.onUserInteraction(); 1684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // If there's an animation in progress, cancel it so the user interaction can be handled 1704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // immediately. 1714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentAnimator != null) { 1724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator.cancel(); 1734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 1764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onButtonClick(View view) { 1775f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mCurrentButton = view; 1785f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 1794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen switch (view.getId()) { 1804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.eq: 1815a3bbade728daf89454aa0485ca54d74884f4134Justin Klaassen if (mCurrentState == CalculatorState.INPUT) { 1824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.EVALUATE); 1834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mEvaluator.evaluate(mFormulaEditText.getText(), this); 1844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 1854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 1864b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.del: 1874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.dispatchKeyEvent( 1884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); 1894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 1904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.clr: 1915f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onClear(); 1924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 1934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_cos: 1944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_ln: 1954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_log: 1964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_sin: 1974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case R.id.fun_tan: 1984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // add left paren after functions 1994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.append(((Button) view).getText() + "("); 2004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen default: 2024b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.append(((Button) view).getText()); 2034b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 2044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 2084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public boolean onLongClick(View view) { 2095f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mCurrentButton = view; 2105f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 2114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (view.getId() == R.id.del) { 2125f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onClear(); 2134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return true; 2144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return false; 2164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 2194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onEvaluate(String expr, String result, String error) { 2204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (mCurrentState == CalculatorState.INPUT) { 2214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setText(result); 2224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (!TextUtils.isEmpty(error)) { 2235f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen onError(error); 2244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (!TextUtils.isEmpty(result)) { 2254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen onResult(result); 2264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } else if (mCurrentState == CalculatorState.EVALUATE) { 2274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // The current expression cannot be evaluated -> return to the input state. 2284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.INPUT); 2294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 2314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 232fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen @Override 233fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen public void onTextSizeChanged(final TextView textView, float oldSize) { 234fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen if (mCurrentState != CalculatorState.INPUT) { 235fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // Only animate text changes that occur from user input. 236fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen return; 237fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen } 238fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 239fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // Calculate the values needed to perform the scale and translation animations, 240fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen // maintaining the same apparent baseline for the displayed text. 241fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float textScale = oldSize / textView.getTextSize(); 242fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float translationX = (1.0f - textScale) * 243fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen (textView.getWidth() / 2.0f - textView.getPaddingEnd()); 244fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final float translationY = (1.0f - textScale) * 245fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen (textView.getHeight() / 2.0f - textView.getPaddingBottom()); 246fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 247fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 248fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.playTogether( 249fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.SCALE_X, textScale, 1.0f), 250fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.SCALE_Y, textScale, 1.0f), 251fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, translationX, 0.0f), 252fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen ObjectAnimator.ofFloat(textView, View.TRANSLATION_Y, translationY, 0.0f)); 25394db720f7daf99923cc8e3d5ba8765b5529913f1Justin Klaassen animatorSet.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); 254fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 255fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen animatorSet.start(); 256fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen } 257fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen 2585f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void reveal(View sourceView, int colorRes, AnimatorListener listener) { 2598fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final View displayView = findViewById(R.id.display); 2608fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final View decorView = getWindow().getDecorView(); 2618fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen 2628fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final Rect displayRect = new Rect(); 2638fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen displayView.getGlobalVisibleRect(displayRect); 2645f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 2655f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen // Make reveal cover the display and status bar. 2665f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final View revealView = new View(this); 2678fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setBottom(displayRect.bottom); 2688fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setLeft(displayRect.left); 2698fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen revealView.setRight(displayRect.right); 2705f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealView.setBackgroundColor(getResources().getColor(colorRes)); 2715f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 2724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int[] clearLocation = new int[2]; 2734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen sourceView.getLocationInWindow(clearLocation); 2744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen clearLocation[0] += sourceView.getWidth() / 2; 2754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen clearLocation[1] += sourceView.getHeight() / 2; 2764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2775f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final int revealCenterX = clearLocation[0] - revealView.getLeft(); 2785f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final int revealCenterY = clearLocation[1] - revealView.getTop(); 2794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2805f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final double x1_2 = Math.pow(revealView.getLeft() - revealCenterX, 2); 2815f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final double x2_2 = Math.pow(revealView.getRight() - revealCenterX, 2); 2825f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final double y_2 = Math.pow(revealView.getTop() - revealCenterY, 2); 2834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float revealRadius = (float) Math.max(Math.sqrt(x1_2 + y_2), Math.sqrt(x2_2 + y_2)); 2844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2855f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final Animator revealAnimator = 2865f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen ViewAnimationUtils.createCircularReveal(revealView, 2873d6ecaf4d3365eeaff75a4bedb57fbe136cf5f64ztenghui revealCenterX, revealCenterY, 0.0f, revealRadius); 2885f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealAnimator.setDuration( 2894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen getResources().getInteger(android.R.integer.config_longAnimTime)); 2905f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen revealAnimator.addListener(listener); 2914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2925f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen final Animator alphaAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f); 2934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen alphaAnimator.setDuration( 2945f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen getResources().getInteger(android.R.integer.config_mediumAnimTime)); 2954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 2968fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen final ViewGroupOverlay groupOverlay = (ViewGroupOverlay) decorView.getOverlay(); 2974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 2985f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen animatorSet.play(revealAnimator).before(alphaAnimator); 2994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 3004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.addListener(new AnimatorListenerAdapter() { 3014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3025f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen public void onAnimationStart(Animator animation) { 3038fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen groupOverlay.add(revealView); 3044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationEnd(Animator animator) { 3088fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen groupOverlay.remove(revealView); 3094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = null; 3104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 3124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = animatorSet; 3144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.start(); 3154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3175f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void onClear() { 3185f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen if (TextUtils.isEmpty(mFormulaEditText.getText())) { 3195f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen return; 3205f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3215f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3225f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen reveal(mCurrentButton, R.color.calculator_accent_color, new AnimatorListenerAdapter() { 3235f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen @Override 3245f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen public void onAnimationEnd(Animator animation) { 3255f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mFormulaEditText.getEditableText().clear(); 3265f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3275f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen }); 3285f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3295f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3305f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen private void onError(final String error) { 3315f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen reveal(mCurrentButton, R.color.calculator_error_color, new AnimatorListenerAdapter() { 3325f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen @Override 3335f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen public void onAnimationEnd(Animator animation) { 3345f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen setState(CalculatorState.ERROR); 3355f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen mResultEditText.setText(error); 3365f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3375f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen }); 3385f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen } 3395f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen 3404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private void onResult(final String result) { 3414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Calculate the values needed to perform the scale and translation animations, 3424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // accounting for how the scale will affect the final position of the text. 3434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultScale = 3444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.getVariableTextSize(result) / mResultEditText.getTextSize(); 3454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultTranslationX = (1.0f - resultScale) * 3464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getWidth() / 2.0f - mResultEditText.getPaddingEnd()); 3474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float resultTranslationY = (1.0f - resultScale) * 3484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getHeight() / 2.0f - mResultEditText.getPaddingBottom()) + 3494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mFormulaEditText.getBottom() - mResultEditText.getBottom()) + 3504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen (mResultEditText.getPaddingBottom() - mFormulaEditText.getPaddingBottom()); 3514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final float formulaTranslationY = -mFormulaEditText.getBottom(); 3524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Use a value animator to fade to the final text color over the course of the animation. 3544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int resultTextColor = mResultEditText.getCurrentTextColor(); 3554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int formulaTextColor = mFormulaEditText.getCurrentTextColor(); 3564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final ValueAnimator textColorAnimator = 3574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ValueAnimator.ofObject(new ArgbEvaluator(), resultTextColor, formulaTextColor); 3584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen textColorAnimator.addUpdateListener(new AnimatorUpdateListener() { 3594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationUpdate(ValueAnimator valueAnimator) { 3614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor((int) valueAnimator.getAnimatedValue()); 3624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 3644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final AnimatorSet animatorSet = new AnimatorSet(); 3664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.playTogether( 3674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen textColorAnimator, 3684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.SCALE_X, resultScale), 3694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.SCALE_Y, resultScale), 3704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_X, resultTranslationX), 3714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_Y, resultTranslationY), 3724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, formulaTranslationY)); 3734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime)); 3744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); 3754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.addListener(new AnimatorListenerAdapter() { 3764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationStart(Animator animation) { 3784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setText(result); 3794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 3824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public void onAnimationEnd(Animator animation) { 3834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Reset all of the values modified during the animation. 3844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTextColor(resultTextColor); 3854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setScaleX(1.0f); 3864b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setScaleY(1.0f); 3874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTranslationX(0.0f); 3884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mResultEditText.setTranslationY(0.0f); 3894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setTranslationY(0.0f); 3904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // Finally update the formula to use the current result. 3924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mFormulaEditText.setText(result); 3934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen setState(CalculatorState.RESULT); 3944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = null; 3964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 3974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen }); 3984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 3994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mCurrentAnimator = animatorSet; 4004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen animatorSet.start(); 4014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 4024b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen} 403