177d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskipackage com.android.server.am;
277d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
677d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport static android.app.ActivityManager.StackId.HOME_STACK_ID;
7caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynskiimport static android.app.ActivityManager.StackId.PINNED_STACK_ID;
8f970410afef518003c84eef022194848b2a4f606Jorim Jaggiimport static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
9f970410afef518003c84eef022194848b2a4f606Jorim Jaggiimport static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
100e381e278a2c2a3a7c86c9951ac5cbcdc3a186f4Filip Gruszczynskiimport static com.android.server.am.ActivityStack.STACK_INVISIBLE;
1177d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
12275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggiimport android.annotation.Nullable;
1377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport android.app.ActivityManager.StackId;
1477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport android.content.Context;
1577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport android.os.SystemClock;
16f970410afef518003c84eef022194848b2a4f606Jorim Jaggiimport android.util.Slog;
1777d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
1877d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiimport com.android.internal.logging.MetricsLogger;
19275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggiimport com.android.internal.logging.MetricsProto.MetricsEvent;
2077d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
211e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggiimport java.util.ArrayList;
221e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi
2377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski/**
2477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski * Handles logging into Tron.
2577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski */
2677d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynskiclass ActivityMetricsLogger {
27f970410afef518003c84eef022194848b2a4f606Jorim Jaggi
28f970410afef518003c84eef022194848b2a4f606Jorim Jaggi    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_AM;
29f970410afef518003c84eef022194848b2a4f606Jorim Jaggi
3077d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    // Window modes we are interested in logging. If we ever introduce a new type, we need to add
3177d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
3277d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private static final int WINDOW_STATE_STANDARD = 0;
3377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
3477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private static final int WINDOW_STATE_FREEFORM = 2;
3577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private static final int WINDOW_STATE_INVALID = -1;
3677d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
37275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private static final long INVALID_START_TIME = -1;
38275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
3977d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
4077d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    // time we log.
4177d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
42ae255ee61b5e174c2164e58389b8a7ff8a95e14dChris Wren            "window_time_0", "window_time_1", "window_time_2"};
4377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
4477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private int mWindowState = WINDOW_STATE_STANDARD;
4577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private long mLastLogTimeSecs;
4677d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private final ActivityStackSupervisor mSupervisor;
4777d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    private final Context mContext;
4877d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
49275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private long mCurrentTransitionStartTime = INVALID_START_TIME;
50275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private boolean mLoggedWindowsDrawn;
51275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private boolean mLoggedStartingWindowDrawn;
52275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private boolean mLoggedTransitionStarting;
53275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
5477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
5577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
5677d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        mSupervisor = supervisor;
5777d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        mContext = context;
5877d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    }
5977d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
6077d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    void logWindowState() {
6177d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        final long now = SystemClock.elapsedRealtime() / 1000;
6277d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        if (mWindowState != WINDOW_STATE_INVALID) {
6377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski            // We log even if the window state hasn't changed, because the user might remain in
6477d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski            // home/fullscreen move forever and we would like to track this kind of behavior
6577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski            // too.
6677d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski            MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
6777d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski                    (int) (now - mLastLogTimeSecs));
6877d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        }
6977d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        mLastLogTimeSecs = now;
7077d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski
7177d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
728051c5c89060906f5a3a1ca4adb3b53bb423e56bWale Ogunwale        if (stack != null && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
7377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski            mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
74caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski            return;
75caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        }
76caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        mWindowState = WINDOW_STATE_INVALID;
77caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        stack = mSupervisor.getFocusedStack();
78caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        if (stack.mStackId == PINNED_STACK_ID) {
79caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski            stack = mSupervisor.findStackBehind(stack);
8077d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        }
81caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        if (stack.mStackId == HOME_STACK_ID
82caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski                || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
83caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski            mWindowState = WINDOW_STATE_STANDARD;
84caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        } else if (stack.mStackId == DOCKED_STACK_ID) {
85f970410afef518003c84eef022194848b2a4f606Jorim Jaggi            Slog.wtf(TAG, "Docked stack shouldn't be the focused stack, because it reported not"
86f970410afef518003c84eef022194848b2a4f606Jorim Jaggi                    + " being visible.");
87f970410afef518003c84eef022194848b2a4f606Jorim Jaggi            mWindowState = WINDOW_STATE_INVALID;
88caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        } else if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
89caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski            mWindowState = WINDOW_STATE_FREEFORM;
90caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski        } else if (StackId.isStaticStack(stack.mStackId)) {
91caae14e478e115d01f9b32890cb31231575e65ddFilip Gruszczynski            throw new IllegalStateException("Unknown stack=" + stack);
9277d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski        }
9377d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski    }
94275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
95275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    /**
96275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * Notifies the tracker at the earliest possible point when we are starting to launch an
97275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * activity.
98275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     */
99275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    void notifyActivityLaunching() {
100275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mCurrentTransitionStartTime = System.currentTimeMillis();
101275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
102275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
103275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    /**
1041e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi     * Notifies the tracker that the activity is actually launching.
1051e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi     *
1061e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi     * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
1071e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi     *                   launch
1081e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi     * @param launchedActivity the activity that is being launched
1091e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi     */
1101e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi    void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
1111e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        final ProcessRecord processRecord = launchedActivity != null
1121e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
1131e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                        launchedActivity.appInfo.uid)
1141e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                : null;
1151e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        final boolean processRunning = processRecord != null;
1161e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        final String componentName = launchedActivity != null
1171e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                ? launchedActivity.shortComponentName
1181e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                : null;
1191e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi
1201e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        // We consider this a "process switch" if the process of the activity that gets launched
1211e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        // didn't have an activity that was in started state. In this case, we assume that lot
1221e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        // of caches might be purged so the time until it produces the first frame is very
1231e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        // interesting.
1241e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        final boolean processSwitch = processRecord == null
1251e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                || !hasStartedActivity(processRecord, launchedActivity);
1261e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi
1271e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        notifyActivityLaunched(resultCode, componentName, processRunning, processSwitch);
1281e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi    }
1291e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi
1301e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi    private boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
1311e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        final ArrayList<ActivityRecord> activities = record.activities;
1321e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        for (int i = activities.size() - 1; i >= 0; i--) {
1331e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi            final ActivityRecord activity = activities.get(i);
1341e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi            if (launchedActivity == activity) {
1351e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                continue;
1361e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi            }
1371e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi            if (!activity.stopped) {
1381e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi                return true;
1391e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi            }
1401e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        }
1411e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi        return false;
1421e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi    }
1431e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi
1441e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi    /**
145275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * Notifies the tracker the the activity is actually launching.
146275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     *
147275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
148275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     *                   launch
149275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * @param componentName the component name of the activity being launched
150275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * @param processRunning whether the process that will contains the activity is already running
151be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5Jorim Jaggi     * @param processSwitch whether the process that will contain the activity didn't have any
152be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5Jorim Jaggi     *                      activity that was stopped, i.e. the started activity is "switching"
153be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5Jorim Jaggi     *                      processes
154275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     */
1551e630c08296ec6cc311cc4e1c397f7ca50a1a735Jorim Jaggi    private void notifyActivityLaunched(int resultCode, @Nullable String componentName,
156be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5Jorim Jaggi            boolean processRunning, boolean processSwitch) {
157275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
158be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5Jorim Jaggi        if (resultCode < 0 || componentName == null || !processSwitch) {
159275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
160be67c90f4c2255cab3bc036ecdc8d9636ed5e4b5Jorim Jaggi            // Failed to launch or it was not a process switch, so we don't care about the timing.
161275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            reset();
162275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            return;
163275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        }
164275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
165275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_COMPONENT_NAME,
166275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi                componentName);
167275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_PROCESS_RUNNING,
168275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi                processRunning);
169275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
170275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi                (int) (SystemClock.uptimeMillis() / 1000));
171275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
172275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
173275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    /**
174275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * Notifies the tracker that all windows of the app have been drawn.
175275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     */
176275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    void notifyWindowsDrawn() {
177275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        if (!isTransitionActive() || mLoggedWindowsDrawn) {
178275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            return;
179275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        }
180275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS,
181275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi                calculateCurrentDelay());
182275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mLoggedWindowsDrawn = true;
183275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        if (mLoggedTransitionStarting) {
184275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            reset();
185275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        }
186275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
187275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
188275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    /**
189275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * Notifies the tracker that the starting window was drawn.
190275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     */
191275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    void notifyStartingWindowDrawn() {
192275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        if (!isTransitionActive() || mLoggedStartingWindowDrawn) {
193275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            return;
194275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        }
195275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mLoggedStartingWindowDrawn = true;
196275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
197275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi                calculateCurrentDelay());
198275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
199275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
200275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    /**
201275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * Notifies the tracker that the app transition is starting.
202275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     *
203275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     * @param reason The reason why we started it. Must be on of
204275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     *               ActivityManagerInternal.APP_TRANSITION_* reasons.
205275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi     */
206275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    void notifyTransitionStarting(int reason) {
207275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        if (!isTransitionActive() || mLoggedTransitionStarting) {
208275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            return;
209275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        }
210275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_REASON, reason);
211275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DELAY_MS,
212275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi                calculateCurrentDelay());
213275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mLoggedTransitionStarting = true;
214275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        if (mLoggedWindowsDrawn) {
215275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi            reset();
216275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        }
217275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
218275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
219275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private boolean isTransitionActive() {
220275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        return mCurrentTransitionStartTime != INVALID_START_TIME;
221275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
222275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
223275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private void reset() {
224275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mCurrentTransitionStartTime = INVALID_START_TIME;
225275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mLoggedWindowsDrawn = false;
226275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mLoggedTransitionStarting = false;
227275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        mLoggedStartingWindowDrawn = false;
228275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
229275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
230275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    private int calculateCurrentDelay() {
231275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi
232275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        // Shouldn't take more than 25 days to launch an app, so int is fine here.
233275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi        return (int) (System.currentTimeMillis() - mCurrentTransitionStartTime);
234275561a74677f9d6c8f3f2cebc3cfea416ca586dJorim Jaggi    }
23577d9448e2d6dd8a45c5fedef43c8a1cf4afd28b9Filip Gruszczynski}
236