1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.test.tilebenchmark; 18 19import android.animation.ArgbEvaluator; 20import android.animation.ObjectAnimator; 21import android.animation.ValueAnimator; 22import android.content.Context; 23import android.graphics.Canvas; 24import android.graphics.Color; 25import android.graphics.Paint; 26import android.graphics.drawable.ShapeDrawable; 27import android.util.AttributeSet; 28import android.view.GestureDetector; 29import android.view.GestureDetector.OnGestureListener; 30import android.view.MotionEvent; 31import android.view.View; 32 33import com.test.tilebenchmark.RunData.TileData; 34 35import java.util.ArrayList; 36 37public class PlaybackView extends View { 38 public static final int TILE_SCALE = 256; 39 private static final int INVAL_FLAG = -2; 40 private static final int INVAL_CYCLE = 250; 41 42 private Paint levelPaint = null, coordPaint = null, goldPaint = null; 43 private PlaybackGraphs mGraphs; 44 45 private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>(); 46 private RunData mProfData = null; 47 private GestureDetector mGestureDetector = null; 48 private ArrayList<String> mRenderStrings = new ArrayList<String>(); 49 50 private class TileDrawable extends ShapeDrawable { 51 TileData tile; 52 String label; 53 54 public TileDrawable(TileData t, int colorId) { 55 this.tile = t; 56 getPaint().setColor(getResources().getColor(colorId)); 57 if (colorId == R.color.ready_tile 58 || colorId == R.color.unready_tile) { 59 60 label = (int) (t.left / TILE_SCALE) + ", " 61 + (int) (t.top / TILE_SCALE); 62 // ignore scale value for tiles 63 setBounds(t.left, t.top, 64 t.right, t.bottom); 65 } else { 66 setBounds((int) (t.left * t.scale), 67 (int) (t.top * t.scale), 68 (int) (t.right * t.scale), 69 (int) (t.bottom * t.scale)); 70 } 71 } 72 73 @SuppressWarnings("unused") 74 public void setColor(int color) { 75 getPaint().setColor(color); 76 } 77 78 @Override 79 public void draw(Canvas canvas) { 80 super.draw(canvas); 81 if (label != null) { 82 canvas.drawText(Integer.toString(tile.level), getBounds().left, 83 getBounds().bottom, levelPaint); 84 canvas.drawText(label, getBounds().left, 85 ((getBounds().bottom + getBounds().top) / 2), 86 coordPaint); 87 } 88 } 89 } 90 91 public PlaybackView(Context context) { 92 super(context); 93 init(); 94 } 95 96 public PlaybackView(Context context, AttributeSet attrs) { 97 super(context, attrs); 98 init(); 99 } 100 101 public PlaybackView(Context context, AttributeSet attrs, int defStyle) { 102 super(context, attrs, defStyle); 103 init(); 104 } 105 106 public void setOnGestureListener(OnGestureListener gl) { 107 mGestureDetector = new GestureDetector(getContext(), gl); 108 } 109 110 @Override 111 public boolean onTouchEvent(MotionEvent event) { 112 mGestureDetector.onTouchEvent(event); 113 return true; 114 } 115 116 private void init() { 117 levelPaint = new Paint(); 118 levelPaint.setColor(Color.WHITE); 119 levelPaint.setTextSize(TILE_SCALE / 2); 120 coordPaint = new Paint(); 121 coordPaint.setColor(Color.BLACK); 122 coordPaint.setTextSize(TILE_SCALE / 3); 123 goldPaint = new Paint(); 124 goldPaint.setColor(0xffa0e010); 125 mGraphs = new PlaybackGraphs(); 126 } 127 128 @Override 129 protected void onDraw(Canvas canvas) { 130 super.onDraw(canvas); 131 132 if (mTempShapes == null || mTempShapes.isEmpty()) { 133 return; 134 } 135 136 mGraphs.draw(canvas, mTempShapes, mRenderStrings, getResources()); 137 invalidate(); // may have animations, force redraw 138 } 139 140 private String statString(int labelId, int value) { 141 return getResources().getString(R.string.format_stat_name, 142 getResources().getString(labelId), value); 143 } 144 private String tileString(int formatStringId, TileData t) { 145 return getResources().getString(formatStringId, 146 t.left, t.top, t.right, t.bottom); 147 } 148 149 public int setFrame(int frame) { 150 if (mProfData == null || mProfData.frames.length == 0) { 151 return 0; 152 } 153 154 int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0; 155 mTempShapes.clear(); 156 mRenderStrings.clear(); 157 158 // create tile shapes (as they're drawn on bottom) 159 for (TileData t : mProfData.frames[frame]) { 160 if (t == mProfData.frames[frame][0]){ 161 // viewport 'tile', add coords to render strings 162 mRenderStrings.add(tileString(R.string.format_view_pos, t)); 163 } else if (t.level != INVAL_FLAG) { 164 int colorId; 165 if (t.isReady) { 166 readyTiles++; 167 colorId = R.color.ready_tile; 168 } else { 169 unreadyTiles++; 170 colorId = R.color.unready_tile; 171 } 172 if (t.left < 0 || t.top < 0) { 173 unplacedTiles++; 174 } 175 mTempShapes.add(new TileDrawable(t, colorId)); 176 } else { 177 // inval 'tile', count and add coords to render strings 178 numInvals++; 179 mRenderStrings.add(tileString(R.string.format_inval_pos, t)); 180 } 181 } 182 183 // create invalidate shapes (drawn above tiles) 184 int invalId = 0; 185 for (TileData t : mProfData.frames[frame]) { 186 if (t.level == INVAL_FLAG && t != mProfData.frames[frame][0]) { 187 TileDrawable invalShape = new TileDrawable(t, 188 R.color.inval_region_start); 189 ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape, 190 "color", 191 getResources().getColor(R.color.inval_region_start), 192 getResources().getColor(R.color.inval_region_stop)); 193 tileAnimator.setDuration(numInvals * INVAL_CYCLE); 194 tileAnimator.setEvaluator(new ArgbEvaluator()); 195 tileAnimator.setRepeatCount(ValueAnimator.INFINITE); 196 tileAnimator.setRepeatMode(ValueAnimator.RESTART); 197 float delay = (float) (invalId) * INVAL_CYCLE; 198 tileAnimator.setStartDelay((int) delay); 199 invalId++; 200 tileAnimator.start(); 201 202 mTempShapes.add(invalShape); 203 } 204 } 205 206 mRenderStrings.add(statString(R.string.ready_tiles, readyTiles)); 207 mRenderStrings.add(statString(R.string.unready_tiles, unreadyTiles)); 208 mRenderStrings.add(statString(R.string.unplaced_tiles, unplacedTiles)); 209 mRenderStrings.add(statString(R.string.number_invalidates, numInvals)); 210 211 // draw view rect (using first TileData object, on top) 212 TileDrawable viewShape = new TileDrawable(mProfData.frames[frame][0], 213 R.color.view); 214 mTempShapes.add(viewShape); 215 this.invalidate(); 216 return frame; 217 } 218 219 public void setData(RunData tileProfilingData) { 220 mProfData = tileProfilingData; 221 222 mGraphs.setData(mProfData); 223 } 224} 225