Merge "Change primary color to match spec." into ub-calculator-euler
diff --git a/res/layout/fragment_history.xml b/res/layout/fragment_history.xml
index 0d8ed9b..78ba4cc 100644
--- a/res/layout/fragment_history.xml
+++ b/res/layout/fragment_history.xml
@@ -32,6 +32,7 @@
         android:minHeight="?android:attr/actionBarSize"
         android:navigationContentDescription="@string/desc_navigate_up"
         android:navigationIcon="?android:attr/homeAsUpIndicator"
+        android:popupTheme="@android:style/ThemeOverlay.Material.Light"
         android:theme="@android:style/ThemeOverlay.Material.Dark.ActionBar"
         android:title="@string/title_history" />
 
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 14f29e1..e270dc8 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -82,6 +82,6 @@
     <string name="desc_navigate_up" msgid="6208699569165589623">"Joan gora"</string>
     <string name="dialog_timeout" msgid="9069768442342329065">"Denbora-muga"</string>
     <string name="dialog_clear" msgid="7137395395908350702">"Memoria eta historia garbitu?"</string>
-    <string name="title_current_expression" msgid="2442754548537900591">"Uneko adierazpena"</string>
+    <string name="title_current_expression" msgid="2442754548537900591">"Adierazpen hau"</string>
     <string name="no_history" msgid="4331262030447527188">"Hutsik dago historia"</string>
 </resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 3ded33a..660b84f 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="1756503303878374382">"കാൽക്കുലേ."</string>
+    <string name="app_name" msgid="1756503303878374382">"കാൽക്കുലേറ്റർ"</string>
     <string name="dec_point" msgid="8920102493070918054">"."</string>
     <string name="mode_deg" msgid="1146123354434332479">"ഡിഗ്രി"</string>
     <string name="mode_rad" msgid="1434228830085760996">"rad"</string>
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index dd1bab3..c149e84 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -934,7 +934,8 @@
         mResultText.onEvaluate(index, initDisplayPrec, msd, leastDigPos, truncatedWholeNumber);
         if (mCurrentState != CalculatorState.INPUT) {
             // In EVALUATE, INIT, or INIT_FOR_RESULT state.
-            onResult(mCurrentState == CalculatorState.EVALUATE);
+            onResult(mCurrentState == CalculatorState.EVALUATE /* animate */,
+                     mCurrentState == CalculatorState.INIT_FOR_RESULT /* previously preserved */);
         }
     }
 
@@ -1156,7 +1157,7 @@
     // formula and result displays back at the end of the animation.  We no longer do that,
     // so that we can continue to properly support scrolling of the result.
     // We assume the result already contains the text to be expanded.
-    private void onResult(boolean animate) {
+    private void onResult(boolean animate, boolean resultWasPreserved) {
         // Calculate the textSize that would be used to display the result in the formula.
         // For scrollable results just use the minimum textSize to maximize the number of digits
         // that are visible on screen.
@@ -1188,10 +1189,15 @@
         // Change the result's textColor to match the formula.
         final int formulaTextColor = mFormulaText.getCurrentTextColor();
 
-        if (animate) {
+        if (resultWasPreserved) {
+            // Result was previously addded to history.
+            mEvaluator.represerve();
+        } else {
             // Add current result to history.
             mEvaluator.preserve(true);
+        }
 
+        if (animate) {
             mResultText.announceForAccessibility(getResources().getString(R.string.desc_eq));
             mResultText.announceForAccessibility(mResultText.getText());
             setState(CalculatorState.ANIMATE);
@@ -1222,7 +1228,6 @@
             mResultText.setTranslationY(resultTranslationY);
             mResultText.setTextColor(formulaTextColor);
             mFormulaContainer.setTranslationY(formulaTranslationY);
-            mEvaluator.represerve();
             setState(CalculatorState.RESULT);
         }
     }
diff --git a/src/com/android/calculator2/CalculatorExpr.java b/src/com/android/calculator2/CalculatorExpr.java
index 321ba5f..18bb6cf 100644
--- a/src/com/android/calculator2/CalculatorExpr.java
+++ b/src/com/android/calculator2/CalculatorExpr.java
@@ -977,7 +977,7 @@
      * Is the current expression worth evaluating?
      */
     public boolean hasInterestingOps() {
-        int last = trailingBinaryOpsStart();
+        final int last = trailingBinaryOpsStart();
         int first = 0;
         if (last > first && isOperatorUnchecked(first, R.id.op_sub)) {
             // Leading minus is not by itself interesting.
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index a90f5ab..148ca28 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -17,6 +17,7 @@
 package com.android.calculator2;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.SharedPreferences;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -101,8 +102,9 @@
 
     public static Evaluator getInstance(Calculator calculator) {
         if (evaluator == null) {
-            evaluator = new Evaluator(calculator);
+            evaluator = new Evaluator(calculator.getApplicationContext());
         }
+        evaluator.mCalculator = calculator;
         return evaluator;
     }
 
@@ -253,7 +255,7 @@
     // estimating exponent size for truncating short representation.
     private static final int EXP_COST = 3;
 
-    private final Calculator mCalculator;
+    private Calculator mCalculator;
 
     //  A hopefully unique name associated with mSaved.
     private String mSavedName;
@@ -334,14 +336,13 @@
         mExprs.put(MAIN_INDEX, expr);
     }
 
-    Evaluator(Calculator calculator) {
-        mCalculator = calculator;
+    Evaluator(Context context) {
         setMainExpr(new ExprInfo(new CalculatorExpr(), false));
         mSavedName = "none";
         mTimeoutHandler = new Handler();
 
-        mExprDB = new ExpressionDB(mCalculator);
-        mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(calculator);
+        mExprDB = new ExpressionDB(context);
+        mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
         mMainExpr.mDegreeMode = mSharedPrefs.getBoolean(KEY_PREF_DEGREE_MODE, false);
         long savedIndex = mSharedPrefs.getLong(KEY_PREF_SAVED_INDEX, 0L);
         long memoryIndex = mSharedPrefs.getLong(KEY_PREF_MEMORY_INDEX, 0L);
@@ -536,7 +537,7 @@
          * Is a computed result too big for decimal conversion?
          */
         private boolean isTooBig(UnifiedReal res) {
-            int maxBits = mRequired ? getMaxResultBits(mExprInfo.mLongTimeout)
+            final int maxBits = mRequired ? getMaxResultBits(mExprInfo.mLongTimeout)
                     : QUICK_MAX_RESULT_BITS;
             return res.approxWholeNumberBitsGreaterThan(maxBits);
         }
@@ -1194,7 +1195,7 @@
                     && ((AsyncEvaluator)(ei.mEvaluator)).mRequired) {
                 // Duplicate request; ignore.
             } else {
-                // Restart evaluator in requested mode, i.e. with longer timeout.
+                // (Re)start evaluator in requested mode, i.e. with longer timeout.
                 cancel(ei, true);
                 evaluateResult(index, listener, cmi, true);
             }
@@ -1374,6 +1375,7 @@
     /**
      * Return an ExprInfo for a copy of the expression with the given index.
      * We remove trailing binary operators in the copy.
+     * mTimeStamp is not copied.
      */
     private ExprInfo copy(long index, boolean copyValue) {
         ExprInfo fromEi = mExprs.get(index);
@@ -1431,6 +1433,7 @@
     /**
      * Add the expression described by the argument to the database.
      * Returns the new row id in the database.
+     * Fills in timestamp in ei, if it was not previously set.
      * If in_history is true, add it with a positive index, so it will appear in the history.
      */
     private long addToDB(boolean in_history, ExprInfo ei) {
@@ -1470,15 +1473,11 @@
      */
     public void represerve() {
         long resultIndex = getMaxIndex();
-        if (mExprs.get(resultIndex) != null) {
-            // We actually didn't lose the cache. Nothing to do.
-            return;
-        }
-        ExprInfo ei = copy(MAIN_INDEX, true);
-        if (resultIndex == MAIN_INDEX) {
-            throw new AssertionError("Should not store main expression");
-        }
-        mExprs.put(resultIndex, ei);
+        // This requires database access only if the local state was preserved, but we
+        // recreated the Evaluator.  That excludes the common cases of device rotation, etc.
+        // TODO: Revisit once we deal with database failures. We could just copy from
+        // MAIN_INDEX instead, but that loses the timestamp.
+        ensureExprIsCached(resultIndex);
     }
 
     /**
diff --git a/src/com/android/calculator2/ExpressionDB.java b/src/com/android/calculator2/ExpressionDB.java
index e1c2d2f..fb7ee04 100644
--- a/src/com/android/calculator2/ExpressionDB.java
+++ b/src/com/android/calculator2/ExpressionDB.java
@@ -205,11 +205,8 @@
     // initialization.
     private Object mLock = new Object();
 
-    private Activity mActivity;
-
-    public ExpressionDB(Activity activity) {
-        mActivity = activity;
-        mExpressionDBHelper = new ExpressionDBHelper(activity);
+    public ExpressionDB(Context context) {
+        mExpressionDBHelper = new ExpressionDBHelper(context);
         AsyncInitializer initializer = new AsyncInitializer();
         // All calls that create background database accesses are made from the UI thread, and
         // use a SERIAL_EXECUTOR. Thus they execute in order.
@@ -536,7 +533,8 @@
             position -= GAP;
         }
         if (position < 0) {
-            throw new AssertionError("Database access out of range");
+            throw new AssertionError("Database access out of range, index = " + index
+                    + " rel. pos. = " + position);
         }
         if (index < 0) {
             // Avoid using mAllCursor to read data that's far away from the current position,