package com.alexvasilkov.gestures.internal; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.view.View; import com.alexvasilkov.gestures.GestureController; import com.alexvasilkov.gestures.GestureController.StateSource; import com.alexvasilkov.gestures.Settings; import com.alexvasilkov.gestures.animation.ViewPositionAnimator; import com.alexvasilkov.gestures.utils.GravityUtils; import com.alexvasilkov.gestures.views.interfaces.AnimatorView; import com.alexvasilkov.gestures.views.interfaces.GestureView; import java.lang.reflect.Field; import java.util.Locale; public class DebugOverlay { private static final float STROKE_WIDTH = 2f; private static final float TEXT_SIZE = 16f; private static final Paint paint = new Paint(); private static final RectF rectF = new RectF(); private static final Rect rect = new Rect(); private static final Matrix matrix = new Matrix(); private static Field stateSourceField; private DebugOverlay() {} public static void drawDebug(View view, Canvas canvas) { final GestureController controller = ((GestureView) view).getController(); final ViewPositionAnimator animator = ((AnimatorView) view).getPositionAnimator(); final Settings settings = controller.getSettings(); final Context context = view.getContext(); final float stroke = UnitsUtils.toPixels(context, STROKE_WIDTH); final float textSize = UnitsUtils.toPixels(context, TEXT_SIZE); canvas.save(); canvas.translate(view.getPaddingLeft(), view.getPaddingTop()); // Viewport rectF.set(0f, 0f, settings.getViewportW(), settings.getViewportH()); drawRect(canvas, rectF, Color.GRAY, stroke); // Movement area GravityUtils.getMovementAreaPosition(settings, rect); rectF.set(rect); drawRect(canvas, rectF, Color.GREEN, stroke); // Image bounds with rotation controller.getState().get(matrix); canvas.save(); canvas.concat(matrix); rectF.set(0f, 0f, settings.getImageW(), settings.getImageH()); drawRect(canvas, rectF, Color.YELLOW, stroke / controller.getState().getZoom()); canvas.restore(); // Image bounds rectF.set(0f, 0f, settings.getImageW(), settings.getImageH()); controller.getState().get(matrix); matrix.mapRect(rectF); drawRect(canvas, rectF, Color.RED, stroke); // State source float pos = animator.getPosition(); if (pos == 1f || (pos == 0f && animator.isLeaving())) { final StateSource source = getStateSource(controller); drawText(canvas, settings, source.name(), Color.CYAN, textSize); if (source != StateSource.NONE) { view.invalidate(); } } else if (pos > 0f) { String direction = animator.isLeaving() ? "EXIT" : "ENTER"; String text = String.format(Locale.US, "%s %.0f%%", direction, pos * 100f); drawText(canvas, settings, text, Color.MAGENTA, textSize); } canvas.restore(); } private static void drawRect(Canvas canvas, RectF rect, int color, float stroke) { paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(stroke); rectF.inset(0.5f * stroke, 0.5f * stroke); paint.setColor(color); canvas.drawRect(rect, paint); } private static void drawText(Canvas canvas, Settings settings, String text, int color, float textSize) { // Text settings paint.setTextSize(textSize); paint.setTypeface(Typeface.MONOSPACE); paint.setTextAlign(Paint.Align.CENTER); final float halfSize = 0.5f * textSize; // Computing text background paint.getTextBounds(text, 0, text.length(), rect); rectF.set(rect); rectF.offset(-rectF.centerX(), -rectF.centerY()); GravityUtils.getMovementAreaPosition(settings, rect); rectF.offset(rect.centerX(), rect.centerY()); rectF.inset(-halfSize, -halfSize); // Drawing background paint.setStyle(Paint.Style.FILL); paint.setColor(Color.WHITE); canvas.drawRoundRect(rectF, halfSize, halfSize, paint); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.GRAY); canvas.drawRoundRect(rectF, halfSize, halfSize, paint); // Drawing text paint.setStyle(Paint.Style.FILL); paint.setColor(color); canvas.drawText(text, rectF.centerX(), rectF.bottom - halfSize, paint); } private static StateSource getStateSource(GestureController controller) { // We can't have public API for state source in GestureController, // since it is only make sense to get it through corresponding listener. // Getting field through reflection for debug purpose does not seem to be very bad. if (stateSourceField == null) { try { stateSourceField = GestureController.class.getDeclaredField("stateSource"); stateSourceField.setAccessible(true); } catch (Exception ignored) { } } if (stateSourceField != null) { try { return (StateSource) stateSourceField.get(controller); } catch (Exception ignored) { } } return StateSource.NONE; } }