/*
* 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;
}
}