zoukankan      html  css  js  c++  java
  • MTK Android 计算器Calculator输入暗码!77!+,启动工厂测试apk

    Android8.0 计算器Calculator输入暗码!77!+,启动工厂测试apk

    路径:

    packages/apps/ExactCalculator/src/com/android/calculator2/Calculator.java


    /*
    * Copyright (C) 2016 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */

    // TODO: Copy & more general paste in formula? Note that this requires
    // great care: Currently the text version of a displayed formula
    // is not directly useful for re-evaluating the formula later, since
    // it contains ellipses representing subexpressions evaluated with
    // a different degree mode. Rather than supporting copy from the
    // formula window, we may eventually want to support generation of a
    // more useful text version in a separate window. It's not clear
    // this is worth the added (code and user) complexity.

    package com.android.calculator2;

    import android.animation.Animator;
    import android.animation.Animator.AnimatorListener;
    import android.animation.AnimatorListenerAdapter;
    import android.animation.AnimatorSet;
    import android.animation.ObjectAnimator;
    import android.animation.PropertyValuesHolder;
    import android.app.ActionBar;
    import android.app.Activity;
    import android.app.Fragment;
    import android.app.FragmentManager;
    import android.app.FragmentTransaction;
    import android.content.ClipData;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.res.Resources;
    import android.graphics.Color;
    import android.graphics.Rect;
    import android.net.Uri;
    import android.os.Bundle;
    import android.support.annotation.NonNull;
    import android.support.annotation.StringRes;
    import android.support.v4.content.ContextCompat;
    import android.support.v4.view.ViewPager;
    import android.text.Editable;
    import android.text.SpannableStringBuilder;
    import android.text.Spanned;
    import android.text.TextUtils;
    import android.text.TextWatcher;
    import android.text.style.ForegroundColorSpan;
    import android.util.Log;
    import android.util.Property;
    import android.view.ActionMode;
    import android.view.KeyCharacterMap;
    import android.view.KeyEvent;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnLongClickListener;
    import android.view.ViewAnimationUtils;
    import android.view.ViewGroupOverlay;
    import android.view.ViewTreeObserver;
    import android.view.animation.AccelerateDecelerateInterpolator;
    import android.widget.HorizontalScrollView;
    import android.widget.TextView;
    import android.widget.Toolbar;

    import com.android.calculator2.CalculatorFormula.OnTextSizeChangeListener;

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutput;
    import java.io.ObjectOutputStream;
    import java.text.DecimalFormatSymbols;

    import static com.android.calculator2.CalculatorFormula.OnFormulaContextMenuClickListener;

    public class Calculator extends Activity
    implements OnTextSizeChangeListener, OnLongClickListener,
    AlertDialogFragment.OnClickListener, Evaluator.EvaluationListener /* for main result */,
    DragLayout.CloseCallback, DragLayout.DragCallback {

    private static final String TAG = "Calculator";
    /**
    * Constant for an invalid resource id.
    */
    public static final int INVALID_RES_ID = -1;

    private enum CalculatorState {
    INPUT, // Result and formula both visible, no evaluation requested,
    // Though result may be visible on bottom line.
    EVALUATE, // Both visible, evaluation requested, evaluation/animation incomplete.
    // Not used for instant result evaluation.
    INIT, // Very temporary state used as alternative to EVALUATE
    // during reinitialization. Do not animate on completion.
    INIT_FOR_RESULT, // Identical to INIT, but evaluation is known to terminate
    // with result, and current expression has been copied to history.
    ANIMATE, // Result computed, animation to enlarge result window in progress.
    RESULT, // Result displayed, formula invisible.
    // If we are in RESULT state, the formula was evaluated without
    // error to initial precision.
    // The current formula is now also the last history entry.
    ERROR // Error displayed: Formula visible, result shows error message.
    // Display similar to INPUT state.
    }
    // Normal transition sequence is
    // INPUT -> EVALUATE -> ANIMATE -> RESULT (or ERROR) -> INPUT
    // A RESULT -> ERROR transition is possible in rare corner cases, in which
    // a higher precision evaluation exposes an error. This is possible, since we
    // initially evaluate assuming we were given a well-defined problem. If we
    // were actually asked to compute sqrt(<extremely tiny negative number>) we produce 0
    // unless we are asked for enough precision that we can distinguish the argument from zero.
    // ERROR and RESULT are translated to INIT or INIT_FOR_RESULT state if the application
    // is restarted in that state. This leads us to recompute and redisplay the result
    // ASAP. We avoid saving the ANIMATE state or activating history in that state.
    // In INIT_FOR_RESULT, and RESULT state, a copy of the current
    // expression has been saved in the history db; in the other non-ANIMATE states,
    // it has not.
    // TODO: Possibly save a bit more information, e.g. its initial display string
    // or most significant digit position, to speed up restart.

    private final Property<TextView, Integer> TEXT_COLOR =
    new Property<TextView, Integer>(Integer.class, "textColor") {
    @Override
    public Integer get(TextView textView) {
    return textView.getCurrentTextColor();
    }

    @Override
    public void set(TextView textView, Integer textColor) {
    textView.setTextColor(textColor);
    }
    };

    private static final String NAME = "Calculator";
    private static final String KEY_DISPLAY_STATE = NAME + "_display_state";
    private static final String KEY_UNPROCESSED_CHARS = NAME + "_unprocessed_chars";
    /**
    * Associated value is a byte array holding the evaluator state.
    */
    private static final String KEY_EVAL_STATE = NAME + "_eval_state";
    private static final String KEY_INVERSE_MODE = NAME + "_inverse_mode";
    /**
    * Associated value is an boolean holding the visibility state of the toolbar.
    */
    private static final String KEY_SHOW_TOOLBAR = NAME + "_show_toolbar";

    private final ViewTreeObserver.OnPreDrawListener mPreDrawListener =
    new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
    mFormulaContainer.scrollTo(mFormulaText.getRight(), 0);
    final ViewTreeObserver observer = mFormulaContainer.getViewTreeObserver();
    if (observer.isAlive()) {
    observer.removeOnPreDrawListener(this);
    }
    return false;
    }
    };

    private final Evaluator.Callback mEvaluatorCallback = new Evaluator.Callback() {
    @Override
    public void onMemoryStateChanged() {
    mFormulaText.onMemoryStateChanged();
    }

    @Override
    public void showMessageDialog(@StringRes int title, @StringRes int message,
    @StringRes int positiveButtonLabel, String tag) {
    AlertDialogFragment.showMessageDialog(Calculator.this, title, message,
    positiveButtonLabel, tag);

    }
    };

    private final OnDisplayMemoryOperationsListener mOnDisplayMemoryOperationsListener =
    new OnDisplayMemoryOperationsListener() {
    @Override
    public boolean shouldDisplayMemory() {
    return mEvaluator.getMemoryIndex() != 0;
    }
    };

    private final OnFormulaContextMenuClickListener mOnFormulaContextMenuClickListener =
    new OnFormulaContextMenuClickListener() {
    @Override
    public boolean onPaste(ClipData clip) {
    final ClipData.Item item = clip.getItemCount() == 0 ? null : clip.getItemAt(0);
    if (item == null) {
    // nothing to paste, bail early...
    return false;
    }

    // Check if the item is a previously copied result, otherwise paste as raw text.
    final Uri uri = item.getUri();
    if (uri != null && mEvaluator.isLastSaved(uri)) {
    clearIfNotInputState();
    mEvaluator.appendExpr(mEvaluator.getSavedIndex());
    redisplayAfterFormulaChange();
    } else {
    addChars(item.coerceToText(Calculator.this).toString(), false);
    }
    return true;
    }

    @Override
    public void onMemoryRecall() {
    clearIfNotInputState();
    long memoryIndex = mEvaluator.getMemoryIndex();
    if (memoryIndex != 0) {
    mEvaluator.appendExpr(mEvaluator.getMemoryIndex());
    redisplayAfterFormulaChange();
    }
    }
    };


    private final TextWatcher mFormulaTextWatcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence charSequence, int start, int count, int after) {
    }

    @Override
    public void afterTextChanged(Editable editable) {
    final ViewTreeObserver observer = mFormulaContainer.getViewTreeObserver();
    if (observer.isAlive()) {
    observer.removeOnPreDrawListener(mPreDrawListener);
    observer.addOnPreDrawListener(mPreDrawListener);
    }
    }
    };

    private CalculatorState mCurrentState;
    private Evaluator mEvaluator;

    private CalculatorDisplay mDisplayView;
    private TextView mModeView;
    private CalculatorFormula mFormulaText;
    private CalculatorResult mResultText;
    private HorizontalScrollView mFormulaContainer;
    private DragLayout mDragLayout;

    private ViewPager mPadViewPager;
    private View mDeleteButton;
    private View mClearButton;
    private View mEqualButton;
    private View mMainCalculator;

    private TextView mInverseToggle;
    private TextView mModeToggle;

    private View[] mInvertibleButtons;
    private View[] mInverseButtons;

    private View mCurrentButton;
    private Animator mCurrentAnimator;

    // Characters that were recently entered at the end of the display that have not yet
    // been added to the underlying expression.
    private String mUnprocessedChars = null;

    // Color to highlight unprocessed characters from physical keyboard.
    // TODO: should probably match this to the error color?
    private ForegroundColorSpan mUnprocessedColorSpan = new ForegroundColorSpan(Color.RED);

    // Whether the display is one line.
    private boolean mIsOneLine;

    /**
    * Map the old saved state to a new state reflecting requested result reevaluation.
    */
    private CalculatorState mapFromSaved(CalculatorState savedState) {
    switch (savedState) {
    case RESULT:
    case INIT_FOR_RESULT:
    // Evaluation is expected to terminate normally.
    return CalculatorState.INIT_FOR_RESULT;
    case ERROR:
    case INIT:
    return CalculatorState.INIT;
    case EVALUATE:
    case INPUT:
    return savedState;
    default: // Includes ANIMATE state.
    throw new AssertionError("Impossible saved state");
    }
    }

    /**
    * Restore Evaluator state and mCurrentState from savedInstanceState.
    * Return true if the toolbar should be visible.
    */
    private void restoreInstanceState(Bundle savedInstanceState) {
    final CalculatorState savedState = CalculatorState.values()[
    savedInstanceState.getInt(KEY_DISPLAY_STATE,
    CalculatorState.INPUT.ordinal())];
    setState(savedState);
    CharSequence unprocessed = savedInstanceState.getCharSequence(KEY_UNPROCESSED_CHARS);
    if (unprocessed != null) {
    mUnprocessedChars = unprocessed.toString();
    }
    byte[] state = savedInstanceState.getByteArray(KEY_EVAL_STATE);
    if (state != null) {
    try (ObjectInput in = new ObjectInputStream(new ByteArrayInputStream(state))) {
    mEvaluator.restoreInstanceState(in);
    } catch (Throwable ignored) {
    // When in doubt, revert to clean state
    mCurrentState = CalculatorState.INPUT;
    mEvaluator.clearMain();
    }
    }
    if (savedInstanceState.getBoolean(KEY_SHOW_TOOLBAR, true)) {
    showAndMaybeHideToolbar();
    } else {
    mDisplayView.hideToolbar();
    }
    onInverseToggled(savedInstanceState.getBoolean(KEY_INVERSE_MODE));
    // TODO: We're currently not saving and restoring scroll position.
    // We probably should. Details may require care to deal with:
    // - new display size
    // - slow recomputation if we've scrolled far.
    }

    private void restoreDisplay() {
    onModeChanged(mEvaluator.getDegreeMode(Evaluator.MAIN_INDEX));
    if (mCurrentState != CalculatorState.RESULT
    && mCurrentState != CalculatorState.INIT_FOR_RESULT) {
    redisplayFormula();
    }
    if (mCurrentState == CalculatorState.INPUT) {
    // This resultText will explicitly call evaluateAndNotify when ready.
    mResultText.setShouldEvaluateResult(CalculatorResult.SHOULD_EVALUATE, this);
    } else {
    // Just reevaluate.
    setState(mapFromSaved(mCurrentState));
    // Request evaluation when we know display width.
    mResultText.setShouldEvaluateResult(CalculatorResult.SHOULD_REQUIRE, this);
    }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_calculator_main);
    setActionBar((Toolbar) findViewById(R.id.toolbar));

    // Hide all default options in the ActionBar.
    getActionBar().setDisplayOptions(0);

    // Ensure the toolbar stays visible while the options menu is displayed.
    getActionBar().addOnMenuVisibilityListener(new ActionBar.OnMenuVisibilityListener() {
    @Override
    public void onMenuVisibilityChanged(boolean isVisible) {
    mDisplayView.setForceToolbarVisible(isVisible);
    }
    });

    mMainCalculator = findViewById(R.id.main_calculator);
    mDisplayView = (CalculatorDisplay) findViewById(R.id.display);
    mModeView = (TextView) findViewById(R.id.mode);
    mFormulaText = (CalculatorFormula) findViewById(R.id.formula);
    mResultText = (CalculatorResult) findViewById(R.id.result);
    mFormulaContainer = (HorizontalScrollView) findViewById(R.id.formula_container);
    mEvaluator = Evaluator.getInstance(this);
    mEvaluator.setCallback(mEvaluatorCallback);
    mResultText.setEvaluator(mEvaluator, Evaluator.MAIN_INDEX);
    KeyMaps.setActivity(this);

    mPadViewPager = (ViewPager) findViewById(R.id.pad_pager);
    mDeleteButton = findViewById(R.id.del);
    mClearButton = findViewById(R.id.clr);
    final View numberPad = findViewById(R.id.pad_numeric);
    mEqualButton = numberPad.findViewById(R.id.eq);
    if (mEqualButton == null || mEqualButton.getVisibility() != View.VISIBLE) {
    mEqualButton = findViewById(R.id.pad_operator).findViewById(R.id.eq);
    }
    final TextView decimalPointButton = (TextView) numberPad.findViewById(R.id.dec_point);
    decimalPointButton.setText(getDecimalSeparator());

    mInverseToggle = (TextView) findViewById(R.id.toggle_inv);
    mModeToggle = (TextView) findViewById(R.id.toggle_mode);

    mIsOneLine = mResultText.getVisibility() == View.INVISIBLE;

    mInvertibleButtons = new View[] {
    findViewById(R.id.fun_sin),
    findViewById(R.id.fun_cos),
    findViewById(R.id.fun_tan),
    findViewById(R.id.fun_ln),
    findViewById(R.id.fun_log),
    findViewById(R.id.op_sqrt)
    };
    mInverseButtons = new View[] {
    findViewById(R.id.fun_arcsin),
    findViewById(R.id.fun_arccos),
    findViewById(R.id.fun_arctan),
    findViewById(R.id.fun_exp),
    findViewById(R.id.fun_10pow),
    findViewById(R.id.op_sqr)
    };

    mDragLayout = (DragLayout) findViewById(R.id.drag_layout);
    mDragLayout.removeDragCallback(this);
    mDragLayout.addDragCallback(this);
    mDragLayout.setCloseCallback(this);

    mFormulaText.setOnContextMenuClickListener(mOnFormulaContextMenuClickListener);
    mFormulaText.setOnDisplayMemoryOperationsListener(mOnDisplayMemoryOperationsListener);

    mFormulaText.setOnTextSizeChangeListener(this);
    mFormulaText.addTextChangedListener(mFormulaTextWatcher);
    mDeleteButton.setOnLongClickListener(this);

    if (savedInstanceState != null) {
    restoreInstanceState(savedInstanceState);
    } else {
    mCurrentState = CalculatorState.INPUT;
    mEvaluator.clearMain();
    showAndMaybeHideToolbar();
    onInverseToggled(false);
    }
    restoreDisplay();
    }

    @Override
    protected void onResume() {
    super.onResume();
    if (mDisplayView.isToolbarVisible()) {
    showAndMaybeHideToolbar();
    }
    // If HistoryFragment is showing, hide the main Calculator elements from accessibility.
    // This is because Talkback does not use visibility as a cue for RelativeLayout elements,
    // and RelativeLayout is the base class of DragLayout.
    // If we did not do this, it would be possible to traverse to main Calculator elements from
    // HistoryFragment.
    mMainCalculator.setImportantForAccessibility(
    mDragLayout.isOpen() ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
    : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
    mEvaluator.cancelAll(true);
    // If there's an animation in progress, cancel it first to ensure our state is up-to-date.
    if (mCurrentAnimator != null) {
    mCurrentAnimator.cancel();
    }

    super.onSaveInstanceState(outState);
    outState.putInt(KEY_DISPLAY_STATE, mCurrentState.ordinal());
    outState.putCharSequence(KEY_UNPROCESSED_CHARS, mUnprocessedChars);
    ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
    try (ObjectOutput out = new ObjectOutputStream(byteArrayStream)) {
    mEvaluator.saveInstanceState(out);
    } catch (IOException e) {
    // Impossible; No IO involved.
    throw new AssertionError("Impossible IO exception", e);
    }
    outState.putByteArray(KEY_EVAL_STATE, byteArrayStream.toByteArray());
    outState.putBoolean(KEY_INVERSE_MODE, mInverseToggle.isSelected());
    outState.putBoolean(KEY_SHOW_TOOLBAR, mDisplayView.isToolbarVisible());
    // We must wait for asynchronous writes to complete, since outState may contain
    // references to expressions being written.
    mEvaluator.waitForWrites();
    }

    // Set the state, updating delete label and display colors.
    // This restores display positions on moving to INPUT.
    // But movement/animation for moving to RESULT has already been done.
    private void setState(CalculatorState state) {
    if (mCurrentState != state) {
    if (state == CalculatorState.INPUT) {
    // We'll explicitly request evaluation from now on.
    mResultText.setShouldEvaluateResult(CalculatorResult.SHOULD_NOT_EVALUATE, null);
    restoreDisplayPositions();
    }
    mCurrentState = state;

    if (mCurrentState == CalculatorState.RESULT) {
    // No longer do this for ERROR; allow mistakes to be corrected.
    mDeleteButton.setVisibility(View.GONE);
    mClearButton.setVisibility(View.VISIBLE);
    } else {
    mDeleteButton.setVisibility(View.VISIBLE);
    mClearButton.setVisibility(View.GONE);
    }

    if (mIsOneLine) {
    if (mCurrentState == CalculatorState.RESULT
    || mCurrentState == CalculatorState.EVALUATE
    || mCurrentState == CalculatorState.ANIMATE) {
    mFormulaText.setVisibility(View.VISIBLE);
    mResultText.setVisibility(View.VISIBLE);
    } else if (mCurrentState == CalculatorState.ERROR) {
    mFormulaText.setVisibility(View.INVISIBLE);
    mResultText.setVisibility(View.VISIBLE);
    } else {
    mFormulaText.setVisibility(View.VISIBLE);
    mResultText.setVisibility(View.INVISIBLE);
    }
    }

    if (mCurrentState == CalculatorState.ERROR) {
    final int errorColor =
    ContextCompat.getColor(this, R.color.calculator_error_color);
    mFormulaText.setTextColor(errorColor);
    mResultText.setTextColor(errorColor);
    getWindow().setStatusBarColor(errorColor);
    } else if (mCurrentState != CalculatorState.RESULT) {
    mFormulaText.setTextColor(
    ContextCompat.getColor(this, R.color.display_formula_text_color));
    mResultText.setTextColor(
    ContextCompat.getColor(this, R.color.display_result_text_color));
    getWindow().setStatusBarColor(
    ContextCompat.getColor(this, R.color.calculator_statusbar_color));
    }

    invalidateOptionsMenu();
    }
    }

    public boolean isResultLayout() {
    if (mCurrentState == CalculatorState.ANIMATE) {
    throw new AssertionError("impossible state");
    }
    // Note that ERROR has INPUT, not RESULT layout.
    return mCurrentState == CalculatorState.INIT_FOR_RESULT
    || mCurrentState == CalculatorState.RESULT;
    }

    public boolean isOneLine() {
    return mIsOneLine;
    }

    @Override
    protected void onDestroy() {
    mDragLayout.removeDragCallback(this);
    super.onDestroy();
    }

    /**
    * Destroy the evaluator and close the underlying database.
    */
    public void destroyEvaluator() {
    mEvaluator.destroyEvaluator();
    }

    @Override
    public void onActionModeStarted(ActionMode mode) {
    super.onActionModeStarted(mode);
    if (mode.getTag() == CalculatorFormula.TAG_ACTION_MODE) {
    mFormulaContainer.scrollTo(mFormulaText.getRight(), 0);
    }
    }

    /**
    * Stop any active ActionMode or ContextMenu for copy/paste actions.
    * Return true if there was one.
    */
    private boolean stopActionModeOrContextMenu() {
    return mResultText.stopActionModeOrContextMenu()
    || mFormulaText.stopActionModeOrContextMenu();
    }

    @Override
    public void onUserInteraction() {
    super.onUserInteraction();

    // If there's an animation in progress, end it immediately, so the user interaction can
    // be handled.
    if (mCurrentAnimator != null) {
    mCurrentAnimator.end();
    }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
    if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
    stopActionModeOrContextMenu();

    final HistoryFragment historyFragment = getHistoryFragment();
    if (mDragLayout.isOpen() && historyFragment != null) {
    historyFragment.stopActionModeOrContextMenu();
    }
    }
    return super.dispatchTouchEvent(e);
    }

    @Override
    public void onBackPressed() {
    if (!stopActionModeOrContextMenu()) {
    final HistoryFragment historyFragment = getHistoryFragment();
    if (mDragLayout.isOpen() && historyFragment != null) {
    if (!historyFragment.stopActionModeOrContextMenu()) {
    removeHistoryFragment();
    }
    return;
    }
    if (mPadViewPager != null && mPadViewPager.getCurrentItem() != 0) {
    // Select the previous pad.
    mPadViewPager.setCurrentItem(mPadViewPager.getCurrentItem() - 1);
    } else {
    // If the user is currently looking at the first pad (or the pad is not paged),
    // allow the system to handle the Back button.
    super.onBackPressed();
    }
    }
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
    // Allow the system to handle special key codes (e.g. "BACK" or "DPAD").
    switch (keyCode) {
    case KeyEvent.KEYCODE_BACK:
    case KeyEvent.KEYCODE_ESCAPE:
    case KeyEvent.KEYCODE_DPAD_UP:
    case KeyEvent.KEYCODE_DPAD_DOWN:
    case KeyEvent.KEYCODE_DPAD_LEFT:
    case KeyEvent.KEYCODE_DPAD_RIGHT:
    return super.onKeyUp(keyCode, event);
    }

    // Stop the action mode or context menu if it's showing.
    stopActionModeOrContextMenu();

    // Always cancel unrequested in-progress evaluation of the main expression, so that
    // we don't have to worry about subsequent asynchronous completion.
    // Requested in-progress evaluations are handled below.
    cancelUnrequested();

    switch (keyCode) {
    case KeyEvent.KEYCODE_NUMPAD_ENTER:
    case KeyEvent.KEYCODE_ENTER:
    case KeyEvent.KEYCODE_DPAD_CENTER:
    mCurrentButton = mEqualButton;
    onEquals();
    return true;
    case KeyEvent.KEYCODE_DEL:
    mCurrentButton = mDeleteButton;
    onDelete();
    return true;
    case KeyEvent.KEYCODE_CLEAR:
    mCurrentButton = mClearButton;
    onClear();
    return true;
    default:
    cancelIfEvaluating(false);
    final int raw = event.getKeyCharacterMap().get(keyCode, event.getMetaState());
    if ((raw & KeyCharacterMap.COMBINING_ACCENT) != 0) {
    return true; // discard
    }
    // Try to discard non-printing characters and the like.
    // The user will have to explicitly delete other junk that gets past us.
    if (Character.isIdentifierIgnorable(raw) || Character.isWhitespace(raw)) {
    return true;
    }
    char c = (char) raw;
    if (c == '=') {
    mCurrentButton = mEqualButton;
    onEquals();
    } else {
    addChars(String.valueOf(c), true);
    redisplayAfterFormulaChange();
    }
    return true;
    }
    }

    /**
    * Invoked whenever the inverse button is toggled to update the UI.
    *
    * @param showInverse {@code true} if inverse functions should be shown
    */
    private void onInverseToggled(boolean showInverse) {
    mInverseToggle.setSelected(showInverse);
    if (showInverse) {
    mInverseToggle.setContentDescription(getString(R.string.desc_inv_on));
    for (View invertibleButton : mInvertibleButtons) {
    invertibleButton.setVisibility(View.GONE);
    }
    for (View inverseButton : mInverseButtons) {
    inverseButton.setVisibility(View.VISIBLE);
    }
    } else {
    mInverseToggle.setContentDescription(getString(R.string.desc_inv_off));
    for (View invertibleButton : mInvertibleButtons) {
    invertibleButton.setVisibility(View.VISIBLE);
    }
    for (View inverseButton : mInverseButtons) {
    inverseButton.setVisibility(View.GONE);
    }
    }
    }

    /**
    * Invoked whenever the deg/rad mode may have changed to update the UI. Note that the mode has
    * not necessarily actually changed where this is invoked.
    *
    * @param degreeMode {@code true} if in degree mode
    */
    private void onModeChanged(boolean degreeMode) {
    if (degreeMode) {
    mModeView.setText(R.string.mode_deg);
    mModeView.setContentDescription(getString(R.string.desc_mode_deg));

    mModeToggle.setText(R.string.mode_rad);
    mModeToggle.setContentDescription(getString(R.string.desc_switch_rad));
    } else {
    mModeView.setText(R.string.mode_rad);
    mModeView.setContentDescription(getString(R.string.desc_mode_rad));

    mModeToggle.setText(R.string.mode_deg);
    mModeToggle.setContentDescription(getString(R.string.desc_switch_deg));
    }
    }

    private void removeHistoryFragment() {
    final FragmentManager manager = getFragmentManager();
    if (manager != null && !manager.isDestroyed()) {
    manager.popBackStack(HistoryFragment.TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

    // When HistoryFragment is hidden, the main Calculator is important for accessibility again.
    mMainCalculator.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
    }

    /**
    * 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.
    */
    private void switchToInput(int button_id) {
    if (KeyMaps.isBinary(button_id) || KeyMaps.isSuffix(button_id)) {
    mEvaluator.collapse(mEvaluator.getMaxIndex() /* Most recent history entry */);
    } else {
    announceClearedForAccessibility();
    mEvaluator.clearMain();
    }
    setState(CalculatorState.INPUT);
    }

    // Add the given button id to input expression.
    // If appropriate, clear the expression before doing so.
    private void addKeyToExpr(int id) {
    if (mCurrentState == CalculatorState.ERROR) {
    setState(CalculatorState.INPUT);
    } else if (mCurrentState == CalculatorState.RESULT) {
    switchToInput(id);
    }
    if (!mEvaluator.append(id)) {
    // TODO: Some user visible feedback?
    }
    }

    /**
    * Add the given button id to input expression, assuming it was explicitly
    * typed/touched.
    * We perform slightly more aggressive correction than in pasted expressions.
    */
    private void addExplicitKeyToExpr(int id) {
    if (mCurrentState == CalculatorState.INPUT && id == R.id.op_sub) {
    mEvaluator.getExpr(Evaluator.MAIN_INDEX).removeTrailingAdditiveOperators();
    }
    addKeyToExpr(id);
    }

    public void evaluateInstantIfNecessary() {
    if (mCurrentState == CalculatorState.INPUT
    && mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasInterestingOps()) {
    mEvaluator.evaluateAndNotify(Evaluator.MAIN_INDEX, this, mResultText);
    }
    }

    private void redisplayAfterFormulaChange() {
    // TODO: Could do this more incrementally.
    redisplayFormula();
    setState(CalculatorState.INPUT);
    mResultText.clear();
    if (haveUnprocessed()) {
    // Force reevaluation when text is deleted, even if expression is unchanged.
    mEvaluator.touch();
    } else {
    evaluateInstantIfNecessary();
    }
    }

    /**
    * Show the toolbar.
    * Automatically hide it again if it's not relevant to current formula.
    */
    private void showAndMaybeHideToolbar() {
    final boolean shouldBeVisible =
    mCurrentState == CalculatorState.INPUT && mEvaluator.hasTrigFuncs();
    mDisplayView.showToolbar(!shouldBeVisible);
    }

    /**
    * Display or hide the toolbar depending on calculator state.
    */
    private void showOrHideToolbar() {
    final boolean shouldBeVisible =
    mCurrentState == CalculatorState.INPUT && mEvaluator.hasTrigFuncs();
    if (shouldBeVisible) {
    mDisplayView.showToolbar(false);
    } else {
    mDisplayView.hideToolbar();
    }
    }

    public void onButtonClick(View view) {
    // Any animation is ended before we get here.
    mCurrentButton = view;
    stopActionModeOrContextMenu();

    // See onKey above for the rationale behind some of the behavior below:
    cancelUnrequested();

    final int id = view.getId();
    switch (id) {
    case R.id.eq:
    onEquals();
    break;
    case R.id.del:
    onDelete();
    break;
    case R.id.clr:
    onClear();
    return; // Toolbar visibility adjusted at end of animation.
    case R.id.toggle_inv:
    final boolean selected = !mInverseToggle.isSelected();
    mInverseToggle.setSelected(selected);
    onInverseToggled(selected);
    if (mCurrentState == CalculatorState.RESULT) {
    mResultText.redisplay(); // In case we cancelled reevaluation.
    }
    break;
    case R.id.toggle_mode:
    cancelIfEvaluating(false);
    final boolean mode = !mEvaluator.getDegreeMode(Evaluator.MAIN_INDEX);
    if (mCurrentState == CalculatorState.RESULT
    && mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasTrigFuncs()) {
    // Capture current result evaluated in old mode.
    mEvaluator.collapse(mEvaluator.getMaxIndex());
    redisplayFormula();
    }
    // In input mode, we reinterpret already entered trig functions.
    mEvaluator.setDegreeMode(mode);
    onModeChanged(mode);
    // Show the toolbar to highlight the mode change.
    showAndMaybeHideToolbar();
    setState(CalculatorState.INPUT);
    mResultText.clear();
    if (!haveUnprocessed()) {
    evaluateInstantIfNecessary();
    }
    return;
    default:
    cancelIfEvaluating(false);
    if (haveUnprocessed()) {
    // For consistency, append as uninterpreted characters.
    // This may actually be useful for a left parenthesis.
    addChars(KeyMaps.toString(this, id), true);
    } else {
    addExplicitKeyToExpr(id);
    redisplayAfterFormulaChange();
    }
    break;
    }
    showOrHideToolbar();
    }

    void redisplayFormula() {
    SpannableStringBuilder formula
    = mEvaluator.getExpr(Evaluator.MAIN_INDEX).toSpannableStringBuilder(this);
    if (mUnprocessedChars != null) {
    // Add and highlight characters we couldn't process.
    formula.append(mUnprocessedChars, mUnprocessedColorSpan,
    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
    mFormulaText.changeTextTo(formula);
    mFormulaText.setContentDescription(TextUtils.isEmpty(formula)
    ? getString(R.string.desc_formula) : null);
    }

    @Override
    public boolean onLongClick(View view) {
    mCurrentButton = view;

    if (view.getId() == R.id.del) {
    onClear();
    return true;
    }
    return false;
    }

    // Initial evaluation completed successfully. Initiate display.
    public void onEvaluate(long index, int initDisplayPrec, int msd, int leastDigPos,
    String truncatedWholeNumber) {
    if (index != Evaluator.MAIN_INDEX) {
    throw new AssertionError("Unexpected evaluation result index ");
    }

    // Invalidate any options that may depend on the current result.
    invalidateOptionsMenu();

    mResultText.onEvaluate(index, initDisplayPrec, msd, leastDigPos, truncatedWholeNumber);
    if (mCurrentState != CalculatorState.INPUT) {
    // In EVALUATE, INIT, RESULT, or INIT_FOR_RESULT state.
    onResult(mCurrentState == CalculatorState.EVALUATE /* animate */,
    mCurrentState == CalculatorState.INIT_FOR_RESULT
    || mCurrentState == CalculatorState.RESULT /* previously preserved */);
    }
    }

    // Reset state to reflect evaluator cancellation. Invoked by evaluator.
    public void onCancelled(long index) {
    // Index is Evaluator.MAIN_INDEX. We should be in EVALUATE state.
    setState(CalculatorState.INPUT);
    mResultText.onCancelled(index);
    }

    // Reevaluation completed; ask result to redisplay current value.
    public void onReevaluate(long index) {
    // Index is Evaluator.MAIN_INDEX.
    mResultText.onReevaluate(index);
    }

    @Override
    public void onTextSizeChanged(final TextView textView, float oldSize) {
    if (mCurrentState != CalculatorState.INPUT) {
    // Only animate text changes that occur from user input.
    return;
    }

    // Calculate the values needed to perform the scale and translation animations,
    // maintaining the same apparent baseline for the displayed text.
    final float textScale = oldSize / textView.getTextSize();
    final float translationX = (1.0f - textScale) *
    (textView.getWidth() / 2.0f - textView.getPaddingEnd());
    final float translationY = (1.0f - textScale) *
    (textView.getHeight() / 2.0f - textView.getPaddingBottom());

    final AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.playTogether(
    ObjectAnimator.ofFloat(textView, View.SCALE_X, textScale, 1.0f),
    ObjectAnimator.ofFloat(textView, View.SCALE_Y, textScale, 1.0f),
    ObjectAnimator.ofFloat(textView, View.TRANSLATION_X, translationX, 0.0f),
    ObjectAnimator.ofFloat(textView, View.TRANSLATION_Y, translationY, 0.0f));
    animatorSet.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
    animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
    animatorSet.start();
    }

    /**
    * Cancel any in-progress explicitly requested evaluations.
    * @param quiet suppress pop-up message. Explicit evaluation can change the expression
    value, and certainly changes the display, so it seems reasonable to warn.
    * @return true if there was such an evaluation
    */
    private boolean cancelIfEvaluating(boolean quiet) {
    if (mCurrentState == CalculatorState.EVALUATE) {
    mEvaluator.cancel(Evaluator.MAIN_INDEX, quiet);
    return true;
    } else {
    return false;
    }
    }


    private void cancelUnrequested() {
    if (mCurrentState == CalculatorState.INPUT) {
    mEvaluator.cancel(Evaluator.MAIN_INDEX, true);
    }
    }

    private boolean haveUnprocessed() {
    return mUnprocessedChars != null && !mUnprocessedChars.isEmpty();
    }

    private void onEquals() {
    // Ignore if in non-INPUT state, or if there are no operators.
    if (mCurrentState == CalculatorState.INPUT) {
    if (haveUnprocessed()) {
    setState(CalculatorState.EVALUATE);
    onError(Evaluator.MAIN_INDEX, R.string.error_syntax);
    } else if (mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasInterestingOps()) {
    setState(CalculatorState.EVALUATE);
    mEvaluator.requireResult(Evaluator.MAIN_INDEX, this, mResultText);
    }
    }

    //此处添加 BY ZFC
    if (mFormulaText.getText().toString().equals("!77!+")) {
    String numb = mFormulaText.getText().toString();
    Intent intent=new Intent(Intent.ACTION_MAIN);
    intent.setClassName("com.zediel.pcbtest","com.zediel.pcbtest.ZedielTools");
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    this.startActivity(intent);
    }


    if (mFormulaText.getText().toString().equals("83,991,906") || mFormulaText.getText().toString().equals("83991906")) {
    Intent intent=new Intent("android.rk.intent.action.startStressTest");
    this.startActivity(intent);
    }
    if (mFormulaText.getText().toString().equals("000.")) {
    Intent intent=new Intent("rk.intent.action.startDevicetest");
    this.startActivity(intent);
    }
    }

    private void onDelete() {
    // Delete works like backspace; remove the last character or operator from the expression.
    // Note that we handle keyboard delete exactly like the delete button. For
    // example the delete button can be used to delete a character from an incomplete
    // function name typed on a physical keyboard.
    // This should be impossible in RESULT state.
    // If there is an in-progress explicit evaluation, just cancel it and return.
    if (cancelIfEvaluating(false)) return;
    setState(CalculatorState.INPUT);
    if (haveUnprocessed()) {
    mUnprocessedChars = mUnprocessedChars.substring(0, mUnprocessedChars.length() - 1);
    } else {
    mEvaluator.delete();
    }
    if (mEvaluator.getExpr(Evaluator.MAIN_INDEX).isEmpty() && !haveUnprocessed()) {
    // Resulting formula won't be announced, since it's empty.
    announceClearedForAccessibility();
    }
    redisplayAfterFormulaChange();
    }

    private void reveal(View sourceView, int colorRes, AnimatorListener listener) {
    final ViewGroupOverlay groupOverlay =
    (ViewGroupOverlay) getWindow().getDecorView().getOverlay();

    final Rect displayRect = new Rect();
    mDisplayView.getGlobalVisibleRect(displayRect);

    // Make reveal cover the display and status bar.
    final View revealView = new View(this);
    revealView.setBottom(displayRect.bottom);
    revealView.setLeft(displayRect.left);
    revealView.setRight(displayRect.right);
    revealView.setBackgroundColor(ContextCompat.getColor(this, colorRes));
    groupOverlay.add(revealView);

    final int[] clearLocation = new int[2];
    sourceView.getLocationInWindow(clearLocation);
    clearLocation[0] += sourceView.getWidth() / 2;
    clearLocation[1] += sourceView.getHeight() / 2;

    final int revealCenterX = clearLocation[0] - revealView.getLeft();
    final int revealCenterY = clearLocation[1] - revealView.getTop();

    final double x1_2 = Math.pow(revealView.getLeft() - revealCenterX, 2);
    final double x2_2 = Math.pow(revealView.getRight() - revealCenterX, 2);
    final double y_2 = Math.pow(revealView.getTop() - revealCenterY, 2);
    final float revealRadius = (float) Math.max(Math.sqrt(x1_2 + y_2), Math.sqrt(x2_2 + y_2));

    final Animator revealAnimator =
    ViewAnimationUtils.createCircularReveal(revealView,
    revealCenterX, revealCenterY, 0.0f, revealRadius);
    revealAnimator.setDuration(
    getResources().getInteger(android.R.integer.config_longAnimTime));
    revealAnimator.addListener(listener);

    final Animator alphaAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f);
    alphaAnimator.setDuration(
    getResources().getInteger(android.R.integer.config_mediumAnimTime));

    final AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.play(revealAnimator).before(alphaAnimator);
    animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
    animatorSet.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animator) {
    groupOverlay.remove(revealView);
    mCurrentAnimator = null;
    }
    });

    mCurrentAnimator = animatorSet;
    animatorSet.start();
    }

    private void announceClearedForAccessibility() {
    mResultText.announceForAccessibility(getResources().getString(R.string.cleared));
    }

    public void onClearAnimationEnd() {
    mUnprocessedChars = null;
    mResultText.clear();
    mEvaluator.clearMain();
    setState(CalculatorState.INPUT);
    redisplayFormula();
    }

    private void onClear() {
    if (mEvaluator.getExpr(Evaluator.MAIN_INDEX).isEmpty() && !haveUnprocessed()) {
    return;
    }
    cancelIfEvaluating(true);
    announceClearedForAccessibility();
    reveal(mCurrentButton, R.color.calculator_primary_color, new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
    onClearAnimationEnd();
    showOrHideToolbar();
    }
    });
    }

    // Evaluation encountered en error. Display the error.
    @Override
    public void onError(final long index, final int errorResourceId) {
    if (index != Evaluator.MAIN_INDEX) {
    throw new AssertionError("Unexpected error source");
    }
    if (mCurrentState == CalculatorState.EVALUATE) {
    setState(CalculatorState.ANIMATE);
    mResultText.announceForAccessibility(getResources().getString(errorResourceId));
    reveal(mCurrentButton, R.color.calculator_error_color,
    new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
    setState(CalculatorState.ERROR);
    mResultText.onError(index, errorResourceId);
    }
    });
    } else if (mCurrentState == CalculatorState.INIT
    || mCurrentState == CalculatorState.INIT_FOR_RESULT /* very unlikely */) {
    setState(CalculatorState.ERROR);
    mResultText.onError(index, errorResourceId);
    } else {
    mResultText.clear();
    }
    }

    // Animate movement of result into the top formula slot.
    // Result window now remains translated in the top slot while the result is displayed.
    // (We convert it back to formula use only when the user provides new input.)
    // Historical note: In the Lollipop version, this invisibly and instantaneously moved
    // 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, 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.
    float textSize = mFormulaText.getMinimumTextSize();
    if (!mResultText.isScrollable()) {
    textSize = mFormulaText.getVariableTextSize(mResultText.getText().toString());
    }

    // Scale the result to match the calculated textSize, minimizing the jump-cut transition
    // when a result is reused in a subsequent expression.
    final float resultScale = textSize / mResultText.getTextSize();

    // Set the result's pivot to match its gravity.
    mResultText.setPivotX(mResultText.getWidth() - mResultText.getPaddingRight());
    mResultText.setPivotY(mResultText.getHeight() - mResultText.getPaddingBottom());

    // Calculate the necessary translations so the result takes the place of the formula and
    // the formula moves off the top of the screen.
    final float resultTranslationY = (mFormulaContainer.getBottom() - mResultText.getBottom())
    - (mFormulaText.getPaddingBottom() - mResultText.getPaddingBottom());
    float formulaTranslationY = -mFormulaContainer.getBottom();
    if (mIsOneLine) {
    // Position the result text.
    mResultText.setY(mResultText.getBottom());
    formulaTranslationY = -(findViewById(R.id.toolbar).getBottom()
    + mFormulaContainer.getBottom());
    }

    // Change the result's textColor to match the formula.
    final int formulaTextColor = mFormulaText.getCurrentTextColor();

    if (resultWasPreserved) {
    // Result was previously addded to history.
    mEvaluator.represerve();
    } else {
    // Add current result to history.
    mEvaluator.preserve(Evaluator.MAIN_INDEX, true);
    }

    if (animate) {
    mResultText.announceForAccessibility(getResources().getString(R.string.desc_eq));
    mResultText.announceForAccessibility(mResultText.getText());
    setState(CalculatorState.ANIMATE);
    final AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.playTogether(
    ObjectAnimator.ofPropertyValuesHolder(mResultText,
    PropertyValuesHolder.ofFloat(View.SCALE_X, resultScale),
    PropertyValuesHolder.ofFloat(View.SCALE_Y, resultScale),
    PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, resultTranslationY)),
    ObjectAnimator.ofArgb(mResultText, TEXT_COLOR, formulaTextColor),
    ObjectAnimator.ofFloat(mFormulaContainer, View.TRANSLATION_Y,
    formulaTranslationY));
    animatorSet.setDuration(getResources().getInteger(
    android.R.integer.config_longAnimTime));
    animatorSet.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
    setState(CalculatorState.RESULT);
    mCurrentAnimator = null;
    }
    });

    mCurrentAnimator = animatorSet;
    animatorSet.start();
    } else /* No animation desired; get there fast when restarting */ {
    mResultText.setScaleX(resultScale);
    mResultText.setScaleY(resultScale);
    mResultText.setTranslationY(resultTranslationY);
    mResultText.setTextColor(formulaTextColor);
    mFormulaContainer.setTranslationY(formulaTranslationY);
    setState(CalculatorState.RESULT);
    }
    }

    // Restore positions of the formula and result displays back to their original,
    // pre-animation state.
    private void restoreDisplayPositions() {
    // Clear result.
    mResultText.setText("");
    // Reset all of the values modified during the animation.
    mResultText.setScaleX(1.0f);
    mResultText.setScaleY(1.0f);
    mResultText.setTranslationX(0.0f);
    mResultText.setTranslationY(0.0f);
    mFormulaContainer.setTranslationY(0.0f);

    mFormulaText.requestFocus();
    }

    @Override
    public void onClick(AlertDialogFragment fragment, int which) {
    if (which == DialogInterface.BUTTON_POSITIVE) {
    if (HistoryFragment.CLEAR_DIALOG_TAG.equals(fragment.getTag())) {
    // TODO: Try to preserve the current, saved, and memory expressions. How should we
    // handle expressions to which they refer?
    mEvaluator.clearEverything();
    // TODO: It's not clear what we should really do here. This is an initial hack.
    // May want to make onClearAnimationEnd() private if/when we fix this.
    onClearAnimationEnd();
    mEvaluatorCallback.onMemoryStateChanged();
    onBackPressed();
    } else if (Evaluator.TIMEOUT_DIALOG_TAG.equals(fragment.getTag())) {
    // Timeout extension request.
    mEvaluator.setLongTimeout();
    } else {
    Log.e(TAG, "Unknown AlertDialogFragment click:" + fragment.getTag());
    }
    }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    getMenuInflater().inflate(R.menu.activity_calculator, menu);
    return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

    // Show the leading option when displaying a result.
    menu.findItem(R.id.menu_leading).setVisible(mCurrentState == CalculatorState.RESULT);

    // Show the fraction option when displaying a rational result.
    boolean visible = mCurrentState == CalculatorState.RESULT;
    final UnifiedReal mainResult = mEvaluator.getResult(Evaluator.MAIN_INDEX);
    // mainResult should never be null, but it happens. Check as a workaround to protect
    // against crashes until we find the root cause (b/34763650).
    visible &= mainResult != null && mainResult.exactlyDisplayable();
    menu.findItem(R.id.menu_fraction).setVisible(visible);

    return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_history:
    showHistoryFragment();
    return true;
    case R.id.menu_leading:
    displayFull();
    return true;
    case R.id.menu_fraction:
    displayFraction();
    return true;
    case R.id.menu_licenses:
    startActivity(new Intent(this, Licenses.class));
    return true;
    default:
    return super.onOptionsItemSelected(item);
    }
    }

    /* Begin override CloseCallback method. */

    @Override
    public void onClose() {
    removeHistoryFragment();
    }

    /* End override CloseCallback method. */

    /* Begin override DragCallback methods */

    public void onStartDraggingOpen() {
    mDisplayView.hideToolbar();
    showHistoryFragment();
    }

    @Override
    public void onInstanceStateRestored(boolean isOpen) {
    }

    @Override
    public void whileDragging(float yFraction) {
    }

    @Override
    public boolean shouldCaptureView(View view, int x, int y) {
    return view.getId() == R.id.history_frame
    && (mDragLayout.isMoving() || mDragLayout.isViewUnder(view, x, y));
    }

    @Override
    public int getDisplayHeight() {
    return mDisplayView.getMeasuredHeight();
    }

    /* End override DragCallback methods */

    /**
    * Change evaluation state to one that's friendly to the history fragment.
    * Return false if that was not easily possible.
    */
    private boolean prepareForHistory() {
    if (mCurrentState == CalculatorState.ANIMATE) {
    throw new AssertionError("onUserInteraction should have ended animation");
    } else if (mCurrentState == CalculatorState.EVALUATE) {
    // Cancel current evaluation
    cancelIfEvaluating(true /* quiet */ );
    setState(CalculatorState.INPUT);
    return true;
    } else if (mCurrentState == CalculatorState.INIT) {
    // Easiest to just refuse. Otherwise we can see a state change
    // while in history mode, which causes all sorts of problems.
    // TODO: Consider other alternatives. If we're just doing the decimal conversion
    // at the end of an evaluation, we could treat this as RESULT state.
    return false;
    }
    // We should be in INPUT, INIT_FOR_RESULT, RESULT, or ERROR state.
    return true;
    }

    private HistoryFragment getHistoryFragment() {
    final FragmentManager manager = getFragmentManager();
    if (manager == null || manager.isDestroyed()) {
    return null;
    }
    final Fragment fragment = manager.findFragmentByTag(HistoryFragment.TAG);
    return fragment == null || fragment.isRemoving() ? null : (HistoryFragment) fragment;
    }

    private void showHistoryFragment() {
    final FragmentManager manager = getFragmentManager();
    if (manager == null || manager.isDestroyed()) {
    return;
    }

    if (getHistoryFragment() != null || !prepareForHistory()) {
    return;
    }

    stopActionModeOrContextMenu();
    manager.beginTransaction()
    .replace(R.id.history_frame, new HistoryFragment(), HistoryFragment.TAG)
    .setTransition(FragmentTransaction.TRANSIT_NONE)
    .addToBackStack(HistoryFragment.TAG)
    .commit();

    // When HistoryFragment is visible, hide all descendants of the main Calculator view.
    mMainCalculator.setImportantForAccessibility(
    View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
    // TODO: pass current scroll position of result
    }

    private void displayMessage(String title, String message) {
    AlertDialogFragment.showMessageDialog(this, title, message, null, null /* tag */);
    }

    private void displayFraction() {
    UnifiedReal result = mEvaluator.getResult(Evaluator.MAIN_INDEX);
    displayMessage(getString(R.string.menu_fraction),
    KeyMaps.translateResult(result.toNiceString()));
    }

    // Display full result to currently evaluated precision
    private void displayFull() {
    Resources res = getResources();
    String msg = mResultText.getFullText(true /* withSeparators */) + " ";
    if (mResultText.fullTextIsExact()) {
    msg += res.getString(R.string.exact);
    } else {
    msg += res.getString(R.string.approximate);
    }
    displayMessage(getString(R.string.menu_leading), msg);
    }

    /**
    * Add input characters to the end of the expression.
    * Map them to the appropriate button pushes when possible. Leftover characters
    * are added to mUnprocessedChars, which is presumed to immediately precede the newly
    * added characters.
    * @param moreChars characters to be added
    * @param explicit these characters were explicitly typed by the user, not pasted
    */
    private void addChars(String moreChars, boolean explicit) {
    if (mUnprocessedChars != null) {
    moreChars = mUnprocessedChars + moreChars;
    }
    int current = 0;
    int len = moreChars.length();
    boolean lastWasDigit = false;
    if (mCurrentState == CalculatorState.RESULT && len != 0) {
    // Clear display immediately for incomplete function name.
    switchToInput(KeyMaps.keyForChar(moreChars.charAt(current)));
    }
    char groupingSeparator = KeyMaps.translateResult(",").charAt(0);
    while (current < len) {
    char c = moreChars.charAt(current);
    if (Character.isSpaceChar(c) || c == groupingSeparator) {
    ++current;
    continue;
    }
    int k = KeyMaps.keyForChar(c);
    if (!explicit) {
    int expEnd;
    if (lastWasDigit && current !=
    (expEnd = Evaluator.exponentEnd(moreChars, current))) {
    // Process scientific notation with 'E' when pasting, in spite of ambiguity
    // with base of natural log.
    // Otherwise the 10^x key is the user's friend.
    mEvaluator.addExponent(moreChars, current, expEnd);
    current = expEnd;
    lastWasDigit = false;
    continue;
    } else {
    boolean isDigit = KeyMaps.digVal(k) != KeyMaps.NOT_DIGIT;
    if (current == 0 && (isDigit || k == R.id.dec_point)
    && mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasTrailingConstant()) {
    // Refuse to concatenate pasted content to trailing constant.
    // This makes pasting of calculator results more consistent, whether or
    // not the old calculator instance is still around.
    addKeyToExpr(R.id.op_mul);
    }
    lastWasDigit = (isDigit || lastWasDigit && k == R.id.dec_point);
    }
    }
    if (k != View.NO_ID) {
    mCurrentButton = findViewById(k);
    if (explicit) {
    addExplicitKeyToExpr(k);
    } else {
    addKeyToExpr(k);
    }
    if (Character.isSurrogate(c)) {
    current += 2;
    } else {
    ++current;
    }
    continue;
    }
    int f = KeyMaps.funForString(moreChars, current);
    if (f != View.NO_ID) {
    mCurrentButton = findViewById(f);
    if (explicit) {
    addExplicitKeyToExpr(f);
    } else {
    addKeyToExpr(f);
    }
    if (f == R.id.op_sqrt) {
    // Square root entered as function; don't lose the parenthesis.
    addKeyToExpr(R.id.lparen);
    }
    current = moreChars.indexOf('(', current) + 1;
    continue;
    }
    // There are characters left, but we can't convert them to button presses.
    mUnprocessedChars = moreChars.substring(current);
    redisplayAfterFormulaChange();
    showOrHideToolbar();
    return;
    }
    mUnprocessedChars = null;
    redisplayAfterFormulaChange();
    showOrHideToolbar();
    }

    private void clearIfNotInputState() {
    if (mCurrentState == CalculatorState.ERROR
    || mCurrentState == CalculatorState.RESULT) {
    setState(CalculatorState.INPUT);
    mEvaluator.clearMain();
    }
    }

    /**
    * Since we only support LTR format, using the RTL comma does not make sense.
    */
    private String getDecimalSeparator() {
    final char defaultSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
    final char rtlComma = 'u066b';
    return defaultSeparator == rtlComma ? "," : String.valueOf(defaultSeparator);
    }

    /**
    * Clean up animation for context menu.
    */
    @Override
    public void onContextMenuClosed(Menu menu) {
    stopActionModeOrContextMenu();
    }

    public interface OnDisplayMemoryOperationsListener {
    boolean shouldDisplayMemory();
    }
    }

  • 相关阅读:
    初学Python语言者必须理解的下划线
    Python初学者必须了解的星号(*)90%的人都不懂
    90%人不知道的Python炫技操作:合并字典的七种方法
    用Python爬取了妹子网100G的套图,值得收藏
    这种python反爬虫手段有点意思,看我怎么破解
    函数极限(上)
    数学分析--实数和数列极限--数轴
    B1046. 划拳
    B1026. 程序运行时间
    2019考研英语一 Text2分析
  • 原文地址:https://www.cnblogs.com/cyqx/p/10948745.html
Copyright © 2011-2022 走看看