103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck/*
203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * Copyright (C) 2016 The Android Open Source Project
303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck *
403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * Licensed under the Apache License, Version 2.0 (the "License");
503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * you may not use this file except in compliance with the License.
603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * You may obtain a copy of the License at
703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck *
803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck *      http://www.apache.org/licenses/LICENSE-2.0
903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck *
1003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * Unless required by applicable law or agreed to in writing, software
1103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * distributed under the License is distributed on an "AS IS" BASIS,
1203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * See the License for the specific language governing permissions and
1403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck * limitations under the License.
1503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck */
1603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
1703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckpackage com.android.test.uibench;
1803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
1903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.app.Activity;
20e692f31fd687abacc58dbf34c28527b224a9598aJohn Reckimport android.content.Context;
2103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.Canvas;
2203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.Color;
2303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.ColorFilter;
2403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.Paint;
2503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.PixelFormat;
2603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.Rect;
2703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.graphics.drawable.Drawable;
2803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.os.Bundle;
2903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.os.Handler;
3003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.os.HandlerThread;
3103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.os.Message;
32e692f31fd687abacc58dbf34c28527b224a9598aJohn Reckimport android.util.AttributeSet;
3303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.view.FrameMetrics;
3403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.view.View;
3503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.view.Window;
3603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.view.Window.OnFrameMetricsAvailableListener;
3703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.view.animation.AnimationUtils;
3803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckimport android.widget.TextView;
3903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
4003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reckpublic class RenderingJitter extends Activity {
4103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private TextView mJitterReport;
4203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private TextView mUiFrameTimeReport;
4303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private TextView mRenderThreadTimeReport;
4403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private TextView mTotalFrameTimeReport;
4503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private TextView mMostlyTotalFrameTimeReport;
46e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck    private PointGraphView mGraph;
4703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
4803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private static Handler sMetricsHandler;
4903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    static {
5003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        HandlerThread thread = new HandlerThread("frameMetricsListener");
5103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        thread.start();
5203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        sMetricsHandler = new Handler(thread.getLooper());
5303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    }
5403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
5503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private Handler mUpdateHandler = new Handler() {
5603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
5703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public void handleMessage(Message msg) {
5803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            switch (msg.what) {
5903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                case R.id.jitter_mma:
6003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    mJitterReport.setText((CharSequence) msg.obj);
6103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    break;
6203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                case R.id.totalish_mma:
6303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    mMostlyTotalFrameTimeReport.setText((CharSequence) msg.obj);
6403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    break;
6503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                case R.id.ui_frametime_mma:
6603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    mUiFrameTimeReport.setText((CharSequence) msg.obj);
6703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    break;
6803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                case R.id.rt_frametime_mma:
6903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    mRenderThreadTimeReport.setText((CharSequence) msg.obj);
7003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    break;
7103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                case R.id.total_mma:
7203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    mTotalFrameTimeReport.setText((CharSequence) msg.obj);
7303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    break;
74e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                case R.id.graph:
75e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    mGraph.addJitterSample(msg.arg1, msg.arg2);
76e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    break;
7703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
7803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
7903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    };
8003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
8103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    @Override
8203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    protected void onCreate(Bundle savedInstanceState) {
8303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        super.onCreate(savedInstanceState);
8403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        setContentView(R.layout.rendering_jitter);
8503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        View content = findViewById(android.R.id.content);
8603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        content.setBackground(new AnimatedBackgroundDrawable());
8703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        content.setKeepScreenOn(true);
8851efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mJitterReport = findViewById(R.id.jitter_mma);
8951efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mMostlyTotalFrameTimeReport = findViewById(R.id.totalish_mma);
9051efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mUiFrameTimeReport = findViewById(R.id.ui_frametime_mma);
9151efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mRenderThreadTimeReport = findViewById(R.id.rt_frametime_mma);
9251efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mTotalFrameTimeReport = findViewById(R.id.total_mma);
9351efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mGraph = findViewById(R.id.graph);
9403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        mJitterReport.setText("abcdefghijklmnopqrstuvwxyz");
9503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        mMostlyTotalFrameTimeReport.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
9603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        mUiFrameTimeReport.setText("0123456789");
9703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        mRenderThreadTimeReport.setText(",.!()[]{};");
9803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        getWindow().addOnFrameMetricsAvailableListener(mMetricsListener, sMetricsHandler);
9903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    }
10003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
101e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck    public static final class PointGraphView extends View {
102e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private static final float[] JITTER_LINES_MS = {
103e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                .5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 5.0f
104e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        };
105e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private static final String[] JITTER_LINES_LABELS = makeLabels(JITTER_LINES_MS);
106e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private static final int[] JITTER_LINES_COLORS = new int[] {
107e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                0xFF00E676, 0xFFFFF176, 0xFFFDD835, 0xFFFBC02D, 0xFFF9A825,
108e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                0xFFF57F17, 0xFFDD2C00
109e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        };
110e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private Paint mPaint = new Paint();
111e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float[] mJitterYs = new float[JITTER_LINES_MS.length];
112e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float mLabelWidth;
113e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float mLabelHeight;
114e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float mDensity;
115e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float mGraphScale;
116e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float mGraphMaxMs;
117e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
118e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float[] mJitterPoints;
119e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float[] mJitterAvgPoints;
120e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
121e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        public PointGraphView(Context context, AttributeSet attrs) {
122e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            super(context, attrs);
123e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            setWillNotDraw(false);
124e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mDensity = context.getResources().getDisplayMetrics().density;
125e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.setTextSize(dp(10));
126e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            Rect textBounds = new Rect();
127e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.getTextBounds("8.8", 0, 3, textBounds);
128e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mLabelWidth = textBounds.width() + dp(2);
129e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mLabelHeight = textBounds.height();
130e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        }
131e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
132e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        public void addJitterSample(int jitterUs, int jitterUsAvg) {
133e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            for (int i = 1; i < mJitterPoints.length - 2; i += 2) {
134e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                mJitterPoints[i] = mJitterPoints[i + 2];
135e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                mJitterAvgPoints[i] = mJitterAvgPoints[i + 2];
136e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
137e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mJitterPoints[mJitterPoints.length - 1] =
138e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    getHeight() - mGraphScale * (jitterUs / 1000.0f);
139e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mJitterAvgPoints[mJitterAvgPoints.length - 1] =
140e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    getHeight() - mGraphScale * (jitterUsAvg / 1000.0f);
141e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            invalidate();
142e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        }
143e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
144e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private float dp(float dp) {
145e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            return mDensity * dp;
146e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        }
147e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
148e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        @Override
149e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        protected void onDraw(Canvas canvas) {
150e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            canvas.drawColor(0x90000000);
151e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            int h = getHeight();
152e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            int w = getWidth();
153e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.setColor(Color.WHITE);
154e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.setStrokeWidth(dp(1));
155e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            canvas.drawLine(mLabelWidth, 0, mLabelWidth, h, mPaint);
156e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
157e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                canvas.drawText(JITTER_LINES_LABELS[i],
158e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                        0, (float) Math.floor(mJitterYs[i] + mLabelHeight * .5f), mPaint);
159e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
160e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
161e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                mPaint.setColor(JITTER_LINES_COLORS[i]);
162e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                canvas.drawLine(mLabelWidth, mJitterYs[i], w, mJitterYs[i], mPaint);
163e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
164e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.setStrokeWidth(dp(2));
165e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.setColor(Color.WHITE);
166e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            canvas.drawPoints(mJitterPoints, mPaint);
167e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mPaint.setColor(0xFF2196F3);
168e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            canvas.drawPoints(mJitterAvgPoints, mPaint);
169e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        }
170e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
171e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        @Override
172e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
173e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            super.onSizeChanged(w, h, oldw, oldh);
174e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            int graphWidth = (int) ((w - mLabelWidth - dp(1)) / mDensity);
175e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            float[] oldJitterPoints = mJitterPoints;
176e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            float[] oldJitterAvgPoints = mJitterAvgPoints;
177e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mJitterPoints = new float[graphWidth * 2];
178e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mJitterAvgPoints = new float[graphWidth * 2];
179e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            for (int i = 0; i < mJitterPoints.length; i += 2) {
180e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                mJitterPoints[i] = mLabelWidth + (i / 2 + 1) * mDensity;
181e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                mJitterAvgPoints[i] = mJitterPoints[i];
182e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
183e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            if (oldJitterPoints != null) {
184e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                int newIndexShift = Math.max(mJitterPoints.length - oldJitterPoints.length, 0);
185e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                int oldIndexShift = oldJitterPoints.length - mJitterPoints.length;
186e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                for (int i = 1 + newIndexShift; i < mJitterPoints.length; i += 2) {
187e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    mJitterPoints[i] = oldJitterPoints[i + oldIndexShift];
188e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    mJitterAvgPoints[i] = oldJitterAvgPoints[i + oldIndexShift];
189e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                }
190e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
191e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mGraphMaxMs = JITTER_LINES_MS[JITTER_LINES_MS.length - 1] + .5f;
192e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mGraphScale = (h / mGraphMaxMs);
193e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            for (int i = 0; i < JITTER_LINES_MS.length; i++) {
194e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                mJitterYs[i] = (float) Math.floor(h - mGraphScale * JITTER_LINES_MS[i]);
195e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
196e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        }
197e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
198e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        private static String[] makeLabels(float[] divisions) {
199e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            String[] ret = new String[divisions.length];
200e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            for (int i = 0; i < divisions.length; i++) {
201e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                ret[i] = Float.toString(divisions[i]);
202e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            }
203e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            return ret;
204e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck        }
205e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck    }
206e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck
20703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private final OnFrameMetricsAvailableListener mMetricsListener = new OnFrameMetricsAvailableListener() {
20803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private final static double WEIGHT = 40;
20903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private long mPreviousFrameTotal;
21003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private double mJitterMma;
21103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private double mUiFrametimeMma;
21203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private double mRtFrametimeMma;
21303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private double mTotalFrametimeMma;
21403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private double mMostlyTotalFrametimeMma;
21503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private boolean mNeedsFirstValues = true;
21603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
21703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
21803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
21903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                int dropCountSinceLastInvocation) {
22003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (frameMetrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1) {
22103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                return;
22203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
22303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
22403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            long uiDuration = frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)
22503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    + frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION)
22603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    + frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)
22703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    + frameMetrics.getMetric(FrameMetrics.DRAW_DURATION);
22803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            long rtDuration = frameMetrics.getMetric(FrameMetrics.SYNC_DURATION)
22903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    + frameMetrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION);
23003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            long totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
23103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            long jitter = Math.abs(totalDuration - mPreviousFrameTotal);
23203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (mNeedsFirstValues) {
23303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mJitterMma = 0;
23403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mUiFrametimeMma = uiDuration;
23503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mRtFrametimeMma = rtDuration;
23603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mTotalFrametimeMma = totalDuration;
23703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mMostlyTotalFrametimeMma = uiDuration + rtDuration;
23803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mNeedsFirstValues = false;
23903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            } else {
24003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mJitterMma = add(mJitterMma, jitter);
24103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mUiFrametimeMma = add(mUiFrametimeMma, uiDuration);
24203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mRtFrametimeMma = add(mRtFrametimeMma, rtDuration);
24303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mTotalFrametimeMma = add(mTotalFrametimeMma, totalDuration);
24403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mMostlyTotalFrametimeMma = add(mMostlyTotalFrametimeMma, uiDuration + rtDuration);
24503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
24603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mPreviousFrameTotal = totalDuration;
24703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mUpdateHandler.obtainMessage(R.id.jitter_mma,
24803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    String.format("Jitter: %.3fms", toMs(mJitterMma))).sendToTarget();
24903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mUpdateHandler.obtainMessage(R.id.totalish_mma,
25003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    String.format("CPU-total duration: %.3fms", toMs(mMostlyTotalFrametimeMma))).sendToTarget();
25103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mUpdateHandler.obtainMessage(R.id.ui_frametime_mma,
25203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    String.format("UI duration: %.3fms", toMs(mUiFrametimeMma))).sendToTarget();
25303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mUpdateHandler.obtainMessage(R.id.rt_frametime_mma,
25403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    String.format("RT duration: %.3fms", toMs(mRtFrametimeMma))).sendToTarget();
25503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mUpdateHandler.obtainMessage(R.id.total_mma,
25603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    String.format("Total duration: %.3fms", toMs(mTotalFrametimeMma))).sendToTarget();
257e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck            mUpdateHandler.obtainMessage(R.id.graph, (int) (jitter / 1000),
258e692f31fd687abacc58dbf34c28527b224a9598aJohn Reck                    (int) (mJitterMma / 1000)).sendToTarget();
25903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
26003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
26103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        double add(double previous, double today) {
26203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            return (((WEIGHT - 1) * previous) + today) / WEIGHT;
26303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
26403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
26503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        double toMs(double val) {
26603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            return val / 1000000;
26703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
26803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    };
26903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
27003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    private static final class AnimatedBackgroundDrawable extends Drawable {
27103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private static final int FROM_COLOR = 0xFF18FFFF;
27203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private static final int TO_COLOR = 0xFF40C4FF;
27303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private static final int DURATION = 1400;
27403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
27503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private final Paint mPaint;
27603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private boolean mReverse;
27703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private long mStartTime;
27803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private int mColor;
27903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
28003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private boolean mReverseX;
28103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private boolean mReverseY;
28203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private float mX;
28303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private float mY;
28403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private float mRadius;
28503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private float mMoveStep = 10.0f;
28603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
28703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public AnimatedBackgroundDrawable() {
28803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mPaint = new Paint();
28903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mPaint.setColor(0xFFFFFF00);
29003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mPaint.setAntiAlias(true);
29103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
29203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
29303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
29403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public void draw(Canvas canvas) {
29503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            stepColor();
29603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            canvas.drawColor(mColor);
29703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
29803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mX += (mReverseX ? -mMoveStep : mMoveStep);
29903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mY += (mReverseY ? -mMoveStep : mMoveStep);
30003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            clampXY();
30103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            canvas.drawCircle(mX, mY, mRadius, mPaint);
30203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
30303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            invalidateSelf();
30403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
30503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
30603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private void clampXY() {
30703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (mX <= mRadius) {
30803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mReverseX = false;
30903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mX = mRadius;
31003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
31103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (mY <= mRadius) {
31203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mReverseY = false;
31303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mY = mRadius;
31403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
31503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            float maxX = getBounds().width() - mRadius;
31603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (mX >= maxX) {
31703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mReverseX = true;
31803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mX = maxX;
31903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
32003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            float maxY = getBounds().height() - mRadius;
32103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (mY >= maxY) {
32203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mReverseY = true;
32303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mY = maxY;
32403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
32503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
32603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
32703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
32803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        protected void onBoundsChange(Rect bounds) {
32903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            super.onBoundsChange(bounds);
33003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mMoveStep = Math.min(bounds.width(), bounds.height()) / 130.0f;
33103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mRadius = Math.min(bounds.width(), bounds.height()) / 20.0f;
33203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
33303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
33403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
33503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public void setAlpha(int alpha) {
33603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
33703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
33803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
33903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public void setColorFilter(ColorFilter colorFilter) {
34003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
34103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
34203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        @Override
34303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        public int getOpacity() {
34403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            return PixelFormat.OPAQUE;
34503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
34603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck
34703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        private void stepColor() {
34803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (mStartTime == 0) {
34903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mStartTime = AnimationUtils.currentAnimationTimeMillis();
35003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
35103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            float frac = (AnimationUtils.currentAnimationTimeMillis() - mStartTime)
35203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                    / (float) DURATION;
35303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (frac > 1.0f) frac = 1.0f;
35403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            int dest = mReverse ? FROM_COLOR : TO_COLOR;
35503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            int src = mReverse ? TO_COLOR : FROM_COLOR;
35603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            int r = (int) (Color.red(src) + (Color.red(dest) - Color.red(src)) * frac);
35703a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            int g = (int) (Color.green(src) + (Color.green(dest) - Color.green(src)) * frac);
35803a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            int b = (int) (Color.blue(src) + (Color.blue(dest) - Color.blue(src)) * frac);
35903a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            mColor = Color.rgb(r, g, b);
36003a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            if (frac == 1.0f) {
36103a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mStartTime = 0;
36203a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck                mReverse = !mReverse;
36303a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck            }
36403a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck        }
36503a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck    }
36603a1edfe7f3aec23c8d459a53dadd2fe01b6eda2John Reck}
367