new interface implementation

This commit is contained in:
serso
2011-09-10 22:20:58 +04:00
parent 0063f193ff
commit b846f07781
15 changed files with 808 additions and 190 deletions

View File

@@ -10,7 +10,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.util.TypedValue;
import android.view.*;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.view.*;
@@ -26,7 +28,9 @@ import android.util.Log;
import android.widget.EditText;
import org.solovyev.util.math.Point2d;
public class CalculatorActivity extends Activity {
public class CalculatorActivity extends Activity implements FontSizeAdjuster{
private static final int HVGA_WIDTH_PIXELS = 320;
@NotNull
private EditText editText;
@@ -273,4 +277,18 @@ public class CalculatorActivity extends Activity {
private void showHelp() {
Log.d(CalculatorActivity.class + "showHelp()", "Show help!");
}
/**
* The font sizes in the layout files are specified for a HVGA display.
* Adjust the font sizes accordingly if we are running on a different
* display.
*/
@Override
public void adjustFontSize(@NotNull TextView view) {
float fontPixelSize = view.getTextSize();
Display display = getWindowManager().getDefaultDisplay();
int h = Math.min(display.getWidth(), display.getHeight());
float ratio = (float)h/HVGA_WIDTH_PIXELS;
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontPixelSize*ratio);
}
}

View File

@@ -1,7 +1,6 @@
package org.solovyev.android.calculator;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -24,7 +23,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.prefs.Preferences;
/**
* User: serso
@@ -33,14 +31,10 @@ import java.util.prefs.Preferences;
*/
public class DragButtonCalibrationActivity extends Activity {
@NotNull
private DragDirection dragDirection = DragDirection.up;
@NotNull
private final List<DragData> dragHistory = new ArrayList<DragData>();
@NotNull
private ImageView calibrationArrow;
private final Map<DragButton, CalibrationArrow> map = new HashMap<DragButton, CalibrationArrow>();
public static final String PREFERENCES = "dragButtonPreferences";
@@ -52,7 +46,6 @@ public class DragButtonCalibrationActivity extends Activity {
private static final float DEFAULT_VALUE = -999;
private static final int MIN_HISTORY_FOR_CALIBRATION = 10;
public static final String INTENT_ACTION = "org.solovyev.android.calculator.DragButtonPreferencesChanged";
;
public static enum PreferenceType {
angle,
@@ -67,26 +60,36 @@ public class DragButtonCalibrationActivity extends Activity {
setContentView(R.layout.drag_button_calibration);
final DragButton calibrationButton = (DragButton) findViewById(R.id.calibrationButton);
calibrationButton.setOnDragListener(new CalibrationOnDragListener());
calibrationArrow = (ImageView) findViewById(R.id.calibrationArrow);
createDragDirection(0);
createCalibrationButton(R.id.calibrationButtonRight, R.id.calibrationArrowRight);
createCalibrationButton(R.id.calibrationButtonLeft, R.id.calibrationArrowLeft);
}
private void createDragDirection(long timeout) {
private void createCalibrationButton(int buttonId, int arrowId) {
final DragButton calibrationButton = (DragButton) findViewById(buttonId);
calibrationButton.setOnDragListener(new CalibrationOnDragListener());
ImageView imageView = (ImageView) findViewById(arrowId);
CalibrationArrow calibrationArrow = new CalibrationArrow(imageView);
createDragDirection(0, calibrationArrow);
map.put(calibrationButton, calibrationArrow);
}
private void createDragDirection(long timeout, @NotNull final CalibrationArrow calibrationArrow) {
new Handler().postDelayed(new Runnable() {
public void run() {
dragDirection = Math.random() > 0.5 ? DragDirection.up : DragDirection.down;
calibrationArrow.dragDirection = Math.random() > 0.5 ? DragDirection.up : DragDirection.down;
calibrationArrow.setImageResource(dragDirection == DragDirection.down ? R.drawable.down : R.drawable.up);
calibrationArrow.calibrationArrow.setImageResource(calibrationArrow.dragDirection == DragDirection.down ? R.drawable.down : R.drawable.up);
}
}, timeout);
}
public void restartClickHandler(View v) {
createDragDirection(0);
for (CalibrationArrow calibrationArrow : map.values()) {
createDragDirection(0, calibrationArrow);
}
}
@@ -109,6 +112,9 @@ public class DragButtonCalibrationActivity extends Activity {
double angle = Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, SimpleOnDragListener.axis), endPoint));
final CalibrationArrow calibrationArrow = map.get(dragButton);
final DragDirection dragDirection = calibrationArrow.dragDirection;
assert dragDirection == DragDirection.up || dragDirection == DragDirection.down;
double deviationAngle = angle;
@@ -117,13 +123,13 @@ public class DragButtonCalibrationActivity extends Activity {
}
if (deviationAngle > 45) {
calibrationArrow.setImageResource(R.drawable.not_ok);
calibrationArrow.calibrationArrow.setImageResource(R.drawable.not_ok);
} else {
calibrationArrow.setImageResource(R.drawable.ok);
calibrationArrow.calibrationArrow.setImageResource(R.drawable.ok);
dragHistory.add(new DragData(dragDirection, distance, angle, (motionEvent.getEventTime() - motionEvent.getDownTime())));
}
createDragDirection(500);
createDragDirection(500, calibrationArrow);
return true;
}
@@ -372,4 +378,16 @@ public class DragButtonCalibrationActivity extends Activity {
return time;
}
}
private class CalibrationArrow {
@NotNull
private ImageView calibrationArrow;
@NotNull
private DragDirection dragDirection = DragDirection.up;
private CalibrationArrow(@NotNull ImageView calibrationArrow) {
this.calibrationArrow = calibrationArrow;
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* 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 org.solovyev.android.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.widget.Button;
import android.view.MotionEvent;
import android.content.res.Resources;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.R;
import org.solovyev.util.StringUtils;
import org.solovyev.util.math.Point2d;
/**
* NOTE: copied from com.android.calculator2.ColorButton
*/
/**
* Button with click-animation effect.
*/
public class ColorButton extends Button {
int CLICK_FEEDBACK_COLOR;
static final int CLICK_FEEDBACK_INTERVAL = 10;
static final int CLICK_FEEDBACK_DURATION = 350;
@NotNull
private Point2d textPosition;
private long mAnimStart;
private Paint mFeedbackPaint;
public ColorButton(Context context, AttributeSet attrs) {
this(context, attrs, true);
}
public ColorButton(Context context, AttributeSet attrs, boolean init) {
super(context, attrs);
if (init) {
init(context);
}
}
protected void init(Context context) {
Resources res = getResources();
CLICK_FEEDBACK_COLOR = res.getColor(R.color.magic_flame);
mFeedbackPaint = new Paint();
mFeedbackPaint.setStyle(Style.STROKE);
mFeedbackPaint.setStrokeWidth(2);
getPaint().setColor(res.getColor(R.color.button_text));
mAnimStart = -1;
if (context instanceof FontSizeAdjuster) {
((FontSizeAdjuster) context).adjustFontSize(this);
}
}
@Override
public void onSizeChanged(int w, int h, int oldW, int oldH) {
measureText();
}
protected void measureText() {
Paint paint = getPaint();
if (getText() != null) {
textPosition = getTextPosition(paint, getText());
}
}
private Point2d getTextPosition(@NotNull Paint paint, @NotNull CharSequence text) {
final Point2d result = new Point2d();
result.setX((getWidth() - paint.measureText(text.toString())) / 2);
float height = getHeight() - paint.ascent() - paint.descent();
result.setY(height / 2);
return result;
}
@Override
protected void onTextChanged(CharSequence text, int start, int before, int after) {
measureText();
}
private void drawMagicFlame(int duration, Canvas canvas) {
int alpha = 255 - 255 * duration / CLICK_FEEDBACK_DURATION;
int color = CLICK_FEEDBACK_COLOR | (alpha << 24);
mFeedbackPaint.setColor(color);
canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, mFeedbackPaint);
}
@Override
public void onDraw(Canvas canvas) {
if (mAnimStart != -1) {
int animDuration = (int) (System.currentTimeMillis() - mAnimStart);
if (animDuration >= CLICK_FEEDBACK_DURATION) {
mAnimStart = -1;
} else {
drawMagicFlame(animDuration, canvas);
postInvalidateDelayed(CLICK_FEEDBACK_INTERVAL);
}
} else if (isPressed()) {
drawMagicFlame(0, canvas);
}
CharSequence text = getText();
if (text != null && textPosition != null) {
canvas.drawText(text, 0, text.length(), textPosition.getX(), textPosition.getY(), getPaint());
}
}
public void animateClickFeedback() {
mAnimStart = System.currentTimeMillis();
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
animateClickFeedback();
break;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
invalidate();
break;
}
return result;
}
}

View File

@@ -2,12 +2,16 @@ package org.solovyev.android.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Html;
import android.text.TextPaint;
import android.util.AttributeSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.util.StringUtils;
import org.solovyev.util.math.Point2d;
/**
* User: serso
@@ -25,15 +29,20 @@ public class DirectionDragButton extends DragButton {
@Nullable
private String textMiddle;
@NotNull
private Point2d textUpPosition;
@NotNull
private Point2d textDownPosition;
@NotNull
private TextPaint upDownTextPaint;
public DirectionDragButton(Context context, @NotNull AttributeSet attrs) {
super(context, attrs);
super(context, attrs, false);
init(context, attrs);
}
public DirectionDragButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(@NotNull Context context, @NotNull AttributeSet attrs) {
@@ -55,19 +64,81 @@ public class DirectionDragButton extends DragButton {
// backup text
this.textMiddle = String.valueOf(getText());
setText(Html.fromHtml(getStyledUpDownText(this.textUp) + "<br><b>" + StringUtils.getNotEmpty(this.textMiddle, "&nbsp;") + "</b><br>" + getStyledUpDownText(this.textDown)));
super.init(context);
}
// change top padding in order to show all text
setPadding(getPaddingLeft(), -7, getPaddingRight(), getPaddingBottom());
@Override
protected void measureText() {
super.measureText();
final Paint basePaint = getPaint();
initUpDownTextPaint(basePaint);
if (textUp != null) {
textUpPosition = getTextPosition(upDownTextPaint, basePaint, textUp, 1);
}
if (textDown != null) {
textDownPosition = getTextPosition(upDownTextPaint, basePaint, textDown, -1);
}
if ( textDownPosition != null && textUpPosition != null ) {
if ( textDownPosition.getX() > textUpPosition.getX() ) {
textDownPosition.setX(textUpPosition.getX());
} else {
textUpPosition.setX(textDownPosition.getX());
}
}
}
private Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, float direction) {
final Point2d result = new Point2d();
float width = paint.measureText(text.toString() + " ");
result.setX(getWidth() - width);
float selfHeight = paint.ascent() + paint.descent();
basePaint.measureText(StringUtils.getNotEmpty(getText(), "|"));
float height = getHeight() - basePaint.ascent() - basePaint.descent();
if (direction < 0) {
result.setY(height / 2 - direction * height / 3 + selfHeight);
} else {
result.setY(height / 2 - direction * height / 3);
}
return result;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
initUpDownTextPaint(null);
if (textUp != null && textUpPosition != null) {
canvas.drawText(textUp, 0, textUp.length(), textUpPosition.getX(), textUpPosition.getY(), upDownTextPaint);
}
if (textDown != null && textDownPosition != null) {
canvas.drawText(textDown, 0, textDown.length(), textDownPosition.getX(), textDownPosition.getY(), upDownTextPaint);
}
}
private void initUpDownTextPaint(@Nullable Paint paint) {
if (paint == null) {
paint = getPaint();
}
upDownTextPaint = new TextPaint(paint);
upDownTextPaint.setAlpha(150);
upDownTextPaint.setTextSize(paint.getTextSize() / 2);
}
private String getStyledUpDownText(@Nullable String text) {
final StringBuilder sb = new StringBuilder();
sb.append("<font color='#585858'><small><small>");
sb.append(StringUtils.getNotEmpty(text, "&nbsp;"));
sb.append("</small></small></font>");
return sb.toString();
return StringUtils.getNotEmpty(text, "&nbsp;");
}
public void setTextUp(@Nullable String textUp) {

View File

@@ -2,22 +2,15 @@ package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.common.utils.StringsUtils;
import org.solovyev.util.StringUtils;
import org.solovyev.util.math.MathUtils;
import org.solovyev.util.math.Point2d;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Html;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
public class DragButton extends Button {
public class DragButton extends ColorButton {
@Nullable
private Point2d startPoint = null;
@@ -28,13 +21,15 @@ public class DragButton extends Button {
private final OnTouchListener onTouchListener = new OnTouchListenerImpl();
public DragButton(Context context, @NotNull AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this.onTouchListener);
this(context, attrs, true);
}
public DragButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
public DragButton(Context context, @NotNull AttributeSet attrs, boolean init) {
super(context, attrs, false);
setOnTouchListener(this.onTouchListener);
if ( init ) {
super.init(context);
}
}
public void setOnDragListener(@Nullable OnDragListener onDragListener) {

View File

@@ -0,0 +1,14 @@
package org.solovyev.android.view;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
/**
* User: serso
* Date: 9/10/11
* Time: 7:21 PM
*/
public interface FontSizeAdjuster {
void adjustFontSize(@NotNull TextView textView);
}

View File

@@ -0,0 +1,144 @@
/*
* 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 org.solovyev.android.view;
import android.view.animation.TranslateAnimation;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector;
import android.widget.FrameLayout;
import android.content.Context;
import android.util.AttributeSet;
class PanelSwitcher extends FrameLayout {
private static final int MAJOR_MOVE = 60;
private static final int ANIM_DURATION = 400;
private GestureDetector mGestureDetector;
private int mCurrentView;
private View mChildren[] = new View[0];
private int mWidth;
private TranslateAnimation inLeft;
private TranslateAnimation outLeft;
private TranslateAnimation inRight;
private TranslateAnimation outRight;
private static final int LEFT = 1;
private static final int RIGHT = 2;
private int mPreviousMove;
public PanelSwitcher(Context context, AttributeSet attrs) {
super(context, attrs);
mCurrentView = 0;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
int dx = (int) (e2.getX() - e1.getX());
// don't accept the fling if it's too short
// as it may conflict with a button push
if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.abs(velocityY)) {
if (velocityX > 0) {
moveRight();
} else {
moveLeft();
}
return true;
} else {
return false;
}
}
});
}
void setCurrentIndex(int current) {
mCurrentView = current;
updateCurrentView();
}
private void updateCurrentView() {
for (int i = mChildren.length-1; i >= 0 ; --i) {
mChildren[i].setVisibility(i==mCurrentView ? View.VISIBLE : View.GONE);
}
}
@Override
public void onSizeChanged(int w, int h, int oldW, int oldH) {
mWidth = w;
inLeft = new TranslateAnimation(mWidth, 0, 0, 0);
outLeft = new TranslateAnimation(0, -mWidth, 0, 0);
inRight = new TranslateAnimation(-mWidth, 0, 0, 0);
outRight = new TranslateAnimation(0, mWidth, 0, 0);
inLeft.setDuration(ANIM_DURATION);
outLeft.setDuration(ANIM_DURATION);
inRight.setDuration(ANIM_DURATION);
outRight.setDuration(ANIM_DURATION);
}
protected void onFinishInflate() {
int count = getChildCount();
mChildren = new View[count];
for (int i = 0; i < count; ++i) {
mChildren[i] = getChildAt(i);
}
updateCurrentView();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
void moveLeft() {
// <--
if (mCurrentView < mChildren.length - 1 && mPreviousMove != LEFT) {
mChildren[mCurrentView+1].setVisibility(View.VISIBLE);
mChildren[mCurrentView+1].startAnimation(inLeft);
mChildren[mCurrentView].startAnimation(outLeft);
mChildren[mCurrentView].setVisibility(View.GONE);
mCurrentView++;
mPreviousMove = LEFT;
}
}
void moveRight() {
// -->
if (mCurrentView > 0 && mPreviousMove != RIGHT) {
mChildren[mCurrentView-1].setVisibility(View.VISIBLE);
mChildren[mCurrentView-1].startAnimation(inRight);
mChildren[mCurrentView].startAnimation(outRight);
mChildren[mCurrentView].setVisibility(View.GONE);
mCurrentView--;
mPreviousMove = RIGHT;
}
}
int getCurrentIndex() {
return mCurrentView;
}
}

View File

@@ -5,13 +5,13 @@ import org.jetbrains.annotations.Nullable;
public class StringUtils {
public static boolean isEmpty ( @Nullable String s ){
public static boolean isEmpty ( @Nullable CharSequence s ){
return s == null || s.length() == 0;
}
@NotNull
public static String getNotEmpty ( @Nullable String s, @NotNull String defaultValue ){
return isEmpty(s) ? defaultValue : s;
public static String getNotEmpty ( @Nullable CharSequence s, @NotNull String defaultValue ){
return isEmpty(s) ? defaultValue : s.toString();
}
}