/****************************************************************************
**
** Copyright (C) 2010-2012 UC Mobile Ltd. All Rights Reserved
** File : WebViewFPS.java
**
** Description : Used to calculate FPS for WebView
**
** Creation : 2012/09/21
** Author : Roger (yixx@ucweb.com)
** History :
** Creation, 2012/09/21, Roger, Create the file
**
****************************************************************************/
package com.uc.webkit.utils;
import android.app.ActivityManager;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.os.Debug;
import android.view.View;
import com.uc.webkit.helper.CanvasHelper;
/**
* Used to calculate FPS for WebView.
*/
public class WebViewFPS {
public static boolean ENABLE = false;
//add by zhaochuang
public static boolean ENABLE_AC_RENDERING_STATSTIC = false;
// Enable profiling fps in GL draw path - drawGL in WebView.cpp,
// this is more appropriate than in onDraw of WebView.java
public static boolean ENABLE_GL = ENABLE;
public static boolean ENABLE_GL_EX = false;
public static boolean ENABLE_GL_CANVAS = false;
public static boolean ENABLE_GL_AUTO_REDRAW = false;
public static boolean ENABLE_MEMORY_INFO = ENABLE;
public static boolean ENABLE_NETWORK_INFO = ENABLE;
public static boolean ENABLE_MEMORY_VERBOSE = false;
public static final String FPS = "debug.uc.fps";
public static final String FPS_EX = "debug.uc.fpsex";
public static final String FPS_CANVAS = "debug.uc.fpscanvas";
private static final int CACL_CIRCLE = 1000;
private static long sFirstFrameCompensation = 17;
private static long sOverallTime = 0;
private static long sDrawTime = 0;
private static long sLastTime = -1;
private static double sOverallFps = 0;
private static double sDrawFps = 0;
private static int sTotalFrames = 0;
private static int sFrames = 0;
private static Paint sFpsBgPaint = null;
private static Paint sFpsTxtPaint = null;
private static Paint sFpsWarningTxtPaint = null;
private static double sGLFps = 0;
private static double sGLDrawAvg = 0;
private static double sGLDrawMax = 0;
private static double sGLDrawMin = 0;
private static double sGLBaseLayerTexMem = 0;
private static double sGLLayerTexMem = 0;
private static double sGLGbMem = 0;
private static int sGLLayerMode = 0;
private static Debug.MemoryInfo sMemInfo;
private static ActivityManager.MemoryInfo sActMemInfo;
private static long sLastMemInfoUpdateTime;
//add by zhouliang for performance test
public static boolean ENABLE_PERFORANCE_TEST = false;
public static double getFPS() {
return sGLFps != 0 ? sGLFps : sOverallFps;
}
//add by zhaochuang for AC rendering statstic
public static double getGLBaseLayerTexMem() {
return sGLBaseLayerTexMem;
}
public static double getGLLayerTexMem() {
return sGLLayerTexMem;
}
public static double getGLGbMem() {
return sGLGbMem;
}
//for T1 time display
//TODO: should move to new class
private static long sT0 = 0;
private static long sT1 = 0;
public static void setT0(){
sT0 = System.currentTimeMillis();
}
public static void setT1(){
sT1 = System.currentTimeMillis();
}
public static void setGLFps(boolean isScrolling, double fps, double drawAvg, double drawMax, double drawMin,
double baseLayerTexMem, double layerTexMem, double gbMem, int layerMode) {
sGLFps = fps;
sGLDrawAvg = drawAvg;
sGLDrawMax = drawMax;
sGLDrawMin = drawMin;
sGLBaseLayerTexMem = baseLayerTexMem;
sGLLayerTexMem = layerTexMem;
sGLGbMem = gbMem;
sGLLayerMode = layerMode;
if (ENABLE && !isScrolling) {
final long now = System.currentTimeMillis();
if (ENABLE_MEMORY_INFO && now - sLastMemInfoUpdateTime > 5 * 1000) {
sMemInfo = SystemInfo.getProcessMemoryInfo();
sActMemInfo = SystemInfo.getActivityMemoryInfo();
sLastMemInfoUpdateTime = now;
}
} else if (ENABLE) {
sLastMemInfoUpdateTime = System.currentTimeMillis();
}
}
public static float getSmoothnessRate(final double frameRate) {
final float displayRefreshRate = SystemInfo.getDisplayRefreshRate();
float rate = 0;
if (frameRate >= displayRefreshRate) {
rate = 100;
} else {
rate = (float) (frameRate - (displayRefreshRate - frameRate)) * 100 / displayRefreshRate;
}
if (displayRefreshRate < 60) {
rate *= (displayRefreshRate) / 60;
}
return rate >= 0 ? rate : 0;
}
public final static int SMOOTHNESS_VERY_SMOOTH = 5;
public final static int SMOOTHNESS_SMOOTH = 4;
public final static int SMOOTHNESS_SLIGHTLY_JANK = 3;
public final static int SMOOTHNESS_JANK = 2;
public final static int SMOOTHNESS_VERY_JANK = 1;
public final static int SMOOTHNESS_FROZEN = 0;
public static int getSmoothnessLevel(final float smoothnessRate) {
final int srate = Math.round(smoothnessRate);
if (srate >= 90) return SMOOTHNESS_VERY_SMOOTH;
else if (srate >= 80) return SMOOTHNESS_SMOOTH;
else if (srate >= 60) return SMOOTHNESS_SLIGHTLY_JANK;
else if (srate >= 40) return SMOOTHNESS_JANK;
else if (srate >= 0) return SMOOTHNESS_VERY_JANK;
return SMOOTHNESS_FROZEN;
}
public static void fps(long begin, Canvas canvas, View view) {
if (!(ENABLE || ENABLE_PERFORANCE_TEST))
return;
if (sFpsBgPaint == null) {
sFpsBgPaint = new Paint();
sFpsBgPaint.setStyle(Style.FILL);
sFpsBgPaint.setColor(0x7f5f5f5f);
sFpsTxtPaint = new Paint();
sFpsTxtPaint.setStyle(Style.FILL);
sFpsTxtPaint.setColor(0xff00ff00);
sFpsTxtPaint.setTextSize(20);
sFpsTxtPaint.setTextAlign(Align.RIGHT);
sFpsWarningTxtPaint = new Paint();
sFpsWarningTxtPaint.setStyle(Style.FILL);
sFpsWarningTxtPaint.setColor(0xffff0000);
sFpsWarningTxtPaint.setTextSize(20);
sFpsWarningTxtPaint.setTextAlign(Align.RIGHT);
}
final int width = view.getWidth();
final int height = view.getHeight();
final int scrollX = view.getScrollX();
final int scrollY = view.getScrollY();
final boolean showGLFps = ENABLE_GL && sGLFps != 0;
if (!showGLFps) {
if (sLastTime <= 0) {
sLastTime = System.currentTimeMillis() - sFirstFrameCompensation;
}
final long now = System.currentTimeMillis();
final long used = Math.max(now - begin, 1);
final long pass = now - sLastTime;
// If we wait too long for one frame, regard as a pause,
// skip it, otherwise continue to accumulate the frames
if (pass - used < 500) {
sOverallTime += pass;
sDrawTime += used;
++sFrames;
++sTotalFrames;
}
sLastTime = now;
// calculation then reset every second
if (sOverallTime > CACL_CIRCLE) {
sDrawFps = sFrames * 1000.0 / sDrawTime;
sOverallFps = sFrames * 1000.0 / sOverallTime;
sOverallTime = 0;
sDrawTime = 0;
sFrames = 0;
}
}
//add by zhouliang, do not show fps in performance test
if (ENABLE_PERFORANCE_TEST) {
return;
}
//cal T1 time
//TODO: should move to new class
String t1Str = sT1 > sT0 ? String.format("T1: %.1fs", (sT1 - sT0) * 0.001) : "T1: ? sec";
String version = CanvasHelper.isHardwareAccelerated(canvas) ? "hd>" : "sf>";
//cal fps time
final float rrate = SystemInfo.getDisplayRefreshRate();
final float srate = getSmoothnessRate(showGLFps ? sGLFps : sOverallFps);
String fpsStr = null;
String drawStr = null;
String texMemStr = null;
if (showGLFps) {
fpsStr = String.format("GL>%.1f/%dfps %d%%", sGLFps, Math.round(rrate), Math.round(srate));
drawStr = String.format("Draw[%d]:%.1f/%.1f/%.1f", sGLLayerMode, sGLDrawAvg, sGLDrawMax, sGLDrawMin);
texMemStr = String.format("Tex:%.1f=%.1f+%.1f+%.0f", sGLBaseLayerTexMem
+ sGLLayerTexMem + sGLGbMem, sGLBaseLayerTexMem, sGLLayerTexMem, sGLGbMem);
} else {
fpsStr = String.format("%s%.1f/%dfps %d%%", version, sOverallFps,
Math.round(rrate), Math.round(srate));
}
final int fpsWidth = 220;
final int fpsHeight = 30 + (drawStr != null ? 30 : 0) + (texMemStr != null ? 30 : 0)
+ (sMemInfo != null ? (ENABLE_MEMORY_VERBOSE ? 120 : 30) : 0)
+ (ENABLE_NETWORK_INFO && t1Str != null ? 30 : 0);
canvas.save();
canvas.translate(scrollX, scrollY + height - fpsHeight);
canvas.drawRect(width - fpsWidth, 0, width, fpsHeight, sFpsBgPaint);
canvas.drawText(fpsStr, width - 2, 22, sFpsTxtPaint);
if (drawStr != null) {
canvas.translate(0, 30);
canvas.drawText(drawStr, width - 2, 22, sFpsTxtPaint);
}
if (texMemStr != null) {
canvas.translate(0, 30);
canvas.drawText(texMemStr, width - 2, 22, sFpsTxtPaint);
}
if (sMemInfo != null && sActMemInfo != null) {
final Debug.MemoryInfo mi = sMemInfo;
final ActivityManager.MemoryInfo ami = sActMemInfo;
String str;
if (ENABLE_MEMORY_VERBOSE) {
str = String.format("D Mem:%.1f/%.1f/%.1f",
mi.dalvikPss / 1024.0f, mi.dalvikSharedDirty / 1024.0f,
mi.dalvikPrivateDirty / 1024.0f);
canvas.translate(0, 30);
canvas.drawText(str, width - 2, 22, sFpsTxtPaint);
}
if (ENABLE_MEMORY_VERBOSE) {
str = String.format("N Mem:%.1f/%.1f/%.1f",
mi.nativePss / 1024.0f, mi.nativeSharedDirty / 1024.0f,
mi.nativePrivateDirty / 1024.0f);
canvas.translate(0, 30);
canvas.drawText(str, width - 2, 22, sFpsTxtPaint);
}
if (ENABLE_MEMORY_VERBOSE) {
str = String.format("O Mem:%.1f/%.1f/%.1f",
mi.otherPss / 1024.0f, mi.otherSharedDirty / 1024.0f,
mi.otherPrivateDirty / 1024.0f);
canvas.translate(0, 30);
canvas.drawText(str, width - 2, 22, sFpsTxtPaint);
}
final float mb = 1024.0f * 1024.0f;
str = String.format("Mem:%.1f[%.0f/%.0f]",
mi.getTotalPss() / 1024.0f,
ami.availMem / mb, ami.threshold / mb);
canvas.translate(0, 30);
canvas.drawText(str, width - 2, 22, ami.lowMemory ? sFpsWarningTxtPaint : sFpsTxtPaint);
}
if (ENABLE_NETWORK_INFO && t1Str != null) {
canvas.translate(0, 30);
canvas.drawText(t1Str, width - 2, 22, sFpsTxtPaint);
}
canvas.restore();
}
public static void enableDebug() {
// try {
// int enableFps = DebugHelper.invokeSystemPropertiesGetInt(WebViewFPS.FPS, -1);
// int enableFpsEx = DebugHelper.invokeSystemPropertiesGetInt(WebViewFPS.FPS_EX, -1);
// if (enableFps == 1 || enableFpsEx == 1) {
// WebViewFPS.ENABLE = true;
// WebViewFPS.ENABLE_GL = true;
// WebViewFPS.ENABLE_MEMORY_INFO = enableFpsEx == 1;
// WebViewFPS.ENABLE_NETWORK_INFO = enableFpsEx == 1;
// if (enableFpsEx == 1) {
// WebViewFPS.ENABLE_GL_EX = true;
// }
// } else if (enableFps == 0 && enableFpsEx == 0) {
// WebViewFPS.ENABLE = false;
// WebViewFPS.ENABLE_GL = false;
// WebViewFPS.ENABLE_GL_EX = false;
// WebViewFPS.ENABLE_MEMORY_INFO = false;
// }
//
// int enableFpsCanvas = DebugHelper.invokeSystemPropertiesGetInt(WebViewFPS.FPS_CANVAS, -1);
// if (enableFpsCanvas == 1) {
// WebViewFPS.ENABLE_GL_CANVAS = true;
// } else if (enableFpsCanvas == 0) {
// WebViewFPS.ENABLE_GL_CANVAS = false;
// }
// } catch (Throwable t) {
// }
}
public static void enableFps(boolean enable) {
ENABLE = enable;
ENABLE_GL = enable;
ENABLE_MEMORY_INFO = enable;
ENABLE_MEMORY_VERBOSE = enable;
enableDebug();
}
}