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