Calculator.java revision 2be4fdbfcd5f16bc12066d1ccac181bca3dfaa7a
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.View;
354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.View.OnLongClickListener;
365f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassenimport android.view.ViewAnimationUtils;
378fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassenimport android.view.ViewGroupOverlay;
384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.view.animation.AccelerateDecelerateInterpolator;
394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.widget.Button;
40fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport android.widget.TextView;
41fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen
42fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorEditText.OnTextSizeChangeListener;
43fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassenimport com.android.calculator2.CalculatorExpressionEvaluator.EvaluateCallback;
444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
4504f79c7a5f46f6c2cf07a164ce352ab54dfe7f47Justin Klaassenpublic class Calculator extends Activity
46fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        implements OnTextSizeChangeListener, EvaluateCallback, OnLongClickListener {
474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
482be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    private static final String NAME = Calculator.class.getName();
492be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen
502be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    // instance state keys
512be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    private static final String KEY_CURRENT_STATE = NAME + "_currentState";
522be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    private static final String KEY_CURRENT_EXPRESSION = NAME + "_currentExpression";
532be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen
542be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    /**
552be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen     * Constant for an invalid resource id.
562be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen     */
572be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    public static final int INVALID_RES_ID = -1;
584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private enum CalculatorState {
604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        INPUT, EVALUATE, RESULT, ERROR
614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private final TextWatcher mFormulaTextWatcher = new TextWatcher() {
644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        @Override
654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        @Override
694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        public void onTextChanged(CharSequence charSequence, int start, int count, int after) {
704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        @Override
734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        public void afterTextChanged(Editable editable) {
744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            setState(CalculatorState.INPUT);
7504f79c7a5f46f6c2cf07a164ce352ab54dfe7f47Justin Klaassen            mEvaluator.evaluate(editable, Calculator.this);
764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    };
784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
79741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen    private final Editable.Factory mFormulaEditableFactory = new Editable.Factory() {
80741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen        @Override
81741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen        public Editable newEditable(CharSequence source) {
822be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen            final boolean isEdited = mCurrentState == CalculatorState.INPUT
832be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                    || mCurrentState == CalculatorState.ERROR;
842be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen            return new CalculatorExpressionBuilder(source, mTokenizer, isEdited);
85741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen        }
86741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen    };
87741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen
884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private CalculatorState mCurrentState;
892be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    private CalculatorExpressionTokenizer mTokenizer;
904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private CalculatorExpressionEvaluator mEvaluator;
914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private CalculatorEditText mFormulaEditText;
934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private CalculatorEditText mResultEditText;
943b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen    private ViewPager mPadViewPager;
954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private View mDeleteButton;
964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private View mClearButton;
974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
985f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen    private View mCurrentButton;
994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private Animator mCurrentAnimator;
1004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    @Override
1024b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    protected void onCreate(Bundle savedInstanceState) {
1034b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        super.onCreate(savedInstanceState);
1045f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        setContentView(R.layout.activity_calculator);
1054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mFormulaEditText = (CalculatorEditText) findViewById(R.id.formula);
1074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mResultEditText = (CalculatorEditText) findViewById(R.id.result);
1083b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen        mPadViewPager = (ViewPager) findViewById(R.id.pad_pager);
1094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mDeleteButton = findViewById(R.id.del);
1104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mClearButton = findViewById(R.id.clr);
1114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1122be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        mTokenizer = new CalculatorExpressionTokenizer(this);
1132be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        mEvaluator = new CalculatorExpressionEvaluator(mTokenizer);
1142be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen
1155f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        savedInstanceState = savedInstanceState == null ? Bundle.EMPTY : savedInstanceState;
1162be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        setState(CalculatorState.values()[
1172be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                savedInstanceState.getInt(KEY_CURRENT_STATE, CalculatorState.INPUT.ordinal())]);
1182be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        mFormulaEditText.setText(mTokenizer.getLocalizedExpression(
1192be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                savedInstanceState.getString(KEY_CURRENT_EXPRESSION, "")));
1202be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        mEvaluator.evaluate(mFormulaEditText.getText(), this);
121741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen
122741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen        mFormulaEditText.setEditableFactory(mFormulaEditableFactory);
1234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mFormulaEditText.addTextChangedListener(mFormulaTextWatcher);
124fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        mFormulaEditText.setOnTextSizeChangeListener(this);
1254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mDeleteButton.setOnLongClickListener(this);
1264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
1274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    @Override
1294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    protected void onSaveInstanceState(Bundle outState) {
1304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        super.onSaveInstanceState(outState);
1312be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        outState.putInt(KEY_CURRENT_STATE, mCurrentState.ordinal());
1322be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        outState.putString(KEY_CURRENT_EXPRESSION,
1332be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                mTokenizer.getNormalizedExpression(mFormulaEditText.getText().toString()));
1344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
1354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private void setState(CalculatorState state) {
1374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        if (mCurrentState != state) {
1384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            mCurrentState = state;
1394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            if (state == CalculatorState.RESULT || state == CalculatorState.ERROR) {
1414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mDeleteButton.setVisibility(View.GONE);
1424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mClearButton.setVisibility(View.VISIBLE);
1434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            } else {
1444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mDeleteButton.setVisibility(View.VISIBLE);
1454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mClearButton.setVisibility(View.GONE);
1464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
1474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            if (state == CalculatorState.ERROR) {
1494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                final int errorColor = getResources().getColor(R.color.calculator_error_color);
1504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.setTextColor(errorColor);
1514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setTextColor(errorColor);
1528fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen                getWindow().setStatusBarColor(errorColor);
1534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            } else {
1544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.setTextColor(
1554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                        getResources().getColor(R.color.display_formula_text_color));
1564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setTextColor(
1574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                        getResources().getColor(R.color.display_result_text_color));
1588fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen                getWindow().setStatusBarColor(
1594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                        getResources().getColor(R.color.calculator_accent_color));
1604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
1614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
1624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
1634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    @Override
1653b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen    public void onBackPressed() {
1663b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen        if (mPadViewPager == null || mPadViewPager.getCurrentItem() == 0) {
1673b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen            // If the user is currently looking at the first pad (or the pad is not paged),
1683b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen            // allow the system to handle the Back button.
1693b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen            super.onBackPressed();
1703b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen        } else {
1713b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen            // Otherwise, select the previous pad.
1723b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen            mPadViewPager.setCurrentItem(mPadViewPager.getCurrentItem() - 1);
1733b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen        }
1743b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen    }
1753b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen
1763b4d13d528a14a0f46e7ae022357dfde90a307adJustin Klaassen    @Override
1774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    public void onUserInteraction() {
1784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        super.onUserInteraction();
1794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        // If there's an animation in progress, cancel it so the user interaction can be handled
1814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        // immediately.
1824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        if (mCurrentAnimator != null) {
1834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            mCurrentAnimator.cancel();
1844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
1854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
1864b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
1874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    public void onButtonClick(View view) {
1885f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        mCurrentButton = view;
1895f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
1904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        switch (view.getId()) {
1914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.eq:
1925a3bbade728daf89454aa0485ca54d74884f4134Justin Klaassen                if (mCurrentState == CalculatorState.INPUT) {
1934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                    setState(CalculatorState.EVALUATE);
1944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                    mEvaluator.evaluate(mFormulaEditText.getText(), this);
1954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                }
1964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                break;
1974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.del:
1982be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                // Delete works like backspace; remove the last character from the expression.
1992be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                final Editable formulaText = mFormulaEditText.getEditableText();
2002be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                final int formulaLength = formulaText.length();
2012be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                if (formulaLength > 0) {
2022be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                    formulaText.delete(formulaLength - 1, formulaLength);
2032be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                }
2044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                break;
2054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.clr:
2065f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen                onClear();
2074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                break;
2084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.fun_cos:
2094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.fun_ln:
2104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.fun_log:
2114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.fun_sin:
2124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            case R.id.fun_tan:
2132be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                // Add left parenthesis after functions.
2144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.append(((Button) view).getText() + "(");
2154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                break;
2164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            default:
2174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.append(((Button) view).getText());
2184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                break;
2194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
2204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
2214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
2224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    @Override
2234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    public boolean onLongClick(View view) {
2245f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        mCurrentButton = view;
2255f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
2264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        if (view.getId() == R.id.del) {
2275f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            onClear();
2284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            return true;
2294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
2304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        return false;
2314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
2324b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
2334b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    @Override
2342be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    public void onEvaluate(String expr, String result, int errorResourceId) {
2354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        if (mCurrentState == CalculatorState.INPUT) {
2364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            mResultEditText.setText(result);
2372be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        } else if (errorResourceId != INVALID_RES_ID) {
2382be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen            onError(errorResourceId);
2394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        } else if (!TextUtils.isEmpty(result)) {
2404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            onResult(result);
2414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        } else if (mCurrentState == CalculatorState.EVALUATE) {
2424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            // The current expression cannot be evaluated -> return to the input state.
2434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            setState(CalculatorState.INPUT);
2444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        }
2454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
2464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
247fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen    @Override
248fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen    public void onTextSizeChanged(final TextView textView, float oldSize) {
249fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        if (mCurrentState != CalculatorState.INPUT) {
250fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen            // Only animate text changes that occur from user input.
251fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen            return;
252fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        }
253fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen
254fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        // Calculate the values needed to perform the scale and translation animations,
255fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        // maintaining the same apparent baseline for the displayed text.
256fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        final float textScale = oldSize / textView.getTextSize();
257fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        final float translationX = (1.0f - textScale) *
258fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen                (textView.getWidth() / 2.0f - textView.getPaddingEnd());
259fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        final float translationY = (1.0f - textScale) *
260fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen                (textView.getHeight() / 2.0f - textView.getPaddingBottom());
261fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen
262fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        final AnimatorSet animatorSet = new AnimatorSet();
263fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        animatorSet.playTogether(
264fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen                ObjectAnimator.ofFloat(textView, View.SCALE_X, textScale, 1.0f),
265fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen                ObjectAnimator.ofFloat(textView, View.SCALE_Y, textScale, 1.0f),
266fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen                ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, translationX, 0.0f),
267fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen                ObjectAnimator.ofFloat(textView, View.TRANSLATION_Y, translationY, 0.0f));
26894db720f7daf99923cc8e3d5ba8765b5529913f1Justin Klaassen        animatorSet.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
269fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
270fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen        animatorSet.start();
271fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen    }
272fed941a1b4b2a3a011b8a17f486060f593db2f3cJustin Klaassen
2735f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen    private void reveal(View sourceView, int colorRes, AnimatorListener listener) {
2748fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        final View displayView = findViewById(R.id.display);
2758fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        final View decorView = getWindow().getDecorView();
2768fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen
2778fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        final Rect displayRect = new Rect();
2788fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        displayView.getGlobalVisibleRect(displayRect);
2795f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
2805f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        // Make reveal cover the display and status bar.
2815f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final View revealView = new View(this);
2828fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        revealView.setBottom(displayRect.bottom);
2838fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        revealView.setLeft(displayRect.left);
2848fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        revealView.setRight(displayRect.right);
2855f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        revealView.setBackgroundColor(getResources().getColor(colorRes));
2865f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
2874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final int[] clearLocation = new int[2];
2884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        sourceView.getLocationInWindow(clearLocation);
2894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        clearLocation[0] += sourceView.getWidth() / 2;
2904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        clearLocation[1] += sourceView.getHeight() / 2;
2914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
2925f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final int revealCenterX = clearLocation[0] - revealView.getLeft();
2935f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final int revealCenterY = clearLocation[1] - revealView.getTop();
2944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
2955f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final double x1_2 = Math.pow(revealView.getLeft() - revealCenterX, 2);
2965f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final double x2_2 = Math.pow(revealView.getRight() - revealCenterX, 2);
2975f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final double y_2 = Math.pow(revealView.getTop() - revealCenterY, 2);
2984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final float revealRadius = (float) Math.max(Math.sqrt(x1_2 + y_2), Math.sqrt(x2_2 + y_2));
2994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3005f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final Animator revealAnimator =
3015f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen                ViewAnimationUtils.createCircularReveal(revealView,
3023d6ecaf4d3365eeaff75a4bedb57fbe136cf5f64ztenghui                        revealCenterX, revealCenterY, 0.0f, revealRadius);
3035f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        revealAnimator.setDuration(
3044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                getResources().getInteger(android.R.integer.config_longAnimTime));
3055f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        revealAnimator.addListener(listener);
3064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3075f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        final Animator alphaAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f);
3084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        alphaAnimator.setDuration(
3095f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen                getResources().getInteger(android.R.integer.config_mediumAnimTime));
3104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3118fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen        final ViewGroupOverlay groupOverlay = (ViewGroupOverlay) decorView.getOverlay();
3124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final AnimatorSet animatorSet = new AnimatorSet();
3135f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        animatorSet.play(revealAnimator).before(alphaAnimator);
3144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
3154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.addListener(new AnimatorListenerAdapter() {
3164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            @Override
3175f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            public void onAnimationStart(Animator animation) {
3188fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen                groupOverlay.add(revealView);
3194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
3204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            @Override
3224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            public void onAnimationEnd(Animator animator) {
3238fff144d6cf5d44b2a8e00b3468334019aa4f8b8Justin Klaassen                groupOverlay.remove(revealView);
3244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mCurrentAnimator = null;
3254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
3264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        });
3274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3284b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mCurrentAnimator = animatorSet;
3294b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.start();
3304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
3314b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3325f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen    private void onClear() {
3335f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        if (TextUtils.isEmpty(mFormulaEditText.getText())) {
3345f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            return;
3355f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        }
3365f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
3375f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        reveal(mCurrentButton, R.color.calculator_accent_color, new AnimatorListenerAdapter() {
3385f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            @Override
3395f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            public void onAnimationEnd(Animator animation) {
3405f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen                mFormulaEditText.getEditableText().clear();
3415f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            }
3425f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        });
3435f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen    }
3445f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
3452be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen    private void onError(final int errorResourceId) {
3462be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        if (mCurrentState != CalculatorState.EVALUATE) {
3472be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen            // Only animate error on evaluate.
3482be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen            mResultEditText.setText(errorResourceId);
3492be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen            return;
3502be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen        }
3512be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen
3525f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        reveal(mCurrentButton, R.color.calculator_error_color, new AnimatorListenerAdapter() {
3535f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            @Override
3545f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            public void onAnimationEnd(Animator animation) {
3555f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen                setState(CalculatorState.ERROR);
3562be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen                mResultEditText.setText(errorResourceId);
3575f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen            }
3585f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen        });
3595f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen    }
3605f2a334a7789cd88e210451ff5cd39bfacfe054eJustin Klaassen
3614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    private void onResult(final String result) {
3624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        // Calculate the values needed to perform the scale and translation animations,
3634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        // accounting for how the scale will affect the final position of the text.
3644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final float resultScale =
3654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.getVariableTextSize(result) / mResultEditText.getTextSize();
3664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final float resultTranslationX = (1.0f - resultScale) *
3674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                (mResultEditText.getWidth() / 2.0f - mResultEditText.getPaddingEnd());
3684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final float resultTranslationY = (1.0f - resultScale) *
3694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                (mResultEditText.getHeight() / 2.0f - mResultEditText.getPaddingBottom()) +
3704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                (mFormulaEditText.getBottom() - mResultEditText.getBottom()) +
3714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                (mResultEditText.getPaddingBottom() - mFormulaEditText.getPaddingBottom());
3724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final float formulaTranslationY = -mFormulaEditText.getBottom();
3734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        // Use a value animator to fade to the final text color over the course of the animation.
3754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final int resultTextColor = mResultEditText.getCurrentTextColor();
3764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final int formulaTextColor = mFormulaEditText.getCurrentTextColor();
3774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final ValueAnimator textColorAnimator =
3784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                ValueAnimator.ofObject(new ArgbEvaluator(), resultTextColor, formulaTextColor);
3794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        textColorAnimator.addUpdateListener(new AnimatorUpdateListener() {
3804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            @Override
3814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            public void onAnimationUpdate(ValueAnimator valueAnimator) {
3824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setTextColor((int) valueAnimator.getAnimatedValue());
3834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
3844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        });
3854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
3864b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        final AnimatorSet animatorSet = new AnimatorSet();
3874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.playTogether(
3884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                textColorAnimator,
3894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                ObjectAnimator.ofFloat(mResultEditText, View.SCALE_X, resultScale),
3904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                ObjectAnimator.ofFloat(mResultEditText, View.SCALE_Y, resultScale),
3914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_X, resultTranslationX),
3924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_Y, resultTranslationY),
3934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, formulaTranslationY));
3944b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
3954b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
3964b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.addListener(new AnimatorListenerAdapter() {
3974b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            @Override
3984b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            public void onAnimationStart(Animator animation) {
3994b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setText(result);
4004b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
4014b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
4024b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            @Override
4034b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            public void onAnimationEnd(Animator animation) {
4044b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                // Reset all of the values modified during the animation.
4054b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setTextColor(resultTextColor);
4064b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setScaleX(1.0f);
4074b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setScaleY(1.0f);
4084b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setTranslationX(0.0f);
4094b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mResultEditText.setTranslationY(0.0f);
4104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.setTranslationY(0.0f);
4114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
4124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                // Finally update the formula to use the current result.
4134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mFormulaEditText.setText(result);
4144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                setState(CalculatorState.RESULT);
4154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
4164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen                mCurrentAnimator = null;
4174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen            }
4184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        });
4194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen
4204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        mCurrentAnimator = animatorSet;
4214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen        animatorSet.start();
4224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen    }
4234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen}
424