17cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu/*
27cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * Copyright (C) 2014 The Android Open Source Project
37cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu *
47cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * Licensed under the Apache License, Version 2.0 (the "License");
57cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * you may not use this file except in compliance with the License.
67cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * You may obtain a copy of the License at
77cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu *
87cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu *      http://www.apache.org/licenses/LICENSE-2.0
97cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu *
107cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * Unless required by applicable law or agreed to in writing, software
117cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * distributed under the License is distributed on an "AS IS" BASIS,
127cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * See the License for the specific language governing permissions and
147cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * limitations under the License.
157cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu */
167cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
177cbeceed6d03d0550797c435f3db6205714cd49fDoris Liupackage android.util;
187cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
197cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu/**
207cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * This class tracks the timing of important state changes in camera app (e.g latency
217cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * of cold/warm start of the activity, mode switch duration, etc). We can then query
227cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * these values from the instrument tests, which will be helpful for tracking camera
237cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu * app performance and regression tests.
247cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu */
257cbeceed6d03d0550797c435f3db6205714cd49fDoris Liupublic class CameraPerformanceTracker {
267cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
277cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    // Event types to track.
287cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static final int ACTIVITY_START = 0;
297cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static final int ACTIVITY_PAUSE = 1;
307cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static final int ACTIVITY_RESUME = 2;
317cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static final int MODE_SWITCH_START = 3;
327cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static final int FIRST_PREVIEW_FRAME = 5;
337cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static final int UNSET = -1;
347cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
357cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private static final String TAG = "CameraPerformanceTracker";
367cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private static final boolean DEBUG = false;
377cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private static CameraPerformanceTracker sInstance;
387cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
397cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    // Internal tracking time.
407cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private long mAppStartTime = UNSET;
417cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private long mAppResumeTime = UNSET;
427cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private long mModeSwitchStartTime = UNSET;
437cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
447cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    // Duration and/or latency or later querying.
457cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private long mFirstPreviewFrameLatencyColdStart = UNSET;
467cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private long mFirstPreviewFrameLatencyWarmStart = UNSET;
477cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    // TODO: Need to how to best track the duration for each switch from/to pair.
487cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private long mModeSwitchDuration = UNSET;
497cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
507cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    private CameraPerformanceTracker() {
517cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        // Private constructor to ensure that it can only be created from within
527cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        // the class.
537cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    }
547cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
557cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    /**
567cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * This gets called when an important state change happens. Based on the type
577cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * of the event/state change, either we will record the time of the event, or
587cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * calculate the duration/latency.
597cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *
607cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * @param eventType type of a event to track
617cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     */
627cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static void onEvent(int eventType) {
637cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        if (sInstance == null) {
647cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            sInstance = new CameraPerformanceTracker();
657cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        }
667cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        long currentTime = System.currentTimeMillis();
677cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        switch (eventType) {
687cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            case ACTIVITY_START:
697cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                sInstance.mAppStartTime = currentTime;
707cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                break;
717cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            case ACTIVITY_PAUSE:
727cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                sInstance.mFirstPreviewFrameLatencyWarmStart = UNSET;
737cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                break;
747cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            case ACTIVITY_RESUME:
757cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                sInstance.mAppResumeTime = currentTime;
767cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                break;
777cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            case FIRST_PREVIEW_FRAME:
7854092780951fd84ffd98cc6ea3e54ad388e7db4cPuneet Lall                Log.d(TAG, "First preview frame received");
797cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                if (sInstance.mFirstPreviewFrameLatencyColdStart == UNSET) {
807cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                    // Cold start.
817cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                    sInstance.mFirstPreviewFrameLatencyColdStart =
827cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                            currentTime - sInstance.mAppStartTime;
837cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                } else {
847cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                    // Warm Start.
857cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                    sInstance.mFirstPreviewFrameLatencyWarmStart =
867cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                            currentTime - sInstance.mAppResumeTime;
877cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                }
887cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                // If the new frame is triggered by the mode switch, track the duration.
897cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                if (sInstance.mModeSwitchStartTime != UNSET) {
907cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                    sInstance.mModeSwitchDuration = currentTime - sInstance.mModeSwitchStartTime;
917cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                    sInstance.mModeSwitchStartTime = UNSET;
927cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                }
937cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                break;
947cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            case MODE_SWITCH_START:
957cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                sInstance.mModeSwitchStartTime = currentTime;
967cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                break;
977cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            default:
987cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu                break;
997cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        }
1005f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren        if (DEBUG && eventType == FIRST_PREVIEW_FRAME) {
1015f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren            Log.d(TAG, "Mode switch duration: " + (sInstance.mModeSwitchDuration
1025f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren                == UNSET ? "UNSET" : sInstance.mModeSwitchDuration));
1035f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren            Log.d(TAG, "Cold start latency: " + (sInstance.mFirstPreviewFrameLatencyColdStart
1045f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren                == UNSET ? "UNSET" : sInstance.mFirstPreviewFrameLatencyColdStart));
1055f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren            Log.d(TAG, "Warm start latency: " + (sInstance.mFirstPreviewFrameLatencyWarmStart
1065f38da866e2f0eb057662619ef8703ace40eb64cErin Dahlgren                == UNSET ? "UNSET" : sInstance.mFirstPreviewFrameLatencyWarmStart));
1077cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        }
1087cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    }
1097cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
1107cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    //TODO: Hook up these getters in the instrument tests.
1117cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    /**
1127cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * Gets the latency of a cold start of the app, measured from the time onCreate
1137cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * gets called to the time first preview frame gets received.
1147cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *
1157cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * @return latency of a cold start. If no instances have been created, return
1167cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *         UNSET.
1177cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     */
1187cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static long getColdStartLatency() {
1197cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        if (sInstance == null) {
1207cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            return UNSET;
1217cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        }
1227cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        return sInstance.mFirstPreviewFrameLatencyColdStart;
1237cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    }
1247cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
1257cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    /**
1267cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * Gets the latency of a warm start of the app, measured from the time onResume
1277cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * gets called to the time next preview frame gets received.
1287cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *
1297cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * @return latency of a warm start. If no instances have been created,
1307cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *         return UNSET.
1317cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     */
1327cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static long getWarmStartLatency() {
1337cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        if (sInstance == null) {
1347cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            return UNSET;
1357cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        }
1367cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        return sInstance.mFirstPreviewFrameLatencyWarmStart;
1377cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    }
1387cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu
1397cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    /**
1407cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * Gets the duration of the mode switch, measured from the start of a mode switch
1417cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * to the time next preview frame gets received.
1427cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *
1437cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     * @return duration of the mode switch. If no instances have been created,
1447cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     *         return UNSET.
1457cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu     */
1467cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    public static long getModeSwitchDuration() {
1477cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        if (sInstance == null) {
1487cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu            return UNSET;
1497cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        }
1507cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu        return sInstance.mModeSwitchDuration;
1517cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu    }
1527cbeceed6d03d0550797c435f3db6205714cd49fDoris Liu}
153