/**
   * @param canvas
   * @param mapView
   * @param shadow
   * @see SegmentOverlay#draw(Canvas, MapView, boolean)
   */
  private void calculateDots() {
    mPathCalculation.reset();
    mDotPathCalculation.clear();

    mCalculatedPoints = 0;

    if (mWaypointsCursor == null) {
      mWaypointsCursor =
          this.mResolver.query(
              this.mWaypointsUri,
              new String[] {
                Waypoints.LATITUDE,
                Waypoints.LONGITUDE,
                Waypoints.SPEED,
                Waypoints.TIME,
                Waypoints.ACCURACY
              },
              null,
              null,
              null);
    }
    if (mRequeryFlag) {
      mWaypointsCursor.requery();
      mRequeryFlag = false;
    }
    if (mProjection != null && mWaypointsCursor.moveToFirst()) {
      GeoPoint geoPoint;

      mStartPoint = extractGeoPoint();
      mPrevGeoPoint = mStartPoint;

      do {
        geoPoint = extractGeoPoint();
        setScreenPoint(geoPoint);

        float distance = (float) distanceInPoints(this.mPrevDrawnScreenPoint, this.mScreenPoint);
        if (distance > MINIMUM_PX_DISTANCE) {
          DotVO dotVO = new DotVO();
          dotVO.x = this.mScreenPoint.x;
          dotVO.y = this.mScreenPoint.y;
          dotVO.speed = mWaypointsCursor.getLong(2);
          dotVO.time = mWaypointsCursor.getLong(3);
          dotVO.radius = mProjection.metersToEquatorPixels(mWaypointsCursor.getFloat(4));
          mDotPathCalculation.add(dotVO);

          this.mPrevDrawnScreenPoint.x = this.mScreenPoint.x;
          this.mPrevDrawnScreenPoint.y = this.mScreenPoint.y;
        }
      } while (moveToNextWayPoint());

      this.mEndPoint = extractGeoPoint();
      DotVO pointVO = new DotVO();
      pointVO.x = this.mScreenPoint.x;
      pointVO.y = this.mScreenPoint.y;
      pointVO.speed = mWaypointsCursor.getLong(2);
      pointVO.time = mWaypointsCursor.getLong(3);
      pointVO.radius = mProjection.metersToEquatorPixels(mWaypointsCursor.getFloat(4));
      mDotPathCalculation.add(pointVO);
    }
  }
 @Override
 public void draw(Canvas canvas, MapView mapView, boolean shadow) {
   super.draw(canvas, mapView, shadow);
   if (!shadow) {
     mProjection.setProjection(mapView.getProjection());
     draw(canvas);
   }
 }
  /** Either the Path or the Dots are calculated based on he current track coloring method */
  private synchronized void calculateTrackAsync() {
    GeoPoint oldTopLeft = mGeoTopLeft;
    GeoPoint oldBottumRight = mGeoBottumRight;
    mGeoTopLeft = mProjection.fromPixels(0, 0);
    mGeoBottumRight = mProjection.fromPixels(mWidth, mHeight);

    if (mRequeryFlag
        || oldTopLeft == null
        || oldBottumRight == null
        || mGeoTopLeft.getLatitudeE6() / 100 != oldTopLeft.getLatitudeE6() / 100
        || mGeoTopLeft.getLongitudeE6() / 100 != oldTopLeft.getLongitudeE6() / 100
        || mGeoBottumRight.getLatitudeE6() / 100 != oldBottumRight.getLatitudeE6() / 100
        || mGeoBottumRight.getLongitudeE6() / 100 != oldBottumRight.getLongitudeE6() / 100) {
      calculateStepSize();

      mScreenPoint.x = -1;
      mScreenPoint.y = -1;
      this.mPrevDrawnScreenPoint.x = -1;
      this.mPrevDrawnScreenPoint.y = -1;

      switch (mTrackColoringMethod) {
        case (DRAW_CALCULATED):
        case (DRAW_MEASURED):
        case (DRAW_RED):
        case (DRAW_GREEN):
          calculatePath();
          synchronized (mPath) // Switch the fresh path with the old Path object
          {
            Path oldPath = mPath;
            mPath = mPathCalculation;
            mPathCalculation = oldPath;
          }
          break;
        case (DRAW_DOTS):
          calculateDots();
          synchronized (mDotPath) // Switch the fresh path with the old Path object
          {
            Vector<DotVO> oldDotPath = mDotPath;
            mDotPath = mDotPathCalculation;
            mDotPathCalculation = oldDotPath;
          }
          break;
      }
      mLoggerMap.onDateOverlayChanged();
    }
  }
  private boolean commonOnTap(GeoPoint tappedGeoPoint) {
    List<Uri> tappedUri = new Vector<Uri>();

    Point tappedPoint = new Point();
    mProjection.toPixels(tappedGeoPoint, tappedPoint);
    for (MediaVO media : mMediaPath) {
      if (media.x < tappedPoint.x
          && tappedPoint.x < media.x + media.w
          && media.y < tappedPoint.y
          && tappedPoint.y < media.y + media.h) {
        // Log.d( TAG, String.format( "Tapped at a (x,y) (%d,%d)", tappedPoint.x, tappedPoint.y ) );
        tappedUri.add(media.uri);
      }
    }
    if (tappedUri.size() > 0) {
      return handleMediaTapList(tappedUri);
    } else {
      if (mTrackColoringMethod == DRAW_DOTS) {
        DotVO tapped = null;
        synchronized (mDotPath) // Switch the fresh path with the old Path object
        {
          int w = 25;
          for (DotVO dot : mDotPath) {
            //                  Log.d( TAG, "Compare ("+dot.x+","+dot.y+") with tap
            // ("+tappedPoint.x+","+tappedPoint.y+")" );
            if (dot.x - w < tappedPoint.x
                && tappedPoint.x < dot.x + w
                && dot.y - w < tappedPoint.y
                && tappedPoint.y < dot.y + w) {
              if (tapped == null) {
                tapped = dot;
              } else {
                tapped =
                    dot.distanceTo(tappedPoint) < tapped.distanceTo(tappedPoint) ? dot : tapped;
              }
            }
          }
        }
        if (tapped != null) {
          DateFormat timeFormat =
              android.text.format.DateFormat.getTimeFormat(mLoggerMap.getApplicationContext());
          String timetxt = timeFormat.format(new Date(tapped.time));
          UnitsI18n units = new UnitsI18n(mLoggerMap, null);
          double speed = units.conversionFromMetersPerSecond(tapped.speed);
          String speedtxt = String.format("%.1f %s", speed, units.getSpeedUnit());
          String text = mLoggerMap.getString(R.string.time_and_speed, timetxt, speedtxt);
          Toast toast = Toast.makeText(mLoggerMap, text, Toast.LENGTH_SHORT);
          toast.show();
        }
      }
      return false;
    }
  }