/* * Copyright (C) 2008 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. */ package com.numix.calculator; import java.util.List; import android.animation.Animator; import android.content.Context; import android.os.Build; import android.support.v4.view.ViewPager; import android.view.KeyEvent; import android.view.View; import android.view.ViewAnimationUtils; import android.view.animation.AccelerateInterpolator; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.numix.calculator.BaseModule.Mode; import com.numix.calculator.Calculator.Panel; import com.numix.calculator.view.CalculatorDisplay; import com.numix.calculator.view.MatrixEditText; import com.numix.calculator.view.MatrixInverseView; import com.numix.calculator.view.MatrixTransposeView; import com.numix.calculator.view.MatrixView; public class EventListener implements View.OnKeyListener, View.OnClickListener, View.OnLongClickListener { Context mContext; Logic mHandler; ViewPager mPager; ViewPager mSmallPager; ViewPager mLargePager; private String mErrorString; private String mModString; private String mX; private String mY; private String mDX; private String mDY; void setHandler(Context context, Logic handler, ViewPager pager) { setHandler(context, handler, pager, null, null); } void setHandler(Context context, Logic handler, ViewPager smallPager, ViewPager largePager) { setHandler(context, handler, null, smallPager, largePager); } private void setHandler(Context context, Logic handler, ViewPager pager, ViewPager smallPager, ViewPager largePager) { mContext = context; mHandler = handler; mPager = pager; mSmallPager = smallPager; mLargePager = largePager; mErrorString = mContext.getString(R.string.error); mModString = mContext.getString(R.string.mod); mX = mContext.getString(R.string.X); mY = mContext.getString(R.string.Y); mDX = mContext.getString(R.string.dx); mDY = mContext.getString(R.string.dy); } private void deleteAnimation(View view){ final TextView colorLayout = (TextView) view.getRootView().findViewById(R.id.deleteColor); final LinearLayout displayView = (LinearLayout) view.getRootView().findViewById(R.id.displayLayout); final CalculatorDisplay calculatorDisplay = (CalculatorDisplay) view.getRootView().findViewById(R.id.display); int finalRadius = Math.max(displayView.getWidth(), displayView.getHeight()); // create the animator for this view (the start radius is zero) Animator colorAnim; colorAnim = ViewAnimationUtils.createCircularReveal(colorLayout, (int) displayView.getRight(), (int) displayView.getBottom(), 0, finalRadius); final AlphaAnimation fadeAnim = new AlphaAnimation(1.0f, 0.0f); final AlphaAnimation fadeDisplay = new AlphaAnimation(1.0f, 0.0f); fadeAnim.setDuration(250); fadeAnim.setInterpolator(new AccelerateInterpolator()); fadeAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { colorLayout.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { } }); fadeDisplay.setDuration(250); fadeDisplay.setInterpolator(new AccelerateInterpolator()); fadeDisplay.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mHandler.onClear(); displayView.setAlpha(1.0f); } @Override public void onAnimationRepeat(Animation animation) { } }); colorAnim.setInterpolator(new AccelerateInterpolator()); colorAnim.addListener(new android.animation.Animator.AnimatorListener() { @Override public void onAnimationStart(android.animation.Animator animation) { calculatorDisplay.startAnimation(fadeDisplay); } @Override public void onAnimationRepeat(android.animation.Animator animation) { } @Override public void onAnimationEnd(android.animation.Animator animation) { colorLayout.startAnimation(fadeAnim); } @Override public void onAnimationCancel(android.animation.Animator animation) { }}); colorLayout.setVisibility(View.VISIBLE); colorAnim.start(); } @Override public void onClick(View view) { View v; EditText active; int id = view.getId(); switch(id) { case R.id.del: mHandler.onDelete(); break; case R.id.clear: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { deleteAnimation(view); } break; case R.id.equal: if(mHandler.getText().contains(mX) || mHandler.getText().contains(mY)) { if(!mHandler.getText().contains("=")) { mHandler.insert("="); returnToBasic(); } break; } mHandler.onEnter(); break; case R.id.hex: mHandler.setText(mHandler.mBaseModule.setMode(Mode.HEXADECIMAL)); view.setSelected(true); ((View) view.getParent()).findViewById(R.id.bin).setSelected(false); ((View) view.getParent()).findViewById(R.id.dec).setSelected(false); applyAllBannedResources(mHandler.mBaseModule, Mode.HEXADECIMAL); break; case R.id.bin: mHandler.setText(mHandler.mBaseModule.setMode(Mode.BINARY)); view.setSelected(true); ((View) view.getParent()).findViewById(R.id.hex).setSelected(false); ((View) view.getParent()).findViewById(R.id.dec).setSelected(false); applyAllBannedResources(mHandler.mBaseModule, Mode.BINARY); break; case R.id.dec: mHandler.setText(mHandler.mBaseModule.setMode(Mode.DECIMAL)); view.setSelected(true); ((View) view.getParent()).findViewById(R.id.bin).setSelected(false); ((View) view.getParent()).findViewById(R.id.hex).setSelected(false); applyAllBannedResources(mHandler.mBaseModule, Mode.DECIMAL); break; case R.id.matrix: mHandler.insert(MatrixView.getPattern(mContext)); returnToBasic(); break; case R.id.matrix_inverse: mHandler.insert(MatrixInverseView.PATTERN); returnToBasic(); break; case R.id.matrix_transpose: mHandler.insert(MatrixTransposeView.PATTERN); returnToBasic(); break; case R.id.plus_row: v = mHandler.mDisplay.getActiveEditText(); if(v instanceof MatrixEditText) ((MatrixEditText) v).getMatrixView().addRow(); break; case R.id.minus_row: v = mHandler.mDisplay.getActiveEditText(); if(v instanceof MatrixEditText) ((MatrixEditText) v).getMatrixView().removeRow(); break; case R.id.plus_col: v = mHandler.mDisplay.getActiveEditText(); if(v instanceof MatrixEditText) ((MatrixEditText) v).getMatrixView().addColumn(); break; case R.id.minus_col: v = mHandler.mDisplay.getActiveEditText(); if(v instanceof MatrixEditText) ((MatrixEditText) v).getMatrixView().removeColumn(); break; case R.id.next: if(mHandler.getText().equals(mErrorString)) mHandler.setText(""); active = mHandler.mDisplay.getActiveEditText(); if(active.getSelectionStart() == active.getText().length()) { v = mHandler.mDisplay.getActiveEditText().focusSearch(View.FOCUS_RIGHT); if(v != null) v.requestFocus(); active = mHandler.mDisplay.getActiveEditText(); active.setSelection(0); } else { active.setSelection(active.getSelectionStart() + 1); } break; // +/-, changes the sign of the current number. Might be useful later // (but removed for now) // case R.id.sign: // if(mHandler.getText().equals(mErrorString)) mHandler.setText(""); // active = mHandler.mDisplay.getActiveEditText(); // int selection = active.getSelectionStart(); // if(active.getText().toString().matches(Logic.NUMBER)) { // if(active.getText().toString().startsWith(String.valueOf(Logic.MINUS))) // { // active.setText(active.getText().toString().substring(1)); // selection--; // } // else { // active.setText(Logic.MINUS + active.getText().toString()); // selection++; // } // if(selection > active.length()) selection--; // if(selection < 0) selection = 0; // active.setSelection(selection); // } // break; case R.id.parentheses: if(mHandler.getText().equals(mErrorString)) mHandler.setText(""); if(mHandler.getText().contains("=")) { String[] equation = mHandler.getText().split("="); if(equation.length > 1) { mHandler.setText(equation[0] + "=(" + equation[1] + ")"); } else { mHandler.setText(equation[0] + "=()"); } } else { mHandler.setText("(" + mHandler.getText() + ")"); } returnToBasic(); break; case R.id.mod: if(mHandler.getText().equals(mErrorString)) mHandler.setText(""); if(mHandler.getText().contains("=")) { String[] equation = mHandler.getText().split("="); if(equation.length > 1) { mHandler.setText(equation[0] + "=" + mModString + "(" + equation[1] + ","); } else { mHandler.insert(mModString + "("); } } else { if(mHandler.getText().length() > 0) { mHandler.setText(mModString + "(" + mHandler.getText() + ","); } else { mHandler.insert(mModString + "("); } } returnToBasic(); break; case R.id.easter: Toast.makeText(mContext, R.string.easter_egg, Toast.LENGTH_SHORT).show(); break; default: if(view instanceof Button) { String text = ((Button) view).getText().toString(); if(text.equals(mDX) || text.equals(mDY)) { // Do nothing } else if(text.length() >= 2) { // Add paren after sin, cos, ln, etc. from buttons text += "("; } mHandler.insert(text); returnToBasic(); } } } private void applyAllBannedResources(BaseModule base, Mode baseMode) { for(Mode key : base.mBannedResources.keySet()) { if(baseMode.compareTo(key) != 0) { applyBannedResources(base, key, true); } } applyBannedResources(base, baseMode, false); } private void applyBannedResources(BaseModule base, Mode baseMode, boolean enabled) { List<Integer> resources = base.mBannedResources.get(baseMode); ViewPager pager = mPager != null ? mPager : mSmallPager; for(Integer resource : resources) { final int resId = resource.intValue(); // There are multiple views with the same id, // but the id is unique per page // Find ids on every page int count = pager.getAdapter().getCount(); for(int i = 0; i < count; i++) { View child = ((CalculatorPageAdapter) pager.getAdapter()).getViewAt(i); View v = child.findViewById(resId); if(v != null) { v.setEnabled(enabled); } } // An especial check when current pager is mLargePager if(mPager == null && mLargePager != null) { count = mLargePager.getAdapter().getCount(); for(int i = 0; i < count; i++) { View child = ((CalculatorPageAdapter) mLargePager.getAdapter()).getViewAt(i); View v = child.findViewById(resId); if(v != null) { v.setEnabled(enabled); } } } } } @Override public boolean onLongClick(View view) { switch(view.getId()) { case R.id.del: mHandler.onClear(); return true; case R.id.next: // Handle back EditText active = mHandler.mDisplay.getActiveEditText(); if(active.getSelectionStart() == 0) { View v = mHandler.mDisplay.getActiveEditText().focusSearch(View.FOCUS_LEFT); if(v != null) v.requestFocus(); active = mHandler.mDisplay.getActiveEditText(); active.setSelection(active.getText().length()); } else { active.setSelection(active.getSelectionStart() - 1); } return true; } if(view.getTag() != null) { String text = (String) view.getTag(); if(!text.isEmpty()) { Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show(); return true; } } if(view instanceof TextView && ((TextView) view).getHint() != null) { String text = ((TextView) view).getHint().toString(); if(text.length() >= 2) { // Add paren after sin, cos, ln, etc. from buttons text += "("; } mHandler.insert(text); returnToBasic(); return true; } return false; } @Override public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { int action = keyEvent.getAction(); // Work-around for spurious key event from IME, bug #1639445 if(action == KeyEvent.ACTION_MULTIPLE && keyCode == KeyEvent.KEYCODE_UNKNOWN) { return true; // eat it } if(keyEvent.getUnicodeChar() == '=') { if(action == KeyEvent.ACTION_UP) { mHandler.onEnter(); } return true; } if(keyCode != KeyEvent.KEYCODE_DPAD_CENTER && keyCode != KeyEvent.KEYCODE_DPAD_UP && keyCode != KeyEvent.KEYCODE_DPAD_DOWN && keyCode != KeyEvent.KEYCODE_ENTER) { if(keyEvent.isPrintingKey() && action == KeyEvent.ACTION_UP) { // Tell the handler that text was updated. mHandler.onTextChanged(); } return false; } /* * We should act on KeyEvent.ACTION_DOWN, but strangely sometimes the * DOWN event isn't received, only the UP. So the workaround is to act * on UP... http://b/issue?id=1022478 */ if(action == KeyEvent.ACTION_UP) { switch(keyCode) { case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_DPAD_CENTER: mHandler.onEnter(); break; case KeyEvent.KEYCODE_DPAD_UP: mHandler.onUp(); break; case KeyEvent.KEYCODE_DPAD_DOWN: mHandler.onDown(); break; } } return true; } private boolean returnToBasic() { if(mPager != null && mPager.getCurrentItem() != Panel.BASIC.getOrder() && CalculatorSettings.returnToBasic(mContext)) { mPager.setCurrentItem(Panel.BASIC.getOrder()); return true; } return false; } }