/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.imagepipeline.animated.impl;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.SystemClock;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import com.facebook.common.logging.FLog;
import com.facebook.imagepipeline.animated.base.AnimatedDrawableCachingBackend;
import com.facebook.imagepipeline.animated.base.AnimatedDrawableDiagnostics;
import com.facebook.imagepipeline.animated.util.AnimatedDrawableUtil;
/**
* Implementation of {@link AnimatedDrawableDiagnostics} that logs extra information and draws
* a debug overlay..
*/
public class AnimatedDrawableDiagnosticsImpl implements AnimatedDrawableDiagnostics {
private static final Class<?> TAG = AnimatedDrawableDiagnostics.class;
private final AnimatedDrawableUtil mAnimatedDrawableUtil;
private final DisplayMetrics mDisplayMetrics;
private final TextPaint mDebugTextPaint;
private final StringBuilder sbTemp;
private final RollingStat mDroppedFramesStat;
private final RollingStat mDrawnFrames;
private AnimatedDrawableCachingBackend mAnimatedDrawableBackend;
private long mLastTimeStamp;
public AnimatedDrawableDiagnosticsImpl(
AnimatedDrawableUtil animatedDrawableUtil,
DisplayMetrics displayMetrics) {
mAnimatedDrawableUtil = animatedDrawableUtil;
mDisplayMetrics = displayMetrics;
mDroppedFramesStat = new RollingStat();
mDrawnFrames = new RollingStat();
sbTemp = new StringBuilder();
mDebugTextPaint = new TextPaint();
mDebugTextPaint.setColor(Color.BLUE);
mDebugTextPaint.setTextSize(convertDpToPx(14));
}
@Override
public void setBackend(AnimatedDrawableCachingBackend animatedDrawableBackend) {
mAnimatedDrawableBackend = animatedDrawableBackend;
}
@Override
public void onStartMethodBegin() {
mLastTimeStamp = SystemClock.uptimeMillis();
}
@Override
public void onStartMethodEnd() {
long elapsedMs = SystemClock.uptimeMillis() - mLastTimeStamp;
if (elapsedMs > 3) {
FLog.v(TAG, "onStart took %d", elapsedMs);
}
}
@Override
public void onNextFrameMethodBegin() {
mLastTimeStamp = SystemClock.uptimeMillis();
}
@Override
public void onNextFrameMethodEnd() {
long elapsedMs = SystemClock.uptimeMillis() - mLastTimeStamp;
if (elapsedMs > 3) {
FLog.v(TAG, "onNextFrame took %d", elapsedMs);
}
}
@Override
public void incrementDroppedFrames(int droppedFrames) {
mDroppedFramesStat.incrementStats(droppedFrames);
if (droppedFrames > 0) {
FLog.v(TAG, "Dropped %d frames", droppedFrames);
}
}
@Override
public void incrementDrawnFrames(int drawnFrames) {
mDrawnFrames.incrementStats(drawnFrames);
}
@Override
public void onDrawMethodBegin() {
mLastTimeStamp = SystemClock.uptimeMillis();
}
@Override
public void onDrawMethodEnd() {
long elapsedMs = SystemClock.uptimeMillis() - mLastTimeStamp;
FLog.v(TAG, "draw took %d", elapsedMs);
}
public void drawDebugOverlay(Canvas canvas, Rect destRect) {
// Running percentage of frames shown (i.e. drop rate).
int droppedFrame10 = mDroppedFramesStat.getSum(10);
int drawnFrames10 = mDrawnFrames.getSum(10);
int totalFrames = drawnFrames10 + droppedFrame10;
int leftMargin = convertDpToPx(10);
int x = leftMargin;
int y = convertDpToPx(20);
int spacingBetweenTextPx = convertDpToPx(5);
if (totalFrames > 0) {
int percentage = drawnFrames10 * 100 / totalFrames;
sbTemp.setLength(0);
sbTemp.append(percentage);
sbTemp.append("%");
canvas.drawText(sbTemp, 0, sbTemp.length(), x, y, mDebugTextPaint);
x += mDebugTextPaint.measureText(sbTemp, 0, sbTemp.length());
x += spacingBetweenTextPx;
}
// Memory usage.
int bytesUsed = mAnimatedDrawableBackend.getMemoryUsage();
sbTemp.setLength(0);
mAnimatedDrawableUtil.appendMemoryString(sbTemp, bytesUsed);
float textWidth = mDebugTextPaint.measureText(sbTemp, 0, sbTemp.length());
if (x + textWidth > destRect.width()) {
x = leftMargin;
y += mDebugTextPaint.getTextSize() + spacingBetweenTextPx;
}
canvas.drawText(sbTemp, 0, sbTemp.length(), x, y, mDebugTextPaint);
x += textWidth;
x += spacingBetweenTextPx;
// Options
sbTemp.setLength(0);
mAnimatedDrawableBackend.appendDebugOptionString(sbTemp);
textWidth = mDebugTextPaint.measureText(sbTemp, 0, sbTemp.length());
if (x + textWidth > destRect.width()) {
x = leftMargin;
y += mDebugTextPaint.getTextSize() + spacingBetweenTextPx;
}
canvas.drawText(sbTemp, 0, sbTemp.length(), x, y, mDebugTextPaint);
}
private int convertDpToPx(int dips) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dips, mDisplayMetrics);
}
}