Android Open Source - tennis-charting-android Match Chart Activity






From Project

Back to project page tennis-charting-android.

License

The source code is released under:

GNU General Public License

If you think the Android project tennis-charting-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.inklily.tennischarting;
//from   w w w .  j av a  2  s  . com
import com.inklily.tennischarting.MatchStorage.MatchStorageNotAvailableException;
import com.inklily.tennischarting.Point.Direction;
import com.inklily.tennischarting.Point.ServeDirection;
import com.inklily.tennischarting.Point.Stroke;
import com.inklily.tennischarting.PointEndDialog.OnPointEndListener;
import com.inklily.tennischarting.util.SystemUiHider;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;

/**
 * Activity to chart matches.
 * 
 * It's a trivial state machine:
 * 
 * SERVE -> STROKE -> POSITION
 *            |          |
 *            \----<<----/
 *
 * TODO: review to ensure all the scoring logic has been removed. This class should be UI only.
 */
public class MatchChartActivity extends FragmentActivity implements OnPointEndListener, SharedPreferences.OnSharedPreferenceChangeListener {
    /**
   * The flags to pass to {@link SystemUiHider#getInstance}.
   */
  private static final int HIDER_FLAGS = SystemUiHider.FLAG_FULLSCREEN;
  private static final float TAP_MAX_DIST = 15.0f;
  private static final double SWINGING_VOLLEY_MAX = Math.toRadians(60.0);
  private static final double SWINGING_VOLLEY_MIN = Math.toRadians(30.0);

  private static final double HALF_VOLLEY_MAX = Math.toRadians(-30.0);
  private static final double HALF_VOLLEY_MIN = Math.toRadians(-60.0);

  private static final double LOB_MAX = Math.toRadians(135.0);
  private static final double DROP_MIN = Math.toRadians(-135.0);

  private static final double TRICK_ANGLE = Math.toRadians(135.0);

    private static final double NET_APPROACH_MIN = Math.toRadians(45.0);
    private static final double NET_APPROACH_MAX = Math.toRadians(135.0);

    private static final double ALT_STROKE_MIN = Math.toRadians(-135.0);
    private static final double ALT_STROKE_MAX = Math.toRadians(-45.0);

    private SharedPreferences mPrefs;
    private ViewGroup contentView;

    private enum State {
    SERVE,
    LOCATION,
    STROKE,
  }

  private State mCurrentState = State.SERVE;

  private PointF mGestureStart = new PointF();
  private PointF mGestureEnd = new PointF();
  private boolean mActiveGesture = false;
  private boolean mDisableInput;

  private Match mMatch;
  private Point mCurrentPoint;

  private SystemUiHider mSystemUiHider;

  private GestureOverlay mGestureOverlay;

  private GuideView mShotGuide;
  private ServeGuide mServeGuid;
  private LocationGuide mLocationGuide;
  private View mCenterLegend;

    private Stroke mCurrentStroke;
    private SQLiteMatchStorage mMatchStorage;
    private Handler mLongPressHandler;

  private Runnable mLongPressRunnable = new Runnable() {
    @Override
    public void run() {
            Point p;

            // Add a partial point if necessary
            if (mCurrentState == State.LOCATION) {
                p = new Point(mCurrentPoint);
                p.addStroke(mCurrentStroke);
            } else {
                p = mCurrentPoint;
            }
      mDisableInput = true;

            // TODO: DI this class for testing
            PointEndDialog pointEndDialog = new PointEndDialog();
      pointEndDialog.show(mMatch, p, getSupportFragmentManager(), "point_end");
      mActiveGesture = false;
    }
    
  };
  
  @SuppressLint("InlinedApi")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mLongPressHandler = new Handler(getMainLooper());
    mMatchStorage = SQLiteMatchStorage.getGlobalInstance(this);
    mDisableInput = false;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
      this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
    } else {
      this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
    setContentView(R.layout.activity_match_chart);

    contentView = (ViewGroup) findViewById(R.id.fullscreen_content);
    mShotGuide = (GuideView) findViewById(R.id.shot_guide);
    mLocationGuide = (LocationGuide) findViewById(R.id.location_guide);
    mServeGuid = (ServeGuide) findViewById(R.id.serve_guide);

    mCenterLegend = findViewById(R.id.center_legend);

    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
    params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
    mGestureOverlay = new GestureOverlay(this);
    contentView.addView(mGestureOverlay, params);


        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        mPrefs.registerOnSharedPreferenceChangeListener(this);

        Long m_id = null;
        if (savedInstanceState != null) {
            m_id = savedInstanceState.getLong("match_id");
            String current_state_string = savedInstanceState.getString("state");
            if (mCurrentState == null)
                mCurrentState = State.SERVE;
            else
                mCurrentState = State.valueOf(current_state_string);
            mCurrentPoint = new Point(savedInstanceState.getString("current_point", ""));
            String current_stroke_string = savedInstanceState.getString("current_stroke");
            if (current_stroke_string == null)
                mCurrentStroke = Stroke.UNKNOWN;
            else
                mCurrentStroke = Stroke.valueOf(current_stroke_string);
        } else {
            Bundle extras = this.getIntent().getExtras();
            if (extras != null && extras.containsKey("match_id")) {
                m_id = extras.getLong("match_id");
            }
            newPoint();
        }

        final Long initial_match_id = m_id;
        mMatchStorage.addOnStorageAvailableListener(new MatchStorage.OnStorageAvailableListener() {
            @Override
            public void onStorageAvailable(MatchStorage storage) {
                if (initial_match_id != null) {
                    try {
                        mMatch = mMatchStorage.retrieveMatch(initial_match_id);
                        updateUI();
                    } catch (MatchStorageNotAvailableException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            }
        });
  }

    @Override
    protected void onPause() {
        super.onPause();
        mLongPressHandler.removeCallbacks(mLongPressRunnable);
    }

    @Override
    protected void onResume() {
        super.onResume();
        fullscreen();
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mMatch != null && mMatch.id != null)
            outState.putLong("match_id", mMatch.id);
        outState.putString("state", mCurrentState.toString());
        outState.putString("current_point", mCurrentPoint == null ? "" : mCurrentPoint.toString());
        outState.putString("current_stroke", mCurrentStroke == null ? "" : mCurrentStroke.toString());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        if (mDisableInput)
            return false;

        if (action == MotionEvent.ACTION_DOWN) {
            mActiveGesture = true;
            mGestureEnd.x = mGestureStart.x = event.getX();
            mGestureEnd.y = mGestureStart.y = event.getY();
            mLongPressHandler.postDelayed(mLongPressRunnable, 1000);
        } else if (action == MotionEvent.ACTION_UP) {
            mLongPressHandler.removeCallbacks(mLongPressRunnable);
            mGestureEnd.x = event.getX();
            mGestureEnd.y = event.getY();
            switch (mCurrentState) {
                case LOCATION:
                    if (mPrefs.getBoolean("return_depth", false) && mCurrentPoint.shotCount() == 1)
                        recordStroke(mLocationGuide.getDirection(event.getX()),
                                mLocationGuide.getDepth(event.getY()));
                    else
                        recordStroke(mLocationGuide.getDirection(event.getX()), null);
                    break;
                case STROKE:
                    mCurrentStroke = detectStroke();

                    // If we're not going to ask the user for the location,
                    // record it now.
                    if (!mPrefs.getBoolean("record_shot_locations", true))
                        recordStroke(null);
                    break;
                case SERVE:
                    recordServe(mServeGuid.getServeDirection(event.getX()));
                    break;
                default:
                    break;
            }
            mActiveGesture = false;
            nextState();
        } else if (action == MotionEvent.ACTION_MOVE) {
            mGestureEnd.x = event.getX();
            mGestureEnd.y = event.getY();
            mGestureOverlay.invalidate();
        } else {
            return super.onTouchEvent(event);
        }
        return false;
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        updateUI();
    }

    @Override
    public void onPointComplete(Point p) {
        mDisableInput = false;
        mCurrentPoint = p;
        savePoint();
        this.mCurrentState = State.SERVE;
        updateUI();
    }

    @Override
    public void onPointContinue(Point p) {
        mDisableInput = false;
        if (p != null) {
            if (mCurrentPoint.toString().equals(p.toString())) {
                mCurrentPoint = p;
                updateUI();
            } else {
                mCurrentPoint = p;
                // The point has changed, Fix the UI
                if (mCurrentPoint.shotCount() > 0)
                    setState(State.STROKE);
                else if (mCurrentPoint.shotCount() == 0)
                    setState(State.SERVE);
            }
        }
    }

    @Override
    public void onReloadMatch() {
        try {
            mMatch = mMatchStorage.retrieveMatch(mMatch.id);
        } catch (MatchStorageNotAvailableException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onMatchOver() {
        endMatch();
    }

    private void fullscreen() {
        // Do the fullscreenish thing
        if (Build.VERSION.SDK_INT < 16) {
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
        }
    }

  private void newPoint() {
    mCurrentPoint = new Point();
  }

  private void savePoint() {
        try {
            mMatch.addPoint(mCurrentPoint, mMatchStorage);
        } catch (MatchStorageNotAvailableException e) {
            // TODO: notify the user
            e.printStackTrace();
        }

        newPoint();

        if (mMatch.isComplete()) {
            endMatch();
        }
  }

    private void endMatch () {
        Intent intent = new Intent(this, MatchDetailActivity.class);
        intent.putExtra("match_id", mMatch.id);
        intent.putExtra("review", false);
        startActivity(intent);
    }


  private void updateUI() {
        fullscreen();
    mServeGuid.setVisibility(View.INVISIBLE);
    mLocationGuide.setVisibility(View.INVISIBLE);
    mShotGuide.setVisibility(View.INVISIBLE);

    switch (mCurrentState) {
    case SERVE:
      mServeGuid.setVisibility(View.VISIBLE);
      mServeGuid.setPoint(mMatch, mCurrentPoint, mPrefs);
      break;
    case STROKE:
      mShotGuide.setVisibility(View.VISIBLE);
      mShotGuide.setPoint(mMatch, mCurrentPoint, mPrefs);
      break;
    case LOCATION:
      mLocationGuide.setVisibility(View.VISIBLE);
      mLocationGuide.setPoint(mMatch, mCurrentPoint, mPrefs);
      break;
    }
  }

    private void setState(State s) {
        mCurrentState = s;
        updateUI();
    }
  
  private void nextState() {
    switch (mCurrentState) {
    case SERVE:
            mCurrentState = State.STROKE;
      break;
    case LOCATION:
            mCurrentState = State.STROKE;
      break;
    case STROKE:
            if (mPrefs.getBoolean("record_shot_locations", true))
                mCurrentState = State.LOCATION;
      break;
    }

    updateUI();
  }


    private void recordServe(Point.ServeDirection dir) {
        float dX = mGestureStart.x  - mGestureEnd.x;
        float dY = mGestureStart.y  - mGestureEnd.y;

        if (distance(dX, dY) > TAP_MAX_DIST) {
            double angle = angle(dX, dY);
            if (angle > NET_APPROACH_MIN && angle < NET_APPROACH_MAX) {
                mCurrentPoint.serve(dir, Point.Approach.SERVE_AND_VOLLEY);
            } else {
                mCurrentPoint.serve(ServeDirection.UNKNOWN);
            }
        } else {
            mCurrentPoint.serve(dir);
        }
    }

    private boolean recordStroke(Direction direction) {
        return recordStroke(direction, null);
    }

  /**
   * Records the stroke based on the current gesture.
   * @param direction direction of the stroke
     * @param depth depth of the stroke
   */
  private boolean recordStroke(Direction direction, Point.Depth depth) {
        float dX = mGestureStart.x  - mGestureEnd.x;
        float dY = mGestureStart.y  - mGestureEnd.y;

        if (distance(dX, dY) < TAP_MAX_DIST) {
            mCurrentPoint.addStroke(mCurrentStroke, direction, depth);
        } else { // Find a gesture
            double angle = angle(dX, dY);
            if (angle > NET_APPROACH_MIN && angle < NET_APPROACH_MAX) {
                mCurrentPoint.addStroke(mCurrentStroke, direction, depth, Point.Approach.NET_APPROACH);
            } else if (angle > ALT_STROKE_MIN && angle < ALT_STROKE_MAX) {
                switch (mCurrentStroke) {
                    case FOREHAND_GROUNDSTROKE:
                    case FOREHAND_LOB:
                    case FOREHAND_DROPSHOT:
                    case FOREHAND_SLICE:
                    case BACKHAND_GROUNDSTROKE:
                    case BACKHAND_LOB:
                    case BACKHAND_DROPSHOT:
                    case BACKHAND_SLICE:
                    case TRICK:
                        mCurrentPoint.addStroke(mCurrentStroke, direction, depth, null, Point.NetPosition.AT_NET);
                        break;
                    default:
                        mCurrentPoint.addStroke(mCurrentStroke, direction, depth, null, Point.NetPosition.AT_BASELINE);
                        break;
                }
            } else { // Unknown direction
                mCurrentPoint.addStroke(mCurrentStroke);
            }
        }

    Log.i("Shot", mCurrentPoint.toString());

    return true;
  }

  private Point.Stroke detectCenterStroke(double distance, double angle) {

    if (distance < TAP_MAX_DIST * getResources().getDisplayMetrics().density)
      return Point.Stroke.UNKNOWN;

    if (angle > TRICK_ANGLE || angle < -TRICK_ANGLE)
      return Point.Stroke.TRICK;
    else if (angle > 0)
      return Point.Stroke.FOREHAND_OVERHEAD;
    else
      return Point.Stroke.BACKHAND_OVERHEAD;
  }

    private static double distance(float dX, float dY) {
        return Math.sqrt(dX*dX + dY*dY);
    }

    private static double angle(float dX, float dY) {
        return Math.atan2(dY, dX);
    }

  private Point.Stroke detectStroke(Point.StrokeIndex index, double distance, double angle) {
    if (distance < TAP_MAX_DIST * getResources().getDisplayMetrics().density)
      return index.GROUNDSTROKE;

    if (angle > LOB_MAX || angle < DROP_MIN)
      return index.SLICE;
    if (angle > SWINGING_VOLLEY_MAX)
      return index.LOB;
    if (angle > SWINGING_VOLLEY_MIN)
      return index.SWINGINGVOLLEY;
    if (angle > HALF_VOLLEY_MAX)
      return index.VOLLEY;
    if (angle > HALF_VOLLEY_MIN)
      return index.HALFVOLLEY;
    if (angle > DROP_MIN)
      return index.DROPSHOT;

    return Point.Stroke.UNKNOWN;
  }

  private Point.Stroke detectStroke() {
    float dX = mGestureStart.x  - mGestureEnd.x;
    float dY = mGestureStart.y  - mGestureEnd.y;
    boolean left = mGestureStart.x < mCenterLegend.getLeft();
    boolean right = mGestureStart.x > mCenterLegend.getRight();
    boolean rightForehand = mShotGuide.isRightHanded();

    if (!right)
      dX = -dX;

        // Find the stroke type
    if ((right && rightForehand) || (left && !rightForehand)) {
      return detectStroke(Point.FOREHAND_STROKES, distance(dX, dY), angle(dX, dY));
    } else if (left || right) {
      return detectStroke(Point.BACKHAND_STROKES, distance(dX, dY), angle(dX, dY));
    } else {
      return detectCenterStroke(dX, dY);
    }
  }

  public class GestureOverlay extends View {
    Paint mPaint = new Paint();

    public GestureOverlay(Context context) {
      super(context);
      mPaint.setColor(Color.RED);
      mPaint.setStrokeWidth(10.0f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      if (mActiveGesture) {
        canvas.drawLine(mGestureStart.x, mGestureStart.y, mGestureEnd.x, mGestureEnd.y, mPaint);
      }
    }
  }

  public static class GuideView extends RelativeLayout {
    final float LINE_WIDTH = 15.0f;
    final float GUIDE_WIDTH = 2.0f;
    final int LINE_COLOR = Color.rgb(220, 220, 220);
    final int GUIDE_COLOR = Color.rgb(220, 220, 220);
    private boolean nearCourt = true;
    private boolean deuceCourt = true;
        protected boolean strokeRightHanded;
        protected boolean locRightHanded;
    protected Paint mLinePaint = new Paint();
    protected Paint mGuidePaint = new Paint();
        private boolean locNearCourt;

        public GuideView(Context context, AttributeSet attrs) {
      super(context, attrs);
      DisplayMetrics metrics = getResources().getDisplayMetrics();
      float density = metrics.density;
      mGuidePaint.setColor(GUIDE_COLOR);
      mGuidePaint.setStrokeWidth(GUIDE_WIDTH * density);
      float dash_length = GUIDE_WIDTH * density * 2;
      float[] ivals = {dash_length,dash_length };
      mGuidePaint.setPathEffect(new DashPathEffect(ivals, 0.0f));
      mLinePaint.setColor(LINE_COLOR);
      mLinePaint.setStrokeWidth(LINE_WIDTH * density);
    }

        protected boolean strokeNear() {
            return nearCourt;
        }

        protected boolean locNear() {
            return locNearCourt;
        }
        protected boolean deuce() {
            return deuceCourt;
        }

        public void setPoint(Match match, Point point, SharedPreferences prefs) {
            //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences();
            if (prefs.getBoolean("no_end_change", false)) {
                nearCourt = true;
                locNearCourt = true;
            } else {
                nearCourt = match.nextNearFor(point);
                locNearCourt = !nearCourt;
            }
      deuceCourt = match.deuceCourt();
            if (prefs.getBoolean("no_handedness", false)) {
                strokeRightHanded = true;
                locRightHanded = true;
            } else {
                strokeRightHanded = match.nextStrokeRighthandedFor(point);
                locRightHanded = match.nextLocRighthandedFor(point);
            }

            invalidate();
    }

    protected void drawGuides(Canvas canvas) {
      float h = (float)this.getHeight();
      float w = (float)this.getWidth();

      // Draw guides
      float g1x = w * 0.3f;
      float g2x = w * 0.7f;
      canvas.drawLine(g1x, 0.0f, g1x, h, mGuidePaint);
      canvas.drawLine(g2x, 0.0f, g2x, h, mGuidePaint);
    }

        public boolean isRightHanded() {
            return strokeRightHanded == nearCourt;
        }
    }

  public static class ServeGuide extends GuideView {
    final float SERVICE_LINE_INSET = 50.0f;
    final float T_LINE_INSET = 40.0f;
    private TextView serve_l = null;
    private TextView serve_r = null;

    public ServeGuide(Context context, AttributeSet attrs) {
      super(context, attrs);
    }

    public ServeDirection getServeDirection(float x) {
      float w = (float)this.getWidth();
      float g1x = w * 0.3f;
      float g2x = w * 0.7f;
      if (x >= g1x && x <= g2x) {
        return Point.ServeDirection.BODY;
      }

      if (locNear() == deuce()) {
        if (x < g1x)
          return Point.ServeDirection.T;
        else
          return Point.ServeDirection.WIDE;
      } else {
        if (x < g1x)
          return Point.ServeDirection.WIDE;
        else
          return Point.ServeDirection.T;
      }

    }

    @Override
        public void setPoint(Match match, Point point, SharedPreferences prefs) {
      super.setPoint(match, point, prefs);

            ((TextView) this.findViewById(R.id.serve_server)).setText(match.playerName(match.server()));
            ((TextView) this.findViewById(R.id.serve_pts_score)).setText(
                    String.format("%s %s %s",
                            match.score().isFirstServe() ?
                                    getResources().getString(R.string.first) :
                                    getResources().getString(R.string.second),
                            getResources().getString(R.string.serving_at),
                            match.score().ptsScore())
            );
            ((TextView) this.findViewById(R.id.serve_score)).setText(match.score().gameScore());

      if (serve_l == null)
        serve_l = ((TextView) this.findViewById(R.id.serve_left_loc));
      if (serve_r == null)
        serve_r = ((TextView) this.findViewById(R.id.serve_right_loc));

      if (locNear() == deuce()) {
        serve_l.setText(R.string.serve_t);
        serve_r.setText(R.string.serve_wide);
      } else {
        serve_l.setText(R.string.serve_wide);
        serve_r.setText(R.string.serve_t);
      }

    }

    @SuppressWarnings("ConstantConditions")
        @Override
    protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      float h = (float)this.getHeight();
      float w = (float)this.getWidth();

      // Draw court lines
      if (deuce() && locNear()) {
        canvas.drawLine(w - LINE_WIDTH / 2, 0.0f, w - LINE_WIDTH / 2, h, mLinePaint); // sideline
        canvas.drawLine(0.0f, h - SERVICE_LINE_INSET, w, h - SERVICE_LINE_INSET, mLinePaint); // service line
        canvas.drawLine(T_LINE_INSET, 0.0f, T_LINE_INSET, h - SERVICE_LINE_INSET, mLinePaint); // T line
      } else if (deuce() && !locNear()) {
        canvas.drawLine(LINE_WIDTH / 2, 0.0f, LINE_WIDTH / 2, h, mLinePaint); // sideline
        canvas.drawLine(0.0f, SERVICE_LINE_INSET, w, SERVICE_LINE_INSET, mLinePaint); // service line
        canvas.drawLine(w - T_LINE_INSET, SERVICE_LINE_INSET, w - T_LINE_INSET, h, mLinePaint); // T line
      } else if (!deuce() && locNear()) {
        canvas.drawLine(LINE_WIDTH / 2, 0.0f, LINE_WIDTH / 2, h, mLinePaint); // sideline
        canvas.drawLine(0.0f, h - SERVICE_LINE_INSET, w, h - SERVICE_LINE_INSET, mLinePaint); // service line
        canvas.drawLine(w - T_LINE_INSET, 0, w - T_LINE_INSET, h - SERVICE_LINE_INSET, mLinePaint); // T line
      } else if (!deuce() && !locNear()) {
        canvas.drawLine(w - LINE_WIDTH / 2, 0.0f, w - LINE_WIDTH / 2, h, mLinePaint); // sideline
        canvas.drawLine(0.0f, SERVICE_LINE_INSET, w, SERVICE_LINE_INSET, mLinePaint); // service line
        canvas.drawLine(T_LINE_INSET, SERVICE_LINE_INSET, T_LINE_INSET, h, mLinePaint); // T line
      }

      this.drawGuides(canvas);
    }
  }

  public static class LocationGuide extends GuideView {
    private TextView shot_l = null;
    private TextView shot_r = null;
        private boolean drawDepthGuides;
        private Paint mDepthPaint;
        final float DEPTH_SHORT = 0.3f;
        final float DEPTH_LONG = 0.7f;

        public LocationGuide(Context context, AttributeSet attrs) {
      super(context, attrs);
            mDepthPaint = new Paint(mGuidePaint);
            mDepthPaint.setColor(Color.rgb(255, 180, 180));
    }

        @Override
        public void setPoint(Match match, Point point, SharedPreferences prefs) {
            super.setPoint(match, point, prefs);

            if (prefs.getBoolean("return_depth", false) && point.shotCount() == 1) {
                drawDepthGuides = true;
            } else {
                drawDepthGuides = false;
            }

      if (shot_l == null)
        shot_l = ((TextView) this.findViewById(R.id.shot_left_loc));
      if (shot_r == null)
        shot_r = ((TextView) this.findViewById(R.id.shot_right_loc));

      if (locNear() == locRightHanded) {
        shot_l.setText(R.string.backhand_side);
        shot_r.setText(R.string.forehand_side);
      } else {
        shot_l.setText(R.string.forehand_side);
        shot_r.setText(R.string.backhand_side);
      }
    }

        public Point.Depth getDepth(float y) {
            float h = (float)this.getHeight();
            float g1y = h * DEPTH_SHORT;
            float g2y = h * DEPTH_LONG;
            if (y >= g1y && y <= g2y) {
                return Point.Depth.MID;
            }

            if (locNear()) {
                if (y < g1y)
                    return Point.Depth.SHORT;
                else
                    return Point.Depth.DEEP;
            } else {
                if (y < g1y)
                    return Point.Depth.DEEP;
                else
                    return Point.Depth.SHORT;
            }
        }

    public Direction getDirection(float x) {
      float w = (float)this.getWidth();
      float g1x = w * 0.3f;
      float g2x = w * 0.7f;
      if (x >= g1x && x <= g2x) {
        return Point.Direction.MIDDLE;
      }

      if (locNear()) {
        if (x < g1x)
          return Point.Direction.AD;
        else
          return Point.Direction.DEUCE;
      } else {
        if (x < g1x)
          return Point.Direction.DEUCE;
        else
          return Point.Direction.AD;
      }

    }

        public boolean isRightHanded() {
            return locRightHanded == locNear();
        }

    @Override
    protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);

      float h = (float)this.getHeight();
      float w = (float)this.getWidth();

      // Draw court lines
      float T_y1 = 0.0f;
      float T_y2 = 0.0f;
      if (locNear()) {
        T_y1 = h * 0.33f;
        T_y2 = 0.0f;
      } else {
        T_y1 = h * 0.66f;
        T_y2 = h;
      }

      // Sidelines
      canvas.drawLine(LINE_WIDTH / 2, 0.0f, LINE_WIDTH / 2, h, mLinePaint);
      canvas.drawLine(w - LINE_WIDTH / 2, 0.0f, w - LINE_WIDTH / 2, h, mLinePaint);

      // Baseline
      if (locNear())
        canvas.drawLine(0.0f, h - LINE_WIDTH / 2, w, h - LINE_WIDTH / 2, mLinePaint);
      else
        canvas.drawLine(0.0f, LINE_WIDTH / 2, w, LINE_WIDTH / 2, mLinePaint);

      // Service line
      canvas.drawLine(0.0f, T_y1, w, T_y1, mLinePaint);

      // T line
      canvas.drawLine(w / 2, T_y1, w / 2, T_y2, mLinePaint);

      // Depth guides
            if (drawDepthGuides) {
                float g1y = h * DEPTH_SHORT;
                float g2y = h * DEPTH_LONG;
                canvas.drawLine(0.0f, g1y, w, g1y, mDepthPaint);
                canvas.drawLine(0.0f, g2y, w, g2y, mDepthPaint);
            }

            this.drawGuides(canvas);

    }
  }

  public static class ShotGuide extends GuideView {
    private TextView right_hand = null;
    private TextView left_hand = null;

    public ShotGuide(Context context, AttributeSet attrs) {
      super(context, attrs);
    }

    @Override
        public void setPoint(Match match, Point point, SharedPreferences prefs) {
            super.setPoint(match, point, prefs);
            String name;
            if (point.nextPlayer() == 1)
                name = match.playerName(match.server());
            else
                name = match.playerName(match.returner());
            ((TextView) this.findViewById(R.id.stoke_player)).setText(name);

      if (right_hand == null)
        right_hand = ((TextView) this.findViewById(R.id.right_hand));
      if (left_hand == null)
        left_hand = ((TextView) this.findViewById(R.id.left_hand));

      if (strokeNear() == strokeRightHanded) {
        left_hand.setText(R.string.backhand);
        right_hand.setText(R.string.forehand);
      } else {
        left_hand.setText(R.string.forehand);
        right_hand.setText(R.string.backhand);
      }
    }
  }

}




Java Source Code List

com.inklily.tennischarting.HelpActivity.java
com.inklily.tennischarting.MainActivity.java
com.inklily.tennischarting.MatchChartActivity.java
com.inklily.tennischarting.MatchDetailActivity.java
com.inklily.tennischarting.MatchInfoActivity.java
com.inklily.tennischarting.MatchReviewActivity.java
com.inklily.tennischarting.MatchStorage.java
com.inklily.tennischarting.Match.java
com.inklily.tennischarting.PointEndDialog.java
com.inklily.tennischarting.Point.java
com.inklily.tennischarting.SQLiteMatchStorage.java
com.inklily.tennischarting.Score.java
com.inklily.tennischarting.SettingsActivity.java
com.inklily.tennischarting.util.SystemUiHiderBase.java
com.inklily.tennischarting.util.SystemUiHiderHoneycomb.java
com.inklily.tennischarting.util.SystemUiHider.java