1b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project/* 2b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * 4b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * you may not use this file except in compliance with the License. 6b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * You may obtain a copy of the License at 7b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * 8b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * 10b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * See the License for the specific language governing permissions and 14b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project * limitations under the License. 15b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project */ 16b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 17b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectpackage com.android.calculator2; 18b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 19582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikovimport com.android.calculator2.CalculatorDisplay.Scroll; 20582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 21520cbbb8a5cb728eb9244a9c2ef5c917b56be756Mindy Pereiraimport android.text.TextUtils; 22b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectimport android.view.KeyEvent; 23b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectimport android.widget.EditText; 24b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectimport android.content.Context; 25caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereiraimport android.content.res.Resources; 26b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 27caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereiraimport java.util.HashMap; 2857fa18e9f76005d29cf1708017259d3527e68ca4Mindy Pereiraimport java.util.Locale; 29caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereiraimport java.util.Map.Entry; 30caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereiraimport java.util.Set; 3157fa18e9f76005d29cf1708017259d3527e68ca4Mindy Pereira 32b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectimport org.javia.arity.Symbols; 33b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectimport org.javia.arity.SyntaxException; 34b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 35b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Projectclass Logic { 36b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private CalculatorDisplay mDisplay; 37b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private Symbols mSymbols = new Symbols(); 38b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private History mHistory; 39b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private String mResult = ""; 40b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private boolean mIsError = false; 41e08c8309119c462f04ec33746d63b895e4f0417dMihai Preda private int mLineLength = 0; 42b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 43b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private static final String INFINITY_UNICODE = "\u221e"; 44b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 45582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov public static final String MARKER_EVALUATE_ON_RESUME = "?"; 46582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 47c249f2edd5d7e03cae1970576e5909d012e0166eVikram Aggarwal // the two strings below are the result of Double.toString() for Infinity & NaN 48b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project // they are not output to the user and don't require internationalization 492501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov private static final String INFINITY = "Infinity"; 50b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private static final String NAN = "NaN"; 51b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 52b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project static final char MINUS = '\u2212'; 53b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 54b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private final String mErrorString; 55b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 562501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov public final static int DELETE_MODE_BACKSPACE = 0; 572501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov public final static int DELETE_MODE_CLEAR = 1; 582501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 592501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov private int mDeleteMode = DELETE_MODE_BACKSPACE; 602501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 612501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov public interface Listener { 622501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov void onDeleteModeChange(); 632501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov } 642501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 652501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov private Listener mListener; 66caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira private Context mContext; 67caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira private Set<Entry<String, String>> mTranslationsSet; 682501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 692501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov Logic(Context context, History history, CalculatorDisplay display) { 70caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira mContext = context; 71caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira mErrorString = mContext.getResources().getString(R.string.error); 72b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mHistory = history; 73b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay = display; 74b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay.setLogic(this); 75b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 76b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 772501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov public void setListener(Listener listener) { 782501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov this.mListener = listener; 792501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov } 802501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 812501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov public void setDeleteMode(int mode) { 822501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov if (mDeleteMode != mode) { 832501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov mDeleteMode = mode; 842501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov mListener.onDeleteModeChange(); 852501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov } 862501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov } 872501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 882501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov public int getDeleteMode() { 892501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov return mDeleteMode; 902501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov } 912501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 92e08c8309119c462f04ec33746d63b895e4f0417dMihai Preda void setLineLength(int nDigits) { 93e08c8309119c462f04ec33746d63b895e4f0417dMihai Preda mLineLength = nDigits; 94e08c8309119c462f04ec33746d63b895e4f0417dMihai Preda } 95e08c8309119c462f04ec33746d63b895e4f0417dMihai Preda 96b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project boolean eatHorizontalMove(boolean toLeft) { 97b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project EditText editText = mDisplay.getEditText(); 98b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project int cursorPos = editText.getSelectionStart(); 992501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov return toLeft ? cursorPos == 0 : cursorPos >= editText.length(); 100b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 101b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 102b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private String getText() { 103b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project return mDisplay.getText().toString(); 104b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 105b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 106b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void insert(String delta) { 107c7e6cba324ca1b7e23a28cb86f4146568c1e8cb4Dmitri Plotnikov mDisplay.insert(delta); 1082501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov setDeleteMode(DELETE_MODE_BACKSPACE); 109b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 110b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 1119e131447a0270f66f025147a243a1fda0e3fea14Mindy Pereira public void onTextChanged() { 1129e131447a0270f66f025147a243a1fda0e3fea14Mindy Pereira setDeleteMode(DELETE_MODE_BACKSPACE); 1139e131447a0270f66f025147a243a1fda0e3fea14Mindy Pereira } 1149e131447a0270f66f025147a243a1fda0e3fea14Mindy Pereira 115582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov public void resumeWithHistory() { 116582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov clearWithHistory(false); 117b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 118b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 119b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private void clearWithHistory(boolean scroll) { 120582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov String text = mHistory.getText(); 121582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (MARKER_EVALUATE_ON_RESUME.equals(text)) { 122582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (!mHistory.moveToPrevious()) { 123582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov text = ""; 124582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 125582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov text = mHistory.getText(); 126582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov evaluateAndShowResult(text, CalculatorDisplay.Scroll.NONE); 127582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } else { 128582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mResult = ""; 129582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mDisplay.setText( 130582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov text, scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE); 131582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mIsError = false; 132582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 133b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 134b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 135b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project private void clear(boolean scroll) { 13657a15b2b8d73c3f3edcbbbc1f9e2c450e3ec9538Andrew Flynn mHistory.enter(""); 137b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay.setText("", scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE); 138b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project cleared(); 139b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 140b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 141b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void cleared() { 142b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mResult = ""; 143b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mIsError = false; 144b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project updateHistory(); 1452501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov 1462501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov setDeleteMode(DELETE_MODE_BACKSPACE); 147b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 148b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 149b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project boolean acceptInsert(String delta) { 150b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project String text = getText(); 151b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project return !mIsError && 1522501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov (!mResult.equals(text) || 153b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project isOperator(delta) || 154b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay.getSelectionStart() != text.length()); 155b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 156b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 157b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void onDelete() { 158b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (getText().equals(mResult) || mIsError) { 159b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project clear(false); 160b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } else { 161b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay.dispatchKeyEvent(new KeyEvent(0, KeyEvent.KEYCODE_DEL)); 162b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mResult = ""; 163b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 164b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 165b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 166b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void onClear() { 1672501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov clear(mDeleteMode == DELETE_MODE_CLEAR); 168b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 169b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 170b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void onEnter() { 1712501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov if (mDeleteMode == DELETE_MODE_CLEAR) { 172582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov clearWithHistory(false); // clear after an Enter on result 173b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } else { 174582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov evaluateAndShowResult(getText(), CalculatorDisplay.Scroll.UP); 175582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 176582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 177582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 178582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov public void evaluateAndShowResult(String text, Scroll scroll) { 179582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov try { 180582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov String result = evaluate(text); 181582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (!text.equals(result)) { 182582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mHistory.enter(text); 183582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mResult = result; 184582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mDisplay.setText(mResult, scroll); 1852501811e0d216bce30ce01823ed1a8191333d4c1Dmitri Plotnikov setDeleteMode(DELETE_MODE_CLEAR); 186b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 187582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } catch (SyntaxException e) { 188582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mIsError = true; 189582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mResult = mErrorString; 190582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mDisplay.setText(mResult, scroll); 191582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov setDeleteMode(DELETE_MODE_CLEAR); 192b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 193b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 194b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 195b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void onUp() { 196b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project String text = getText(); 197b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (!text.equals(mResult)) { 198b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mHistory.update(text); 199b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 200b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (mHistory.moveToPrevious()) { 201b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.DOWN); 202b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 203b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 204b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 205b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void onDown() { 206b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project String text = getText(); 207b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (!text.equals(mResult)) { 208b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mHistory.update(text); 209b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 210b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (mHistory.moveToNext()) { 211b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.UP); 212b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 213b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 214b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 215b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project void updateHistory() { 216582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov String text = getText(); 217520cbbb8a5cb728eb9244a9c2ef5c917b56be756Mindy Pereira // Don't set the ? marker for empty text or the error string. 218520cbbb8a5cb728eb9244a9c2ef5c917b56be756Mindy Pereira // There is no need to evaluate those later. 219520cbbb8a5cb728eb9244a9c2ef5c917b56be756Mindy Pereira if (!TextUtils.isEmpty(text) && !TextUtils.equals(text, mErrorString) 220520cbbb8a5cb728eb9244a9c2ef5c917b56be756Mindy Pereira && text.equals(mResult)) { 221582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mHistory.update(MARKER_EVALUATE_ON_RESUME); 222582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } else { 223582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mHistory.update(getText()); 224582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 225b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 226b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 227b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project String evaluate(String input) throws SyntaxException { 228b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (input.trim().equals("")) { 229b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project return ""; 230b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 231b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 232b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project // drop final infix operators (they can only result in error) 233b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project int size = input.length(); 234b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project while (size > 0 && isOperator(input.charAt(size - 1))) { 235b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project input = input.substring(0, size - 1); 236b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project --size; 237b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 238caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira // Find and replace any translated mathematical functions. 239caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira input = replaceTranslations(input); 240582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov double value = mSymbols.eval(input); 241582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 242582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov String result = ""; 243582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov for (int precision = mLineLength; precision > 6; precision--) { 244582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov result = tryFormattingWithPrecision(value, precision); 245582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (result.length() <= mLineLength) { 246582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov break; 247582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 248582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 249582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov return result.replace('-', MINUS).replace(INFINITY, INFINITY_UNICODE); 250582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 251582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 252caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira private void addTranslation(HashMap<String, String> map, int t, int m) { 253caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira Resources res = mContext.getResources(); 254caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira String translated = res.getString(t); 255caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira String math = res.getString(m); 256caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira if (!TextUtils.equals(translated, math)) { 257caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira map.put(translated, math); 258caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira } 259caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira } 260caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira 261caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira private String replaceTranslations(String input) { 262caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira if (mTranslationsSet == null) { 263caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira HashMap<String, String> map = new HashMap<String, String>(); 264caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira addTranslation(map, R.string.sin, R.string.sin_mathematical_value); 265caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira addTranslation(map, R.string.cos, R.string.cos_mathematical_value); 266caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira addTranslation(map, R.string.tan, R.string.tan_mathematical_value); 26754e8b090cb47e0dfabf5f069f6460e2caacea60fMindy Pereira addTranslation(map, R.string.e, R.string.e_mathematical_value); 26854e8b090cb47e0dfabf5f069f6460e2caacea60fMindy Pereira addTranslation(map, R.string.ln, R.string.ln_mathematical_value); 26954e8b090cb47e0dfabf5f069f6460e2caacea60fMindy Pereira addTranslation(map, R.string.lg, R.string.lg_mathematical_value); 270caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira mTranslationsSet = map.entrySet(); 271caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira } 272caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira for (Entry<String, String> entry : mTranslationsSet) { 273caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira input = input.replace(entry.getKey(), entry.getValue()); 274caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira } 275caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira return input; 276caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira } 277caccbfbeaf0c42b86b6e26ff48c18c4fc136e28fMindy Pereira 278582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov private String tryFormattingWithPrecision(double value, int precision) { 279582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov // The standard scientific formatter is basically what we need. We will 280582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov // start with what it produces and then massage it a bit. 28157fa18e9f76005d29cf1708017259d3527e68ca4Mindy Pereira String result = String.format(Locale.US, "%" + mLineLength + "." + precision + "g", value); 282b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project if (result.equals(NAN)) { // treat NaN as Error 283b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project mIsError = true; 284b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project return mErrorString; 285b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 286582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov String mantissa = result; 287582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov String exponent = null; 288582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov int e = result.indexOf('e'); 289582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (e != -1) { 290582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mantissa = result.substring(0, e); 291582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 292582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov // Strip "+" and unnecessary 0's from the exponent 293582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov exponent = result.substring(e + 1); 294582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (exponent.startsWith("+")) { 295582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov exponent = exponent.substring(1); 296582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 297582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov exponent = String.valueOf(Integer.parseInt(exponent)); 298582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } else { 299582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mantissa = result; 300582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 301582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 302582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov int period = mantissa.indexOf('.'); 303582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (period == -1) { 304582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov period = mantissa.indexOf(','); 305582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 306582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (period != -1) { 307582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov // Strip trailing 0's 308582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov while (mantissa.length() > 0 && mantissa.endsWith("0")) { 309582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mantissa = mantissa.substring(0, mantissa.length() - 1); 310582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 311582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (mantissa.length() == period + 1) { 312582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov mantissa = mantissa.substring(0, mantissa.length() - 1); 313582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 314582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 315582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov 316582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov if (exponent != null) { 317582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov result = mantissa + 'e' + exponent; 318582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } else { 319582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov result = mantissa; 320582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov } 321582273d77e6ee8335447cbd524e7b47b851c7b46Dmitri Plotnikov return result; 322b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 323b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 324b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project static boolean isOperator(String text) { 325b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project return text.length() == 1 && isOperator(text.charAt(0)); 326b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 327b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project 328b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project static boolean isOperator(char c) { 329b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project //plus minus times div 330b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project return "+\u2212\u00d7\u00f7/*".indexOf(c) != -1; 331b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project } 332b301ed2e1720fc9190eaf99ab33b5f49eabcebc5The Android Open Source Project} 333