Identificar triple toque en vista personalizada

Quiero dibujar un círculo, siempre que el usuario toque en una vista personalizada, y en base a los cambios de color del círculo de conteo de toques.

Single Tap : YELLOW CIRCLE
Double Tap : GREEN CIRCLE
Triple Tap : RED COLOR

El problema es que hice una vista personalizada que contará el evento de toque en función del tiempo, pero en algún momento se pierde el primer toque. que causan el problema a la vista.

El siguiente código muestra todo mi esfuerzo por hacer la vista personalizada anterior.

TripleTapView

package com.slk.car_rating_app;

import java.util.ArrayList;
import java.util.Date;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.view.MotionEvent;
import android.view.View;

public class TripleTapView extends View {
    // Set the tap delay in milliseconds
    protected static final long TAP_MAX_DELAY = 500L;
    // Radius to capture tap within bound
    final static int RADIUS = 30;
    // Store all points with tap count
    public ArrayList<CustomPoint> point = new ArrayList<CustomPoint>();
    // Context to access view
    Context context;
    Paint paint;
    private long thisTime = 0, prevTime = 0;
    private boolean firstTap = true, doubleTap = false;;
    float stopX, stopY, startX, startY;
    RectF area_rect;
    TapCounter tapCounter = new TapCounter(TAP_MAX_DELAY, TAP_MAX_DELAY);

    public TripleTapView(Context context) {
        super(context);
        this.context = context;
        paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(2);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        for (CustomPoint point_temp : point) {
            // For changing tap circle color based on tap count
            switch (point_temp.count) {
            case 1:
                paint.setColor(Color.YELLOW);
                break;
            case 2:
                paint.setColor(Color.GREEN);
                break;
            case 3:
                paint.setColor(Color.RED);
                break;
            }
            canvas.drawCircle(point_temp.point.x, point_temp.point.y, 10, paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            stopX = event.getX();
            stopY = event.getY();
            if (firstTap) {
                addFirstTap();
            } else if (doubleTap) {
                prevTime = thisTime;
                thisTime = new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        if (area_rect.contains(stopX, stopY))
                            doubleTap = false;
                        else {
                            addPoint(1);
                            addFirstTap();
                        }
                    } else {
                        addPoint(1);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            } else {
                prevTime = thisTime;
                thisTime = new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        if (area_rect.contains(stopX, stopY)) {
                            addPoint(3);
                            firstTap = true;
                        } else {
                            addPoint(2);
                            addFirstTap();
                        }
                    } else {
                        addPoint(2);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            }
        }
        return true;
    }

    void addPoint(int tapCount) {
        point.add(new CustomPoint(new PointF(startX, startY), tapCount));
        invalidate();
    }

    void addFirstTap() {
        thisTime = new Date().getTime();
        firstTap = false;
        doubleTap = true;
        startX = stopX;
        startY = stopY;
        area_rect = new RectF(stopX - RADIUS, stopY - RADIUS, stopX + RADIUS,
                stopY + RADIUS);
        tapCounter.resetCounter();
    }

    class TapCounter extends CountDownTimer {
        public TapCounter(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onFinish() {
            if (doubleTap) {
                prevTime = thisTime;
                thisTime = new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        doubleTap = false;
                    } else {
                        addPoint(1);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            } else if (!firstTap && !doubleTap) {
                prevTime = thisTime;
                thisTime =  new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        addPoint(2);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            }
        }

        @Override
        public void onTick(long millisUntilFinished) {
        }

        public void resetCounter() {
            start();
        }
    }
}

Por favor, ayúdame a solucionar este problema.

Respuestas a la pregunta(1)

Su respuesta a la pregunta