15888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik/*
25888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * Copyright (C) 2011 The Android Open Source Project
35888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik *
45888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * Licensed under the Apache License, Version 2.0 (the "License");
55888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * you may not use this file except in compliance with the License.
65888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * You may obtain a copy of the License at
75888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik *
85888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik *      http://www.apache.org/licenses/LICENSE-2.0
95888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik *
105888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * Unless required by applicable law or agreed to in writing, software
115888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * distributed under the License is distributed on an "AS IS" BASIS,
125888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * See the License for the specific language governing permissions and
145888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik * limitations under the License.
155888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik */
165888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
175888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikpackage com.test.tilebenchmark;
185888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
195888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport android.content.res.Resources;
205888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport android.graphics.Canvas;
215888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport android.graphics.Color;
225888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport android.graphics.Paint;
235888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport android.graphics.Rect;
245888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport android.graphics.drawable.ShapeDrawable;
25555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik
26555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craikimport com.test.tilebenchmark.RunData.TileData;
275888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
285888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport java.util.ArrayList;
295888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikimport java.util.Arrays;
30555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craikimport java.util.HashMap;
315888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
325888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craikpublic class PlaybackGraphs {
3321555abad7ba5f5377052e2644974d3ce8c37869Chris Craik    private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
345888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    private static final float CANVAS_SCALE = 0.2f;
355888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    private static final double IDEAL_FRAMES = 60;
365888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    private static final int LABELOFFSET = 100;
375888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    private static Paint whiteLabels;
385888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
3921555abad7ba5f5377052e2644974d3ce8c37869Chris Craik    private static double viewportCoverage(TileData view, TileData tile) {
406f92c15180f66d0ec7c8b20ea47f479468255970Chris Craik        if (tile.left < (view.right * view.scale)
416f92c15180f66d0ec7c8b20ea47f479468255970Chris Craik                && tile.right >= (view.left * view.scale)
426f92c15180f66d0ec7c8b20ea47f479468255970Chris Craik                && tile.top < (view.bottom * view.scale)
436f92c15180f66d0ec7c8b20ea47f479468255970Chris Craik                && tile.bottom >= (view.top * view.scale)) {
445888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            return 1.0f;
455888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
465888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        return 0.0f;
475888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
485888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
49555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik    protected interface MetricGen {
505888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        public double getValue(TileData[] frame);
515888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
525888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        public double getMax();
535888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
545888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        public int getLabelId();
555888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    };
565888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
57555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik    protected static MetricGen[] Metrics = new MetricGen[] {
585888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            new MetricGen() {
595888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                // framerate graph
605888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
615888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getValue(TileData[] frame) {
625888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    int renderTimeUS = frame[0].level;
635888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return 1.0e6f / renderTimeUS;
645888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
655888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
665888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
675888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getMax() {
685888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return IDEAL_FRAMES;
695888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
705888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
715888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
725888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public int getLabelId() {
735888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return R.string.frames_per_second;
745888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
755888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            }, new MetricGen() {
765888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                // coverage graph
775888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
785888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getValue(TileData[] frame) {
795888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    double total = 0, totalCount = 0;
8021555abad7ba5f5377052e2644974d3ce8c37869Chris Craik                    for (int tileID = 1; tileID < frame.length; tileID++) {
815888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                        TileData data = frame[tileID];
8221555abad7ba5f5377052e2644974d3ce8c37869Chris Craik                        double coverage = viewportCoverage(frame[0], data);
83702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                        total += coverage * (data.isReady ? 100 : 0);
845888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                        totalCount += coverage;
855888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    }
865888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    if (totalCount == 0) {
875888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                        return -1;
885888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    }
895888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return total / totalCount;
905888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
915888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
925888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
935888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getMax() {
94702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                    return 100;
955888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
965888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
975888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
985888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public int getLabelId() {
995888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return R.string.viewport_coverage;
1005888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
1015888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            }
1025888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    };
1035888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
104555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik    protected interface StatGen {
1055888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        public double getValue(double sortedValues[]);
1065888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
1075888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        public int getLabelId();
1085888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
1095888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
1105888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    public static double getPercentile(double sortedValues[], double ratioAbove) {
111702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        if (sortedValues.length == 0)
112702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            return -1;
113702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
1145888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        double index = ratioAbove * (sortedValues.length - 1);
1155888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        int intIndex = (int) Math.floor(index);
1165888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        if (index == intIndex) {
1175888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            return sortedValues[intIndex];
1185888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
1195888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        double alpha = index - intIndex;
1205888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        return sortedValues[intIndex] * (1 - alpha)
1215888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                + sortedValues[intIndex + 1] * (alpha);
1225888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
1235888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
124702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    public static double getMean(double sortedValues[]) {
125702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        if (sortedValues.length == 0)
126702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            return -1;
127702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
128702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        double agg = 0;
129702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        for (double val : sortedValues) {
130702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            agg += val;
131702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        }
132702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        return agg / sortedValues.length;
133702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    }
134702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
135702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    public static double getStdDev(double sortedValues[]) {
136702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        if (sortedValues.length == 0)
137702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            return -1;
138702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
139702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        double agg = 0;
140702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        double sqrAgg = 0;
141702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        for (double val : sortedValues) {
142702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            agg += val;
143702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            sqrAgg += val*val;
144702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        }
145702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        double mean = agg / sortedValues.length;
146702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean));
147702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    }
148702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
149555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik    protected static StatGen[] Stats = new StatGen[] {
1505888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            new StatGen() {
1515888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
1525888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getValue(double[] sortedValues) {
1535888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return getPercentile(sortedValues, 0.25);
1545888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
1555888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
1565888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
1575888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public int getLabelId() {
1585888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return R.string.percentile_25;
1595888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
1605888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            }, new StatGen() {
1615888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
1625888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getValue(double[] sortedValues) {
1635888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return getPercentile(sortedValues, 0.5);
1645888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
1655888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
1665888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
1675888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public int getLabelId() {
1685888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return R.string.percentile_50;
1695888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
1705888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            }, new StatGen() {
1715888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
1725888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public double getValue(double[] sortedValues) {
1735888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return getPercentile(sortedValues, 0.75);
1745888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
1755888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
1765888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                @Override
1775888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                public int getLabelId() {
1785888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    return R.string.percentile_75;
1795888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                }
180702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            }, new StatGen() {
181702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                @Override
182702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                public double getValue(double[] sortedValues) {
183702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                    return getStdDev(sortedValues);
184702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                }
185702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
186702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                @Override
187702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                public int getLabelId() {
188702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                    return R.string.std_dev;
189702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                }
190702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            }, new StatGen() {
191702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                @Override
192702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                public double getValue(double[] sortedValues) {
193702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                    return getMean(sortedValues);
194702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                }
195702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
196702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                @Override
197702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                public int getLabelId() {
198702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                    return R.string.mean;
199702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik                }
2005888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            },
2015888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    };
2025888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2035888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    public PlaybackGraphs() {
2045888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        whiteLabels = new Paint();
2055888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        whiteLabels.setColor(Color.WHITE);
20621555abad7ba5f5377052e2644974d3ce8c37869Chris Craik        whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3);
2075888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
2085888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2095888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
210702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    protected final double[][] mStats = new double[Metrics.length][Stats.length];
211555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik    protected HashMap<String, Double> mSingleStats;
2125888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
213702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) {
214702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        // create graph out of rectangles, one per frame
215702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        int lastBar = 0;
216702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
217702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            TileData frame[] = data.frames[frameIndex];
2186f92c15180f66d0ec7c8b20ea47f479468255970Chris Craik            int newBar = (int)((frame[0].top + frame[0].bottom) * frame[0].scale / 2.0f);
219702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
220702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            MetricGen s = Metrics[metricIndex];
221702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            double absoluteValue = s.getValue(frame);
222702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            double relativeValue = absoluteValue / s.getMax();
223702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            relativeValue = Math.min(1,relativeValue);
224702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            relativeValue = Math.max(0,relativeValue);
225702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            int rightPos = (int) (-BAR_WIDTH * metricIndex);
226702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
227702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
228702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            ShapeDrawable graphBar = new ShapeDrawable();
229702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            graphBar.getPaint().setColor(Color.BLUE);
230702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
231702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
232702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            mShapes.add(graphBar);
233702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            metricValues[frameIndex] = absoluteValue;
234702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            lastBar = newBar;
235702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        }
236702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik    }
237702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
238555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik    public void setData(RunData data) {
2395888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        mShapes.clear();
240555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik        double metricValues[] = new double[data.frames.length];
2415888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
242702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik        mSingleStats = data.singleStats;
243702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik
244555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik        if (data.frames.length == 0) {
2455888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            return;
2465888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
2475888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2485888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
249702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            // calculate metric based on list of frames
250702c6fdc4799593c16eb0051703e3bd62086ff42Chris Craik            gatherFrameMetric(metricIndex, metricValues, data);
2515888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2525888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            // store aggregate statistics per metric (median, and similar)
2535888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            Arrays.sort(metricValues);
2545888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
255555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik                mStats[metricIndex][statIndex] =
256555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik                        Stats[statIndex].getValue(metricValues);
2575888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            }
2585888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
2595888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
2605888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2615888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    public void drawVerticalShiftedShapes(Canvas canvas,
2625888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            ArrayList<ShapeDrawable> shapes) {
2635888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        // Shapes drawn here are drawn relative to the viewRect
2645888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        Rect viewRect = shapes.get(shapes.size() - 1).getBounds();
26521555abad7ba5f5377052e2644974d3ce8c37869Chris Craik        canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top);
2665888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2675888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        for (ShapeDrawable shape : mShapes) {
2685888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            shape.draw(canvas);
2695888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
2705888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        for (ShapeDrawable shape : shapes) {
2715888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            shape.draw(canvas);
2725888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
2735888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
2745888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2755888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
276555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik            ArrayList<String> strings, Resources resources) {
2775888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
2785888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2795888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        canvas.translate(BAR_WIDTH * Metrics.length, 0);
2805888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2815888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        canvas.save();
2825888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        drawVerticalShiftedShapes(canvas, shapes);
2835888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        canvas.restore();
2845888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik
2855888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
2865888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            String label = resources.getString(
2875888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                    Metrics[metricIndex].getLabelId());
2885888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            int xPos = (metricIndex + 1) * -BAR_WIDTH;
2895888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            int yPos = LABELOFFSET;
2905888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            canvas.drawText(label, xPos, yPos, whiteLabels);
2915888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
2921d36d0fc7f776016c0282ae7ad8e01af81de6bf6Chris Craik                String statLabel = resources.getString(
2931d36d0fc7f776016c0282ae7ad8e01af81de6bf6Chris Craik                        Stats[statIndex].getLabelId()).substring(0,3);
2941d36d0fc7f776016c0282ae7ad8e01af81de6bf6Chris Craik                label = statLabel + " " + resources.getString(
2951d36d0fc7f776016c0282ae7ad8e01af81de6bf6Chris Craik                        R.string.format_stat, mStats[metricIndex][statIndex]);
29621555abad7ba5f5377052e2644974d3ce8c37869Chris Craik                yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
29721555abad7ba5f5377052e2644974d3ce8c37869Chris Craik                        / 2;
2985888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik                canvas.drawText(label, xPos, yPos, whiteLabels);
2995888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik            }
3005888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
301555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik        for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
30221555abad7ba5f5377052e2644974d3ce8c37869Chris Craik            int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
303555c55ed65056e2236430f92e81c1fb6acd05dcdChris Craik            canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
3045888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik        }
3055888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik    }
3065888ec2b30d2c76de84e3b840bf286fa371ccb4fChris Craik}
307