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