summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Boehm <hboehm@google.com>2015-10-11 16:42:21 (GMT)
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-10-11 16:42:21 (GMT)
commitfc6db0729d7f4e4570c9e56d969f4bd983065711 (patch)
treec2ed2de4dee1b6ad0b5ed67676e01947a8da6496
parentd5f67fe2d2ddabecd0618a4bc8ac899cc316ca10 (diff)
parent9192d5c751f2aaf1d18bb9b2f715905ffd9d5925 (diff)
downloadandroid_packages_apps_ExactCalculator-fc6db0729d7f4e4570c9e56d969f4bd983065711.zip
android_packages_apps_ExactCalculator-fc6db0729d7f4e4570c9e56d969f4bd983065711.tar.gz
android_packages_apps_ExactCalculator-fc6db0729d7f4e4570c9e56d969f4bd983065711.tar.bz2
Merge "Cleanup of timeout handling and message" into mnc-dr-dev
-rw-r--r--src/com/android/calculator2/AlertDialogFragment.java54
-rw-r--r--src/com/android/calculator2/Calculator.java17
-rw-r--r--src/com/android/calculator2/Evaluator.java103
3 files changed, 131 insertions, 43 deletions
diff --git a/src/com/android/calculator2/AlertDialogFragment.java b/src/com/android/calculator2/AlertDialogFragment.java
index bb7a50b..49f9549 100644
--- a/src/com/android/calculator2/AlertDialogFragment.java
+++ b/src/com/android/calculator2/AlertDialogFragment.java
@@ -21,22 +21,50 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
+import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.widget.TextView;
-public class AlertDialogFragment extends DialogFragment {
+/**
+ * Display a message with a dismiss putton, and optionally a second button.
+ */
+public class AlertDialogFragment extends DialogFragment implements DialogInterface.OnClickListener {
+
+ public interface OnClickListener {
+ /**
+ * This method will be invoked when a button in the dialog is clicked.
+ *
+ * @param fragment the AlertDialogFragment that received the click
+ * @param which the button that was clicked (e.g.
+ * {@link DialogInterface#BUTTON_POSITIVE}) or the position
+ * of the item clicked
+ */
+ public void onClick(AlertDialogFragment fragment, int which);
+ }
private static final String NAME = AlertDialogFragment.class.getName();
private static final String KEY_MESSAGE = NAME + "_message";
private static final String KEY_BUTTON_NEGATIVE = NAME + "_button_negative";
+ private static final String KEY_BUTTON_POSITIVE = NAME + "_button_positive";
- public static void showMessageDialog(Activity activity, CharSequence message) {
+ /**
+ * Create and show a DialogFragment with the given message.
+ * @param activity originating Activity
+ * @param message displayed message
+ * @param positiveButtonLabel label for second button, if any. If non-null, activity must
+ * implement AlertDialogFragment.OnClickListener to respond.
+ */
+ public static void showMessageDialog(Activity activity, CharSequence message,
+ @Nullable CharSequence positiveButtonLabel) {
+ final AlertDialogFragment dialogFragment = new AlertDialogFragment();
final Bundle args = new Bundle();
args.putCharSequence(KEY_MESSAGE, message);
args.putCharSequence(KEY_BUTTON_NEGATIVE, activity.getString(R.string.dismiss));
-
- final AlertDialogFragment dialogFragment = new AlertDialogFragment();
+ if (positiveButtonLabel != null) {
+ args.putCharSequence(KEY_BUTTON_POSITIVE, positiveButtonLabel);
+ }
dialogFragment.setArguments(args);
dialogFragment.show(activity.getFragmentManager(), null /* tag */);
}
@@ -53,9 +81,21 @@ public class AlertDialogFragment extends DialogFragment {
final TextView textView = (TextView) inflater.inflate(R.layout.dialog_message,
null /* root */);
textView.setText(args.getCharSequence(KEY_MESSAGE));
- return new AlertDialog.Builder(context)
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setView(textView)
- .setNegativeButton(args.getCharSequence(KEY_BUTTON_NEGATIVE), null /* listener */)
- .create();
+ .setNegativeButton(args.getCharSequence(KEY_BUTTON_NEGATIVE), null /* listener */);
+ final CharSequence positiveButtonLabel = args.getCharSequence(KEY_BUTTON_POSITIVE);
+ if (positiveButtonLabel != null) {
+ builder.setPositiveButton(positiveButtonLabel, this);
+ }
+ return builder.create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Activity activity = getActivity();
+ if (activity instanceof AlertDialogFragment.OnClickListener /* always true */) {
+ ((AlertDialogFragment.OnClickListener) activity).onClick(this, which);
+ }
}
}
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index c7e14a4..84f92c8 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -32,7 +32,9 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.app.Activity;
+import android.app.AlertDialog;
import android.content.ClipData;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
@@ -71,7 +73,8 @@ import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
public class Calculator extends Activity
- implements OnTextSizeChangeListener, OnLongClickListener, CalculatorText.OnPasteListener {
+ implements OnTextSizeChangeListener, OnLongClickListener, CalculatorText.OnPasteListener,
+ AlertDialogFragment.OnClickListener {
/**
* Constant for an invalid resource id.
@@ -847,7 +850,15 @@ public class Calculator extends Activity
mFormulaText.setTranslationY(0.0f);
mFormulaText.requestFocus();
- }
+ }
+
+ @Override
+ public void onClick(AlertDialogFragment fragment, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ // Timeout extension request.
+ mEvaluator.setLongTimeOut();
+ }
+ }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -889,7 +900,7 @@ public class Calculator extends Activity
}
private void displayMessage(String s) {
- AlertDialogFragment.showMessageDialog(this, s);
+ AlertDialogFragment.showMessageDialog(this, s, null);
}
private void displayFraction() {
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index fca757d..936d618 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -234,43 +234,65 @@ class Evaluator {
.show();
}
- // Maximum timeout for background computations. Exceeding a few tens of seconds
- // increases the risk of running out of memory and impacting the rest of the system.
- private final long MAX_TIMEOUT = 15000;
+ // Timeout handling.
+ // Expressions are evaluated with a sort timeout or a long timeout.
+ // Each implies different maxima on both computation time and bit length.
+ // We recheck bit length separetly to avoid wasting time on decimal conversions that are
+ // destined to fail.
- // Timeout for requested evaluations, in milliseconds. This is currently not saved and
- // restored with the state; we reset the timeout when the calculator is restarted. We'll call
- // that a feature; others might argue it's a bug.
- private long mTimeout = 2000;
+ /**
+ * Is a long timeout in effect for the main expression?
+ */
+ private boolean mLongTimeout = false;
+
+ /**
+ * Is a long timeout in effect for the saved expression?
+ */
+ private boolean mLongSavedTimeout = false;
+
+ /**
+ * Return the timeout in milliseconds.
+ * @param longTimeout a long timeout is in effect
+ */
+ private long getTimeout(boolean longTimeout) {
+ return longTimeout ? 15000 : 2000;
+ // Exceeding a few tens of seconds increases the risk of running out of memory
+ // and impacting the rest of the system.
+ }
- // Timeout for unrequested, speculative evaluations, in milliseconds.
+ /**
+ * Return the maximum number of bits in the result. Longer results are assumed to time out.
+ * @param longTimeout a long timeout is in effect
+ */
+ private int getMaxResultBits(boolean longTimeout) {
+ return longTimeout ? 350000 : 120000;
+ }
+
+ /**
+ * Timeout for unrequested, speculative evaluations, in milliseconds.
+ */
private final long QUICK_TIMEOUT = 1000;
- private int mMaxResultBits = 120000; // Don't try to display a larger result.
- private final int MAX_MAX_RESULT_BITS = 350000; // Long timeout version.
- private final int QUICK_MAX_RESULT_BITS = 50000; // Instant result version.
+ /**
+ * Maximum result bit length for unrequested, speculative evaluations.
+ */
+ private final int QUICK_MAX_RESULT_BITS = 50000;
private void displayTimeoutMessage() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(mCalculator)
- .setMessage(R.string.timeout)
- .setNegativeButton(R.string.dismiss, null /* listener */);
- if (mTimeout != MAX_TIMEOUT) {
- builder.setPositiveButton(R.string.ok_remove_timeout,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface d, int which) {
- mTimeout = MAX_TIMEOUT;
- mMaxResultBits = MAX_MAX_RESULT_BITS;
- }
- });
- }
- builder.show();
+ AlertDialogFragment.showMessageDialog(mCalculator, mCalculator.getString(R.string.timeout),
+ (mLongTimeout ? null : mCalculator.getString(R.string.ok_remove_timeout)));
}
- // Compute initial cache contents and result when we're good and ready.
- // We leave the expression display up, with scrolling
- // disabled, until this computation completes.
- // Can result in an error display if something goes wrong.
- // By default we set a timeout to catch runaway computations.
+ public void setLongTimeOut() {
+ mLongTimeout = true;
+ }
+
+ /**
+ * Compute initial cache contents and result when we're good and ready.
+ * We leave the expression display up, with scrolling disabled, until this computation
+ * completes. Can result in an error display if something goes wrong. By default we set a
+ * timeout to catch runaway computations.
+ */
class AsyncEvaluator extends AsyncTask<Void, Void, InitialResult> {
private boolean mDm; // degrees
private boolean mRequired; // Result was requested by user.
@@ -299,7 +321,7 @@ class Evaluator {
}
@Override
protected void onPreExecute() {
- long timeout = mRequired ? mTimeout : QUICK_TIMEOUT;
+ long timeout = mRequired ? getTimeout(mLongTimeout) : QUICK_TIMEOUT;
mTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -312,7 +334,7 @@ class Evaluator {
* Is a computed result too big for decimal conversion?
*/
private boolean isTooBig(CalculatorExpr.EvalResult res) {
- int maxBits = mRequired ? mMaxResultBits : QUICK_MAX_RESULT_BITS;
+ int maxBits = mRequired ? getMaxResultBits(mLongTimeout) : QUICK_MAX_RESULT_BITS;
if (res.ratVal != null) {
return res.ratVal.wholeNumberBits() > maxBits;
} else {
@@ -821,11 +843,17 @@ class Evaluator {
mMsdIndex = INVALID_MSD;
}
- public void clear() {
+
+ private void clearPreservingTimeout() {
mExpr.clear();
clearCache();
}
+ public void clear() {
+ clearPreservingTimeout();
+ mLongTimeout = false;
+ }
+
/**
* Start asynchronous result evaluation of formula.
* Will result in display on completion.
@@ -916,6 +944,8 @@ class Evaluator {
try {
CalculatorExpr.initExprInput();
mDegreeMode = in.readBoolean();
+ mLongTimeout = in.readBoolean();
+ mLongSavedTimeout = in.readBoolean();
mExpr = new CalculatorExpr(in);
mSavedName = in.readUTF();
mSaved = new CalculatorExpr(in);
@@ -931,6 +961,8 @@ class Evaluator {
try {
CalculatorExpr.initExprOutput();
out.writeBoolean(mDegreeMode);
+ out.writeBoolean(mLongTimeout);
+ out.writeBoolean(mLongSavedTimeout);
mExpr.write(out);
out.writeUTF(mSavedName);
mSaved.write(out);
@@ -959,6 +991,9 @@ class Evaluator {
public void delete() {
mChangedValue = true;
mExpr.delete();
+ if (mExpr.isEmpty()) {
+ mLongTimeout = false;
+ }
}
void setDegreeMode(boolean degreeMode) {
@@ -993,7 +1028,7 @@ class Evaluator {
*/
public void collapse() {
final CalculatorExpr abbrvExpr = getResultExpr();
- clear();
+ clearPreservingTimeout();
mExpr.append(abbrvExpr);
mChangedValue = true;
}
@@ -1009,6 +1044,7 @@ class Evaluator {
final CalculatorExpr abbrvExpr = getResultExpr();
mSaved.clear();
mSaved.append(abbrvExpr);
+ mLongSavedTimeout = mLongTimeout;
return true;
}
@@ -1042,6 +1078,7 @@ class Evaluator {
public void appendSaved() {
mChangedValue = true;
+ mLongTimeout |= mLongSavedTimeout;
mExpr.append(mSaved);
}