summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAnnie Chin <afchin@google.com>2016-11-07 16:04:33 -0800
committerAnnie Chin <afchin@google.com>2016-11-17 09:55:58 -0800
commit06fd3cf86f20a8b927c8b57ef9e94ee48bee46ff (patch)
tree4621e51e2c506f6824854e4fc8dcf827751b7818 /src
parentab657d463740bfc4322f1c06da80bea9c14e993c (diff)
downloadandroid_packages_apps_ExactCalculator-06fd3cf86f20a8b927c8b57ef9e94ee48bee46ff.tar.gz
android_packages_apps_ExactCalculator-06fd3cf86f20a8b927c8b57ef9e94ee48bee46ff.tar.bz2
android_packages_apps_ExactCalculator-06fd3cf86f20a8b927c8b57ef9e94ee48bee46ff.zip
Integrate database with history.
Bug: 31623549 Note: This CL operates under the assumption that there is something in the current expression field (handling for various states of CalculatorDisplay in ag/1613446) Change-Id: I70992067ddc9c5eec079f00604549727787e26fe
Diffstat (limited to 'src')
-rw-r--r--src/com/android/calculator2/AlertDialogFragment.java7
-rw-r--r--src/com/android/calculator2/Calculator.java19
-rw-r--r--src/com/android/calculator2/CalculatorExpr.java5
-rw-r--r--src/com/android/calculator2/CalculatorResult.java12
-rw-r--r--src/com/android/calculator2/Evaluator.java20
-rw-r--r--src/com/android/calculator2/HistoryAdapter.java61
-rw-r--r--src/com/android/calculator2/HistoryFragment.java47
-rw-r--r--src/com/android/calculator2/HistoryItem.java19
8 files changed, 137 insertions, 53 deletions
diff --git a/src/com/android/calculator2/AlertDialogFragment.java b/src/com/android/calculator2/AlertDialogFragment.java
index e098022..12840ae 100644
--- a/src/com/android/calculator2/AlertDialogFragment.java
+++ b/src/com/android/calculator2/AlertDialogFragment.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
+import android.app.FragmentManager;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -78,6 +79,10 @@ public class AlertDialogFragment extends DialogFragment implements DialogInterfa
*/
public static void showMessageDialog(Activity activity, @Nullable CharSequence title,
CharSequence message, @Nullable CharSequence positiveButtonLabel) {
+ final FragmentManager manager = activity.getFragmentManager();
+ if (manager == null || manager.isDestroyed()) {
+ return;
+ }
final AlertDialogFragment dialogFragment = new AlertDialogFragment();
final Bundle args = new Bundle();
args.putCharSequence(KEY_MESSAGE, message);
@@ -87,7 +92,7 @@ public class AlertDialogFragment extends DialogFragment implements DialogInterfa
}
args.putCharSequence(KEY_TITLE, title);
dialogFragment.setArguments(args);
- dialogFragment.show(activity.getFragmentManager(), null /* tag */);
+ dialogFragment.show(manager, null /* tag */);
}
public AlertDialogFragment() {
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index 8aac061..a5d2e92 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -33,6 +33,7 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.app.ActionBar;
import android.app.Activity;
+import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.ClipData;
import android.content.DialogInterface;
@@ -189,7 +190,7 @@ public class Calculator extends Activity
@Override
public void onClosed() {
- getFragmentManager().popBackStack();
+ popFragmentBackstack();
}
@Override
@@ -308,7 +309,7 @@ public class Calculator extends Activity
findViewById(R.id.op_sqr)
};
- mEvaluator = new Evaluator(this);
+ mEvaluator = Evaluator.getInstance(this);
mResultText.setEvaluator(mEvaluator, Evaluator.MAIN_INDEX);
KeyMaps.setActivity(this);
@@ -500,7 +501,7 @@ public class Calculator extends Activity
if (mDragLayout.isOpen()) {
// Close the layout and remove the fragment.
mDragLayout.setClosed();
- getFragmentManager().popBackStack();
+ popFragmentBackstack();
return;
}
if (mPadViewPager != null && mPadViewPager.getCurrentItem() != 0) {
@@ -623,6 +624,13 @@ public class Calculator extends Activity
}
}
+ private void popFragmentBackstack() {
+ final FragmentManager manager = getFragmentManager();
+ if (manager == null || manager.isDestroyed()) {
+ return;
+ }
+ manager.popBackStack();
+ }
/**
* Switch to INPUT from RESULT state in response to input of the specified button_id.
* View.NO_ID is treated as an incomplete function id.
@@ -1176,6 +1184,10 @@ public class Calculator extends Activity
}
private void showHistoryFragment(int transit) {
+ final FragmentManager manager = getFragmentManager();
+ if (manager == null || manager.isDestroyed()) {
+ return;
+ }
if (!mDragLayout.isOpen()) {
getFragmentManager().beginTransaction()
.replace(R.id.history_frame, mHistoryFragment, HistoryFragment.TAG)
@@ -1183,6 +1195,7 @@ public class Calculator extends Activity
.addToBackStack(HistoryFragment.TAG)
.commit();
}
+ // TODO: pass current scroll position of result
}
private void displayMessage(String title, String message) {
diff --git a/src/com/android/calculator2/CalculatorExpr.java b/src/com/android/calculator2/CalculatorExpr.java
index f20d2bf..c6eb9af 100644
--- a/src/com/android/calculator2/CalculatorExpr.java
+++ b/src/com/android/calculator2/CalculatorExpr.java
@@ -21,15 +21,12 @@ import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.TtsSpan;
-import android.text.style.TtsSpan.TextBuilder;
-import java.math.BigInteger;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
/**
* A mathematical expression represented as a sequence of "tokens".
diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java
index caf72fe..29c20f7 100644
--- a/src/com/android/calculator2/CalculatorResult.java
+++ b/src/com/android/calculator2/CalculatorResult.java
@@ -303,6 +303,18 @@ public class CalculatorResult extends AlignedTextView implements MenuItem.OnMenu
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ if (mEvaluator != null) {
+ final CalculatorExpr expr = mEvaluator.getExpr(mIndex);
+ if (expr != null && expr.hasInterestingOps()) {
+ mEvaluator.requireResult(mIndex, this, this);
+ }
+ }
+ }
+
// From Evaluator.CharMetricsInfo.
@Override
public float separatorChars(String s, int len) {
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index d73534f..8f12ce1 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -17,14 +17,13 @@
package com.android.calculator2;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.VisibleForTesting;
+import android.text.Spannable;
import android.util.Log;
import com.hp.creals.CR;
@@ -38,11 +37,11 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.Date;
import java.util.Random;
import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
/**
* This implements the calculator evaluation logic.
@@ -98,6 +97,15 @@ import java.util.TimeZone;
*/
public class Evaluator implements CalculatorExpr.ExprResolver {
+ private static Evaluator evaluator;
+
+ public static Evaluator getInstance(Calculator calculator) {
+ if (evaluator == null) {
+ evaluator = new Evaluator(calculator);
+ }
+ return evaluator;
+ }
+
public interface EvaluationListener {
/**
* Called if evaluation was explicitly cancelled or evaluation timed out.
@@ -1731,6 +1739,10 @@ public class Evaluator implements CalculatorExpr.ExprResolver {
return getExpr(index).toSpannableStringBuilder(mActivity).toString();
}
+ public Spannable getExprAsSpannable(long index) {
+ return getExpr(index).toSpannableStringBuilder(mActivity);
+ }
+
/**
* Generate a String representation of all expressions in the database.
* Debugging only.
diff --git a/src/com/android/calculator2/HistoryAdapter.java b/src/com/android/calculator2/HistoryAdapter.java
index 25c7044..19aa05b 100644
--- a/src/com/android/calculator2/HistoryAdapter.java
+++ b/src/com/android/calculator2/HistoryAdapter.java
@@ -23,7 +23,6 @@ import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
-import java.util.Calendar;
import java.util.List;
/**
@@ -34,20 +33,17 @@ public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHold
private static final int EMPTY_VIEW_TYPE = 0;
private static final int HISTORY_VIEW_TYPE = 1;
- private final List<HistoryItem> mDataSet = new ArrayList<>();
- private String mCurrentExpression;
-
- public HistoryAdapter(int[] dataset, String currentExpression) {
- mCurrentExpression = currentExpression;
- // Temporary dataset
- final Calendar calendar = Calendar.getInstance();
- for (int i: dataset) {
- calendar.set(2016, 10, i);
- mDataSet.add(new HistoryItem(calendar.getTimeInMillis(), Integer.toString(i) + "+1",
- Integer.toString(i+1)));
- }
- // Temporary: just testing the empty view placeholder
- mDataSet.add(new HistoryItem());
+ private final Evaluator mEvaluator;
+ /* Text/accessibility descriptor for the current expression item. */
+ private final String mCurrentExpressionDescription;
+
+ private List<HistoryItem> mDataSet;
+
+ public HistoryAdapter(Calculator calculator, ArrayList<HistoryItem> dataSet,
+ String currentExpressionDescription) {
+ mEvaluator = Evaluator.getInstance(calculator);
+ mDataSet = dataSet;
+ mCurrentExpressionDescription = currentExpressionDescription;
}
@Override
@@ -64,21 +60,23 @@ public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHold
}
@Override
- public void onBindViewHolder(HistoryAdapter.ViewHolder holder, int position) {
+ public void onBindViewHolder(final HistoryAdapter.ViewHolder holder, int position) {
final HistoryItem item = mDataSet.get(position);
if (item.isEmptyView()) {
return;
}
- if (!isCurrentExpressionItem(position)) {
+
+ holder.mFormula.setText(item.getFormula());
+ // Note: HistoryItems that are not the current expression will always have interesting ops.
+ holder.mResult.setEvaluator(mEvaluator, item.getId());
+ if (isCurrentExpressionItem(position)) {
+ holder.mDate.setText(mCurrentExpressionDescription);
+ holder.mDate.setContentDescription(mCurrentExpressionDescription);
+ } else {
holder.mDate.setText(item.getDateString());
holder.mDate.setContentDescription(item.getDateDescription());
- } else {
- holder.mDate.setText(mCurrentExpression);
- holder.mDate.setContentDescription(mCurrentExpression);
}
- holder.mFormula.setText(item.getFormula());
- holder.mResult.setText(item.getResult());
}
@Override
@@ -88,12 +86,23 @@ public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHold
holder.mFormula.setText(null);
holder.mResult.setText(null);
+ // TODO: Only cancel the calculation for the recycled view
+ mEvaluator.cancelAll(true);
+
super.onViewRecycled(holder);
}
@Override
public int getItemViewType(int position) {
- return mDataSet.get(position).isEmptyView() ? EMPTY_VIEW_TYPE : HISTORY_VIEW_TYPE;
+ HistoryItem item = mDataSet.get(position);
+
+ // lazy-fill the data set
+ if (item == null) {
+ item = new HistoryItem(position, mEvaluator.getTimeStamp(position),
+ mEvaluator.getExprAsSpannable(position));
+ mDataSet.add(position, item);
+ }
+ return item.isEmptyView() ? EMPTY_VIEW_TYPE : HISTORY_VIEW_TYPE;
}
@Override
@@ -102,7 +111,11 @@ public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHold
}
private boolean isCurrentExpressionItem(int position) {
- return position == mDataSet.size() - 1;
+ return position == 0;
+ }
+
+ public void setDataSet(ArrayList<HistoryItem> dataSet) {
+ mDataSet = dataSet;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
diff --git a/src/com/android/calculator2/HistoryFragment.java b/src/com/android/calculator2/HistoryFragment.java
index 984ee82..15bf161 100644
--- a/src/com/android/calculator2/HistoryFragment.java
+++ b/src/com/android/calculator2/HistoryFragment.java
@@ -30,6 +30,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
+import java.util.ArrayList;
+
public class HistoryFragment extends Fragment {
public static final String TAG = "HistoryFragment";
@@ -48,6 +50,9 @@ public class HistoryFragment extends Fragment {
@Override
public void onClosed() {
+ // TODO: only cancel historical evaluations
+ mEvaluator.cancelAll(true);
+
mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
}
@@ -78,13 +83,15 @@ public class HistoryFragment extends Fragment {
private RecyclerView mRecyclerView;
private HistoryAdapter mAdapter;
+ private Evaluator mEvaluator;
+
+ private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // Temporary data
- final int[] testArray = {7};
- mAdapter = new HistoryAdapter(testArray,
+ mAdapter = new HistoryAdapter((Calculator) getActivity(), mDataSet,
getContext().getResources().getString(R.string.title_current_expression));
}
@@ -117,7 +124,6 @@ public class HistoryFragment extends Fragment {
getActivity().onBackPressed();
}
});
-
return view;
}
@@ -129,6 +135,33 @@ public class HistoryFragment extends Fragment {
final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
dragLayout.removeDragCallback(mDragCallback);
dragLayout.addDragCallback(mDragCallback);
+
+ mEvaluator = Evaluator.getInstance((Calculator) getActivity());
+
+ if (mEvaluator != null) {
+ final long maxIndex = mEvaluator.getMaxIndex();
+
+ final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
+ // Add the current expression as the first element in the list (the layout is reversed
+ // and we want the current expression to be the last one in the recyclerview).
+ newDataSet.add(new HistoryItem(Evaluator.MAIN_INDEX, 0 /* millis*/,
+ mEvaluator.getExprAsSpannable(0)));
+ // We retrieve the current expression separately, so it's excluded from this loop.
+ for (long i = maxIndex; i > 0; --i ) {
+ newDataSet.add(null);
+ }
+ if (maxIndex == 0) {
+ newDataSet.add(new HistoryItem());
+ }
+
+ mDataSet = newDataSet;
+ mAdapter.setDataSet(mDataSet);
+ mAdapter.notifyDataSetChanged();
+
+// // Initialize the current expression element to dimensions that match the display to avoid
+// // flickering and scrolling when elements expand on drag start.
+// mDragController.animateViews(1.0f, mRecyclerView, mAdapter.getItemCount());
+ }
}
@Override
@@ -149,6 +182,8 @@ public class HistoryFragment extends Fragment {
if (dragLayout != null) {
dragLayout.removeDragCallback(mDragCallback);
}
+
+ mEvaluator.cancelAll(true);
super.onDestroy();
}
@@ -160,10 +195,6 @@ public class HistoryFragment extends Fragment {
(CalculatorResult) getActivity().findViewById(R.id.result));
mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
-
- // Initialize the current expression element to dimensions that match the display to avoid
- // flickering and scrolling when elements expand on drag start.
- mDragController.animateViews(1.0f, mRecyclerView, mAdapter.getItemCount());
}
private void clearHistory() {
diff --git a/src/com/android/calculator2/HistoryItem.java b/src/com/android/calculator2/HistoryItem.java
index 17f009f..63f46e9 100644
--- a/src/com/android/calculator2/HistoryItem.java
+++ b/src/com/android/calculator2/HistoryItem.java
@@ -16,6 +16,7 @@
package com.android.calculator2;
+import android.text.Spannable;
import android.text.format.DateFormat;
import java.text.SimpleDateFormat;
@@ -27,20 +28,24 @@ public class HistoryItem {
private static final String dateFormat = "EEEMMMd";
private static final String descriptionFormat = "EEEEMMMMd";
+ private long mId;
private Date mDate;
- private String mFormula;
- private String mResult;
+ private Spannable mFormula;
// This is true only for the "empty history" view.
private final boolean mIsEmpty;
- public HistoryItem(long millis, String formula, String result) {
+ public HistoryItem(long id, long millis, Spannable formula) {
+ mId = id;
mDate = new Date(millis);
mFormula = formula;
- mResult = result;
mIsEmpty = false;
}
+ public long getId() {
+ return mId;
+ }
+
public HistoryItem() {
mIsEmpty = true;
}
@@ -62,11 +67,7 @@ public class HistoryItem {
return new SimpleDateFormat(descriptionPattern, l).format(mDate);
}
- public String getFormula() {
+ public Spannable getFormula() {
return mFormula;
}
-
- public String getResult() {
- return mResult;
- }
} \ No newline at end of file