13258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu/*
23258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * Copyright (C) 2015 The Android Open Source Project
33258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu *
43258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * Licensed under the Apache License, Version 2.0 (the "License");
53258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * you may not use this file except in compliance with the License.
63258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * You may obtain a copy of the License at
73258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu *
83258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu *      http://www.apache.org/licenses/LICENSE-2.0
93258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu *
103258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * Unless required by applicable law or agreed to in writing, software
113258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * distributed under the License is distributed on an "AS IS" BASIS,
123258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * See the License for the specific language governing permissions and
143258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * limitations under the License
153258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu */
163258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
173258720f5526f766aa26c19cf01b32ac20d19d1dHall Liupackage com.android.server.telecom;
183258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
19d7fe686253f2135a948cafc776aa25db645ec27eHall Liuimport android.telecom.Connection;
203258720f5526f766aa26c19cf01b32ac20d19d1dHall Liuimport android.telecom.DisconnectCause;
21a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebingerimport android.telecom.Logging.EventManager;
22874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport android.telecom.ParcelableCallAnalytics;
23874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport android.telecom.TelecomAnalytics;
242f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liuimport android.util.Base64;
25a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebingerimport android.telecom.Log;
263258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
273258720f5526f766aa26c19cf01b32ac20d19d1dHall Liuimport com.android.internal.annotations.VisibleForTesting;
283258720f5526f766aa26c19cf01b32ac20d19d1dHall Liuimport com.android.internal.util.IndentingPrintWriter;
2983e882836bea5ae11f21dd619dd9ae3a2e0c12e3Tamas Berghammerimport com.android.server.telecom.nano.TelecomLogClass;
303258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
312f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liuimport java.io.PrintWriter;
32874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport java.util.ArrayList;
332f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liuimport java.util.Arrays;
34874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport java.util.Collections;
353258720f5526f766aa26c19cf01b32ac20d19d1dHall Liuimport java.util.HashMap;
36874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport java.util.LinkedList;
37874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport java.util.List;
383258720f5526f766aa26c19cf01b32ac20d19d1dHall Liuimport java.util.Map;
39d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liuimport java.util.PriorityQueue;
40874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport java.util.stream.Collectors;
41874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
42874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport static android.telecom.ParcelableCallAnalytics.AnalyticsEvent;
43874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liuimport static android.telecom.TelecomAnalytics.SessionTiming;
443258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
453258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu/**
463258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * A class that collects and stores data on how calls are being made, in order to
473258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu * aggregate these into useful statistics.
483258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu */
493258720f5526f766aa26c19cf01b32ac20d19d1dHall Liupublic class Analytics {
502f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu    public static final String ANALYTICS_DUMPSYS_ARG = "analytics";
512f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu    private static final String CLEAR_ANALYTICS_ARG = "clear";
522f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
53874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static final Map<String, Integer> sLogEventToAnalyticsEvent =
54874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            new HashMap<String, Integer>() {{
55a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SET_SELECT_PHONE_ACCOUNT,
56a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                        AnalyticsEvent.SET_SELECT_PHONE_ACCOUNT);
57a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REQUEST_HOLD, AnalyticsEvent.REQUEST_HOLD);
58a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REQUEST_UNHOLD, AnalyticsEvent.REQUEST_UNHOLD);
59a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SWAP, AnalyticsEvent.SWAP);
60a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SKIP_RINGING, AnalyticsEvent.SKIP_RINGING);
61a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.CONFERENCE_WITH, AnalyticsEvent.CONFERENCE_WITH);
62a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SPLIT_FROM_CONFERENCE, AnalyticsEvent.SPLIT_CONFERENCE);
63a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SET_PARENT, AnalyticsEvent.SET_PARENT);
64a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.MUTE, AnalyticsEvent.MUTE);
65a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.UNMUTE, AnalyticsEvent.UNMUTE);
66a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.AUDIO_ROUTE_BT, AnalyticsEvent.AUDIO_ROUTE_BT);
67a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.AUDIO_ROUTE_EARPIECE, AnalyticsEvent.AUDIO_ROUTE_EARPIECE);
68a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.AUDIO_ROUTE_HEADSET, AnalyticsEvent.AUDIO_ROUTE_HEADSET);
69a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.AUDIO_ROUTE_SPEAKER, AnalyticsEvent.AUDIO_ROUTE_SPEAKER);
70a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SILENCE, AnalyticsEvent.SILENCE);
71a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SCREENING_COMPLETED, AnalyticsEvent.SCREENING_COMPLETED);
72a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.BLOCK_CHECK_FINISHED, AnalyticsEvent.BLOCK_CHECK_FINISHED);
73a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.DIRECT_TO_VM_FINISHED, AnalyticsEvent.DIRECT_TO_VM_FINISHED);
74a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REMOTELY_HELD, AnalyticsEvent.REMOTELY_HELD);
75a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REMOTELY_UNHELD, AnalyticsEvent.REMOTELY_UNHELD);
76a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REQUEST_PULL, AnalyticsEvent.REQUEST_PULL);
77a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REQUEST_ACCEPT, AnalyticsEvent.REQUEST_ACCEPT);
78a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.REQUEST_REJECT, AnalyticsEvent.REQUEST_REJECT);
79a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SET_ACTIVE, AnalyticsEvent.SET_ACTIVE);
80a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SET_DISCONNECTED, AnalyticsEvent.SET_DISCONNECTED);
81a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SET_HOLD, AnalyticsEvent.SET_HOLD);
82a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SET_DIALING, AnalyticsEvent.SET_DIALING);
83a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.START_CONNECTION, AnalyticsEvent.START_CONNECTION);
84a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.BIND_CS, AnalyticsEvent.BIND_CS);
85a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.CS_BOUND, AnalyticsEvent.CS_BOUND);
86a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.SCREENING_SENT, AnalyticsEvent.SCREENING_SENT);
87a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.DIRECT_TO_VM_INITIATED, AnalyticsEvent.DIRECT_TO_VM_INITIATED);
88a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.BLOCK_CHECK_INITIATED, AnalyticsEvent.BLOCK_CHECK_INITIATED);
89a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.FILTERING_INITIATED, AnalyticsEvent.FILTERING_INITIATED);
90a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.FILTERING_COMPLETED, AnalyticsEvent.FILTERING_COMPLETED);
91a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.FILTERING_TIMED_OUT, AnalyticsEvent.FILTERING_TIMED_OUT);
92874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            }};
93874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
94874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static final Map<String, Integer> sLogSessionToSessionId =
95874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            new HashMap<String, Integer> () {{
96a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_ANSWER_CALL, SessionTiming.ICA_ANSWER_CALL);
97a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_REJECT_CALL, SessionTiming.ICA_REJECT_CALL);
98a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_DISCONNECT_CALL, SessionTiming.ICA_DISCONNECT_CALL);
99a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_HOLD_CALL, SessionTiming.ICA_HOLD_CALL);
100a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_UNHOLD_CALL, SessionTiming.ICA_UNHOLD_CALL);
101a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_MUTE, SessionTiming.ICA_MUTE);
102a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_SET_AUDIO_ROUTE, SessionTiming.ICA_SET_AUDIO_ROUTE);
103a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.ICA_CONFERENCE, SessionTiming.ICA_CONFERENCE);
104a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE,
105874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        SessionTiming.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);
106a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_SET_ACTIVE, SessionTiming.CSW_SET_ACTIVE);
107a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_SET_RINGING, SessionTiming.CSW_SET_RINGING);
108a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_SET_DIALING, SessionTiming.CSW_SET_DIALING);
109a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_SET_DISCONNECTED, SessionTiming.CSW_SET_DISCONNECTED);
110a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_SET_ON_HOLD, SessionTiming.CSW_SET_ON_HOLD);
111a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_REMOVE_CALL, SessionTiming.CSW_REMOVE_CALL);
112a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_SET_IS_CONFERENCED, SessionTiming.CSW_SET_IS_CONFERENCED);
113a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL,
114a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                        SessionTiming.CSW_ADD_CONFERENCE_CALL);
115874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
116874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            }};
117874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
118874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static final Map<String, Integer> sLogEventTimingToAnalyticsEventTiming =
119874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            new HashMap<String, Integer>() {{
120a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.ACCEPT_TIMING,
121874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.ACCEPT_TIMING);
122a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.REJECT_TIMING,
123874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.REJECT_TIMING);
124a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.DISCONNECT_TIMING,
125874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.DISCONNECT_TIMING);
126a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.HOLD_TIMING,
127874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.HOLD_TIMING);
128a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.UNHOLD_TIMING,
129874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.UNHOLD_TIMING);
130a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.OUTGOING_TIME_TO_DIALING_TIMING,
131874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.OUTGOING_TIME_TO_DIALING_TIMING);
132a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.BIND_CS_TIMING,
133874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.BIND_CS_TIMING);
134a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.SCREENING_COMPLETED_TIMING,
135874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.SCREENING_COMPLETED_TIMING);
136a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.DIRECT_TO_VM_FINISHED_TIMING,
137874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.DIRECT_TO_VM_FINISHED_TIMING);
138a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.BLOCK_CHECK_FINISHED_TIMING,
139874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.BLOCK_CHECK_FINISHED_TIMING);
140a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.FILTERING_COMPLETED_TIMING,
141874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.FILTERING_COMPLETED_TIMING);
142a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger                put(LogUtils.Events.Timings.FILTERING_TIMED_OUT_TIMING,
143874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.FILTERING_TIMED_OUT_TIMING);
144874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            }};
145874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
146874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static final Map<Integer, String> sSessionIdToLogSession = new HashMap<>();
147874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    static {
148874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        for (Map.Entry<String, Integer> e : sLogSessionToSessionId.entrySet()) {
149874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            sSessionIdToLogSession.put(e.getValue(), e.getKey());
1503258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
151874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    }
1523258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
153874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static class CallInfo {
154874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCallStartTime(long startTime) {
1553258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1563258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
157874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCallEndTime(long endTime) {
1583258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1593258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
160874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCallIsAdditional(boolean isAdditional) {
1613258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1623258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
163874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCallIsInterrupted(boolean isInterrupted) {
1643258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1653258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
166874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCallDisconnectCause(DisconnectCause disconnectCause) {
1673258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1683258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
169874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void addCallTechnology(int callTechnology) {
1703258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1713258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
172874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCreatedFromExistingConnection(boolean createdFromExistingConnection) {
173874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        }
174874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
175874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        public void setCallConnectionService(String connectionServiceName) {
176874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        }
177874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
178a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger        public void setCallEvents(EventManager.EventRecord records) {
1793258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
1804640c4fc55ca4118351330d68684ca9989661ccdHall Liu
1814640c4fc55ca4118351330d68684ca9989661ccdHall Liu        public void setCallIsVideo(boolean isVideo) {
1824640c4fc55ca4118351330d68684ca9989661ccdHall Liu        }
1834640c4fc55ca4118351330d68684ca9989661ccdHall Liu
1844640c4fc55ca4118351330d68684ca9989661ccdHall Liu        public void addVideoEvent(int eventId, int videoState) {
1854640c4fc55ca4118351330d68684ca9989661ccdHall Liu        }
1869d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu
1879d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        public void addInCallService(String serviceName, int type) {
1889d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        }
189d7fe686253f2135a948cafc776aa25db645ec27eHall Liu
190d7fe686253f2135a948cafc776aa25db645ec27eHall Liu        public void addCallProperties(int properties) {
191d7fe686253f2135a948cafc776aa25db645ec27eHall Liu        }
1923258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    }
1933258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
1943258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    /**
1953258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu     * A class that holds data associated with a call.
1963258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu     */
1973258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    @VisibleForTesting
1983258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    public static class CallInfoImpl extends CallInfo {
1993258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public String callId;
2003258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public long startTime;  // start time in milliseconds since the epoch. 0 if not yet set.
2013258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public long endTime;  // end time in milliseconds since the epoch. 0 if not yet set.
2023258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public int callDirection;  // one of UNKNOWN_DIRECTION, INCOMING_DIRECTION,
2033258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                                   // or OUTGOING_DIRECTION.
2043258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public boolean isAdditionalCall = false;  // true if the call came in while another call was
2053258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                                                  // in progress or if the user dialed this call
2063258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                                                  // while in the middle of another call.
2073258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public boolean isInterrupted = false;  // true if the call was interrupted by an incoming
2083258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                                               // or outgoing call.
2093258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public int callTechnologies;  // bitmask denoting which technologies a call used.
2103258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2113258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        // true if the Telecom Call object was created from an existing connection via
2123258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        // CallsManager#createCallForExistingConnection, for example, by ImsConference.
2133258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public boolean createdFromExistingConnection = false;
2143258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2153258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public DisconnectCause callTerminationReason;
2163258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public String connectionService;
2173258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public boolean isEmergency = false;
2183258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
219a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger        public EventManager.EventRecord callEvents;
220874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
2214640c4fc55ca4118351330d68684ca9989661ccdHall Liu        public boolean isVideo = false;
2222f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        public List<TelecomLogClass.VideoEvent> videoEvents;
2239d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        public List<TelecomLogClass.InCallServiceInfo> inCallServiceInfos;
224d7fe686253f2135a948cafc776aa25db645ec27eHall Liu        public int callProperties = 0;
225d7fe686253f2135a948cafc776aa25db645ec27eHall Liu
2264640c4fc55ca4118351330d68684ca9989661ccdHall Liu        private long mTimeOfLastVideoEvent = -1;
2274640c4fc55ca4118351330d68684ca9989661ccdHall Liu
2283258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        CallInfoImpl(String callId, int callDirection) {
2293258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callId = callId;
2303258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            startTime = 0;
2313258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            endTime = 0;
2323258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callDirection = callDirection;
2333258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            callTechnologies = 0;
2343258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            connectionService = "";
2354640c4fc55ca4118351330d68684ca9989661ccdHall Liu            videoEvents = new LinkedList<>();
2369d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            inCallServiceInfos = new LinkedList<>();
2373258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2383258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2393258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        CallInfoImpl(CallInfoImpl other) {
2403258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callId = other.callId;
2413258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.startTime = other.startTime;
2423258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.endTime = other.endTime;
2433258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callDirection = other.callDirection;
2443258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.isAdditionalCall = other.isAdditionalCall;
2453258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.isInterrupted = other.isInterrupted;
2463258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callTechnologies = other.callTechnologies;
2473258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.createdFromExistingConnection = other.createdFromExistingConnection;
2483258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.connectionService = other.connectionService;
2493258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.isEmergency = other.isEmergency;
250874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            this.callEvents = other.callEvents;
2514640c4fc55ca4118351330d68684ca9989661ccdHall Liu            this.isVideo = other.isVideo;
2524640c4fc55ca4118351330d68684ca9989661ccdHall Liu            this.videoEvents = other.videoEvents;
253d7fe686253f2135a948cafc776aa25db645ec27eHall Liu            this.callProperties = other.callProperties;
2543258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2553258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if (other.callTerminationReason != null) {
2563258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                this.callTerminationReason = new DisconnectCause(
2573258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                        other.callTerminationReason.getCode(),
2583258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                        other.callTerminationReason.getLabel(),
2593258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                        other.callTerminationReason.getDescription(),
2603258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                        other.callTerminationReason.getReason(),
2613258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                        other.callTerminationReason.getTone());
2623258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            } else {
2633258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                this.callTerminationReason = null;
2643258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            }
2653258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2663258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2673258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
2683258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCallStartTime(long startTime) {
2693258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting startTime for call " + callId + " to " + startTime);
2703258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.startTime = startTime;
2713258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2723258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2733258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
2743258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCallEndTime(long endTime) {
2753258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting endTime for call " + callId + " to " + endTime);
2763258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.endTime = endTime;
2773258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2783258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2793258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
2803258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCallIsAdditional(boolean isAdditional) {
2813258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting isAdditional for call " + callId + " to " + isAdditional);
2823258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.isAdditionalCall = isAdditional;
2833258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2843258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2853258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
2863258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCallIsInterrupted(boolean isInterrupted) {
2873258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting isInterrupted for call " + callId + " to " + isInterrupted);
2883258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.isInterrupted = isInterrupted;
2893258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2903258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2913258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
2923258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void addCallTechnology(int callTechnology) {
2933258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "adding callTechnology for call " + callId + ": " + callTechnology);
2943258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callTechnologies |= callTechnology;
2953258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
2963258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
2973258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
2983258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCallDisconnectCause(DisconnectCause disconnectCause) {
2993258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting disconnectCause for call " + callId + " to " + disconnectCause);
3003258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.callTerminationReason = disconnectCause;
3013258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
3023258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
3033258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
3043258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCreatedFromExistingConnection(boolean createdFromExistingConnection) {
3053258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting createdFromExistingConnection for call " + callId + " to "
3063258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + createdFromExistingConnection);
3073258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.createdFromExistingConnection = createdFromExistingConnection;
3083258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
3093258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
3103258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
3113258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public void setCallConnectionService(String connectionServiceName) {
3123258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Log.d(TAG, "setting connection service for call " + callId + ": "
3133258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + connectionServiceName);
3143258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            this.connectionService = connectionServiceName;
3153258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
3163258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
3173258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        @Override
318a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger        public void setCallEvents(EventManager.EventRecord records) {
319874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            this.callEvents = records;
320874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        }
321874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
322874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        @Override
3234640c4fc55ca4118351330d68684ca9989661ccdHall Liu        public void setCallIsVideo(boolean isVideo) {
3244640c4fc55ca4118351330d68684ca9989661ccdHall Liu            this.isVideo = isVideo;
3254640c4fc55ca4118351330d68684ca9989661ccdHall Liu        }
3264640c4fc55ca4118351330d68684ca9989661ccdHall Liu
3274640c4fc55ca4118351330d68684ca9989661ccdHall Liu        @Override
3284640c4fc55ca4118351330d68684ca9989661ccdHall Liu        public void addVideoEvent(int eventId, int videoState) {
3294640c4fc55ca4118351330d68684ca9989661ccdHall Liu            long timeSinceLastEvent;
3304640c4fc55ca4118351330d68684ca9989661ccdHall Liu            long currentTime = System.currentTimeMillis();
3314640c4fc55ca4118351330d68684ca9989661ccdHall Liu            if (mTimeOfLastVideoEvent < 0) {
3324640c4fc55ca4118351330d68684ca9989661ccdHall Liu                timeSinceLastEvent = -1;
3334640c4fc55ca4118351330d68684ca9989661ccdHall Liu            } else {
3344640c4fc55ca4118351330d68684ca9989661ccdHall Liu                timeSinceLastEvent = roundToOneSigFig(currentTime - mTimeOfLastVideoEvent);
3354640c4fc55ca4118351330d68684ca9989661ccdHall Liu            }
3364640c4fc55ca4118351330d68684ca9989661ccdHall Liu            mTimeOfLastVideoEvent = currentTime;
3374640c4fc55ca4118351330d68684ca9989661ccdHall Liu
3382f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            videoEvents.add(new TelecomLogClass.VideoEvent()
3392f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setEventName(eventId)
3402f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setTimeSinceLastEventMillis(timeSinceLastEvent)
3412f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setVideoState(videoState));
3424640c4fc55ca4118351330d68684ca9989661ccdHall Liu        }
3434640c4fc55ca4118351330d68684ca9989661ccdHall Liu
3444640c4fc55ca4118351330d68684ca9989661ccdHall Liu        @Override
3459d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        public void addInCallService(String serviceName, int type) {
3469d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            inCallServiceInfos.add(new TelecomLogClass.InCallServiceInfo()
3479d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                    .setInCallServiceName(serviceName)
3489d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                    .setInCallServiceType(type));
3499d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        }
3509d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu
3519d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        @Override
352d7fe686253f2135a948cafc776aa25db645ec27eHall Liu        public void addCallProperties(int properties) {
353d7fe686253f2135a948cafc776aa25db645ec27eHall Liu            this.callProperties |= properties;
354d7fe686253f2135a948cafc776aa25db645ec27eHall Liu        }
355d7fe686253f2135a948cafc776aa25db645ec27eHall Liu
356d7fe686253f2135a948cafc776aa25db645ec27eHall Liu        @Override
3573258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        public String toString() {
3583258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            return "{\n"
3593258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    startTime: " + startTime + '\n'
3603258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    endTime: " + endTime + '\n'
3613258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    direction: " + getCallDirectionString() + '\n'
3623258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    isAdditionalCall: " + isAdditionalCall + '\n'
3633258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    isInterrupted: " + isInterrupted + '\n'
3643258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    callTechnologies: " + getCallTechnologiesAsString() + '\n'
3653258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "    callTerminationReason: " + getCallDisconnectReasonString() + '\n'
366ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu                    + "    connectionService: " + connectionService + '\n'
3674640c4fc55ca4118351330d68684ca9989661ccdHall Liu                    + "    isVideoCall: " + isVideo + '\n'
3689d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                    + "    inCallServices: " + getInCallServicesString() + '\n'
369d7fe686253f2135a948cafc776aa25db645ec27eHall Liu                    + "    callProperties: " + Connection.propertiesToStringShort(callProperties)
370d7fe686253f2135a948cafc776aa25db645ec27eHall Liu                    + '\n'
3713258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    + "}\n";
3723258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
3733258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
374ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu        public ParcelableCallAnalytics toParcelableAnalytics() {
3752f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            TelecomLogClass.CallLog analyticsProto = toProto();
3762f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            List<ParcelableCallAnalytics.AnalyticsEvent> events =
3772f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    Arrays.stream(analyticsProto.callEvents)
3782f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .map(callEventProto -> new ParcelableCallAnalytics.AnalyticsEvent(
3792f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                                callEventProto.getEventName(),
3802f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                                callEventProto.getTimeSinceLastEventMillis())
3812f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    ).collect(Collectors.toList());
3822f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
3832f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            List<ParcelableCallAnalytics.EventTiming> timings =
3842f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    Arrays.stream(analyticsProto.callTimings)
3852f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .map(callTimingProto -> new ParcelableCallAnalytics.EventTiming(
3862f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            callTimingProto.getTimingName(),
3872f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            callTimingProto.getTimeMillis())
3882f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    ).collect(Collectors.toList());
3892f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
3902f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            ParcelableCallAnalytics result = new ParcelableCallAnalytics(
3912f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    // rounds down to nearest 5 minute mark
3922f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getStartTime5Min(),
3932f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getCallDurationMillis(),
3942f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getType(),
3952f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getIsAdditionalCall(),
3962f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getIsInterrupted(),
3972f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getCallTechnologies(),
3982f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getCallTerminationCode(),
3992f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getIsEmergencyCall(),
4002f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.connectionService[0],
4012f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    analyticsProto.getIsCreatedFromExistingConnection(),
4022f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    events,
4032f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    timings);
4042f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
4052f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.setIsVideoCall(analyticsProto.getIsVideoCall());
4062f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.setVideoEvents(Arrays.stream(analyticsProto.videoEvents)
4072f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .map(videoEventProto -> new ParcelableCallAnalytics.VideoEvent(
4082f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            videoEventProto.getEventName(),
4092f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            videoEventProto.getTimeSinceLastEventMillis(),
4102f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            videoEventProto.getVideoState())
4112f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    ).collect(Collectors.toList()));
4122f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
4132f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            return result;
4142f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        }
4152f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
4162f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        public TelecomLogClass.CallLog toProto() {
4172f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            TelecomLogClass.CallLog result = new TelecomLogClass.CallLog();
4182f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.setStartTime5Min(
4192f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    startTime - startTime % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
4202f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
421ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu            // Rounds up to the nearest second.
4220bd869ca557dc11950be3e967e7bcc3abf0ca729Hall Liu            long callDuration = (endTime == 0 || startTime == 0) ? 0 : endTime - startTime;
423ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu            callDuration += (callDuration % MILLIS_IN_1_SECOND == 0) ?
424ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu                    0 : (MILLIS_IN_1_SECOND - callDuration % MILLIS_IN_1_SECOND);
4252f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.setCallDurationMillis(callDuration);
4262f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
4272f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.setType(callDirection)
4282f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setIsAdditionalCall(isAdditionalCall)
4292f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setIsInterrupted(isInterrupted)
4302f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setCallTechnologies(callTechnologies)
4312f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setCallTerminationCode(
4322f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            callTerminationReason == null ?
4332f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                                    ParcelableCallAnalytics.STILL_CONNECTED :
4342f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                                    callTerminationReason.getCode())
4352f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setIsEmergencyCall(isEmergency)
4362f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setIsCreatedFromExistingConnection(createdFromExistingConnection)
4372f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .setIsEmergencyCall(isEmergency)
438d7fe686253f2135a948cafc776aa25db645ec27eHall Liu                    .setIsVideoCall(isVideo)
439d7fe686253f2135a948cafc776aa25db645ec27eHall Liu                    .setConnectionProperties(callProperties);
4402f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
4412f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.connectionService = new String[] {connectionService};
442874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            if (callEvents != null) {
4432f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                result.callEvents = convertLogEventsToProtoEvents(callEvents.getEvents());
4442f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                result.callTimings = callEvents.extractEventTimings().stream()
4452f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                        .map(Analytics::logEventTimingToProtoEventTiming)
4462f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                        .toArray(TelecomLogClass.EventTimingEntry[]::new);
447874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            }
4482f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.videoEvents =
4492f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    videoEvents.toArray(new TelecomLogClass.VideoEvent[videoEvents.size()]);
4509d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            result.inCallServices = inCallServiceInfos.toArray(
4519d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                    new TelecomLogClass.InCallServiceInfo[inCallServiceInfos.size()]);
4529d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu
4534640c4fc55ca4118351330d68684ca9989661ccdHall Liu            return result;
454ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu        }
455ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu
4563258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        private String getCallDirectionString() {
4573258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            switch (callDirection) {
4583258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                case UNKNOWN_DIRECTION:
4593258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    return "UNKNOWN";
4603258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                case INCOMING_DIRECTION:
4613258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    return "INCOMING";
4623258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                case OUTGOING_DIRECTION:
4633258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    return "OUTGOING";
4643258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                default:
4653258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                    return "UNKNOWN";
4663258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            }
4673258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
4683258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
4693258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        private String getCallTechnologiesAsString() {
4703258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            StringBuilder s = new StringBuilder();
4713258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            s.append('[');
4723258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if ((callTechnologies & CDMA_PHONE) != 0) s.append("CDMA ");
4733258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if ((callTechnologies & GSM_PHONE) != 0) s.append("GSM ");
4743258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if ((callTechnologies & SIP_PHONE) != 0) s.append("SIP ");
4753258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if ((callTechnologies & IMS_PHONE) != 0) s.append("IMS ");
4763258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if ((callTechnologies & THIRD_PARTY_PHONE) != 0) s.append("THIRD_PARTY ");
4773258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            s.append(']');
4783258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            return s.toString();
4793258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
4803258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
4813258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        private String getCallDisconnectReasonString() {
4823258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            if (callTerminationReason != null) {
4833258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                return callTerminationReason.toString();
4843258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            } else {
4853258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                return "NOT SET";
4863258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            }
4873258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
4889d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu
4899d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        private String getInCallServicesString() {
4909d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            StringBuilder s = new StringBuilder();
4919d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            s.append("[\n");
4929d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            for (TelecomLogClass.InCallServiceInfo service : inCallServiceInfos) {
4939d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                s.append("    ");
4949d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                s.append("name: ");
4959d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                s.append(service.getInCallServiceName());
4969d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                s.append(" type: ");
4979d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                s.append(service.getInCallServiceType());
4989d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu                s.append("\n");
4999d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            }
5009d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            s.append("]");
5019d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu            return s.toString();
5029d15ca4316bb3a89bba11b62d2e17e2fb80fdc74Hall Liu        }
5033258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    }
5043258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    public static final String TAG = "TelecomAnalytics";
5053258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
5063258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    // Constants for call direction
507ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int UNKNOWN_DIRECTION = ParcelableCallAnalytics.CALLTYPE_UNKNOWN;
508ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int INCOMING_DIRECTION = ParcelableCallAnalytics.CALLTYPE_INCOMING;
509ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int OUTGOING_DIRECTION = ParcelableCallAnalytics.CALLTYPE_OUTGOING;
5103258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
5113258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    // Constants for call technology
512ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int CDMA_PHONE = ParcelableCallAnalytics.CDMA_PHONE;
513ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int GSM_PHONE = ParcelableCallAnalytics.GSM_PHONE;
514ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int IMS_PHONE = ParcelableCallAnalytics.IMS_PHONE;
515ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int SIP_PHONE = ParcelableCallAnalytics.SIP_PHONE;
516ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final int THIRD_PARTY_PHONE = ParcelableCallAnalytics.THIRD_PARTY_PHONE;
517ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu
5184640c4fc55ca4118351330d68684ca9989661ccdHall Liu    // Constants for video events
5194640c4fc55ca4118351330d68684ca9989661ccdHall Liu    public static final int SEND_LOCAL_SESSION_MODIFY_REQUEST =
5204640c4fc55ca4118351330d68684ca9989661ccdHall Liu            ParcelableCallAnalytics.VideoEvent.SEND_LOCAL_SESSION_MODIFY_REQUEST;
5214640c4fc55ca4118351330d68684ca9989661ccdHall Liu    public static final int SEND_LOCAL_SESSION_MODIFY_RESPONSE =
5224640c4fc55ca4118351330d68684ca9989661ccdHall Liu            ParcelableCallAnalytics.VideoEvent.SEND_LOCAL_SESSION_MODIFY_RESPONSE;
5234640c4fc55ca4118351330d68684ca9989661ccdHall Liu    public static final int RECEIVE_REMOTE_SESSION_MODIFY_REQUEST =
5244640c4fc55ca4118351330d68684ca9989661ccdHall Liu            ParcelableCallAnalytics.VideoEvent.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST;
5254640c4fc55ca4118351330d68684ca9989661ccdHall Liu    public static final int RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE =
5264640c4fc55ca4118351330d68684ca9989661ccdHall Liu            ParcelableCallAnalytics.VideoEvent.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE;
5274640c4fc55ca4118351330d68684ca9989661ccdHall Liu
528ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    public static final long MILLIS_IN_1_SECOND = ParcelableCallAnalytics.MILLIS_IN_1_SECOND;
5293258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
530d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu    public static final int MAX_NUM_CALLS_TO_STORE = 100;
531d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu
5323258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    private static final Object sLock = new Object(); // Coarse lock for all of analytics
5333258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    private static final Map<String, CallInfoImpl> sCallIdToInfo = new HashMap<>();
534d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu    private static final LinkedList<String> sActiveCallIds = new LinkedList<>();
535874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    private static final List<SessionTiming> sSessionTimings = new LinkedList<>();
536874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
537874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static void addSessionTiming(String sessionName, long time) {
538874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        if (sLogSessionToSessionId.containsKey(sessionName)) {
539874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            synchronized (sLock) {
540874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                sSessionTimings.add(new SessionTiming(sLogSessionToSessionId.get(sessionName),
541874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        time));
542874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            }
543874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        }
544874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    }
5453258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
5463258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    public static CallInfo initiateCallAnalytics(String callId, int direction) {
5473258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        Log.d(TAG, "Starting analytics for call " + callId);
5483258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        CallInfoImpl callInfo = new CallInfoImpl(callId, direction);
5493258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        synchronized (sLock) {
550d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu            while (sActiveCallIds.size() >= MAX_NUM_CALLS_TO_STORE) {
551d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu                String callToRemove = sActiveCallIds.remove();
552d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu                sCallIdToInfo.remove(callToRemove);
553d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu            }
5543258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            sCallIdToInfo.put(callId, callInfo);
555d93b9ececca0fb8a2cc63858ce59012eb6fc17e9Hall Liu            sActiveCallIds.add(callId);
5563258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
5573258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        return callInfo;
5583258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    }
5593258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
560874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static TelecomAnalytics dumpToParcelableAnalytics() {
561874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        List<ParcelableCallAnalytics> calls = new LinkedList<>();
562874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        List<SessionTiming> sessionTimings = new LinkedList<>();
563ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu        synchronized (sLock) {
564874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            calls.addAll(sCallIdToInfo.values().stream()
565874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                    .map(CallInfoImpl::toParcelableAnalytics)
566874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                    .collect(Collectors.toList()));
567874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            sessionTimings.addAll(sSessionTimings);
568ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu            sCallIdToInfo.clear();
569874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            sSessionTimings.clear();
570ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu        }
571874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        return new TelecomAnalytics(sessionTimings, calls);
572ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu    }
573ecd74a56dbce2d15ff46ad3e64a16dfe8b6c734fHall Liu
5742f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu    public static void dumpToEncodedProto(PrintWriter pw, String[] args) {
5752f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        TelecomLogClass.TelecomLog result = new TelecomLogClass.TelecomLog();
5762f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
5772f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        synchronized (sLock) {
5782f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.callLogs = sCallIdToInfo.values().stream()
5792f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .map(CallInfoImpl::toProto)
5802f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .toArray(TelecomLogClass.CallLog[]::new);
5812f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            result.sessionTimings = sSessionTimings.stream()
5822f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .map(timing -> new TelecomLogClass.LogSessionTiming()
5832f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            .setSessionEntryPoint(timing.getKey())
5842f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                            .setTimeMillis(timing.getTime()))
5852f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                    .toArray(TelecomLogClass.LogSessionTiming[]::new);
5862f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            if (args.length > 1 && CLEAR_ANALYTICS_ARG.equals(args[1])) {
5872f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                sCallIdToInfo.clear();
5882f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                sSessionTimings.clear();
5892f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu            }
5902f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        }
5912f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        String encodedProto = Base64.encodeToString(
5922f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                TelecomLogClass.TelecomLog.toByteArray(result), Base64.DEFAULT);
5932f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        pw.write(encodedProto);
5942f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu    }
5952f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu
5963258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    public static void dump(IndentingPrintWriter writer) {
5973258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        synchronized (sLock) {
598874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            int prefixLength = CallsManager.TELECOM_CALL_ID_PREFIX.length();
599874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            List<String> callIds = new ArrayList<>(sCallIdToInfo.keySet());
600874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            // Sort the analytics in increasing order of call IDs
601d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu            try {
602d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                Collections.sort(callIds, (id1, id2) -> {
603d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    int i1, i2;
604d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    try {
605d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                        i1 = Integer.valueOf(id1.substring(prefixLength));
606d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    } catch (NumberFormatException e) {
607d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                        i1 = Integer.MAX_VALUE;
608d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    }
609d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu
610d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    try {
611d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                        i2 = Integer.valueOf(id2.substring(prefixLength));
612d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    } catch (NumberFormatException e) {
613d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                        i2 = Integer.MAX_VALUE;
614d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    }
615d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                    return i1 - i2;
616d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                });
617d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu            } catch (IllegalArgumentException e) {
618d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu                // do nothing, leave the list in a partially sorted state.
619d7e370d9a0b5fa4b99e8a832ba0b690f0f8fb4beHall Liu            }
620874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
621874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            for (String callId : callIds) {
622874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                writer.printf("Call %s: ", callId);
623874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                writer.println(sCallIdToInfo.get(callId).toString());
6243258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            }
625874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
626874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            Map<Integer, Double> averageTimings = SessionTiming.averageTimings(sSessionTimings);
627874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            averageTimings.entrySet().stream()
628874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                    .filter(e -> sSessionIdToLogSession.containsKey(e.getKey()))
629874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                    .forEach(e -> writer.printf("%s: %.2f\n",
630874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                            sSessionIdToLogSession.get(e.getKey()), e.getValue()));
6313258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
6323258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    }
6333258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
6343258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    public static void reset() {
6353258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        synchronized (sLock) {
6363258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            sCallIdToInfo.clear();
6373258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
6383258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    }
6393258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu
6403258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    /**
641874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu     * Returns a copy of callIdToInfo. Use only for testing.
6423258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu     */
643874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    @VisibleForTesting
6443258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    public static Map<String, CallInfoImpl> cloneData() {
6453258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        synchronized (sLock) {
6463258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            Map<String, CallInfoImpl> result = new HashMap<>(sCallIdToInfo.size());
6473258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            for (Map.Entry<String, CallInfoImpl> entry : sCallIdToInfo.entrySet()) {
6483258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu                result.put(entry.getKey(), new CallInfoImpl(entry.getValue()));
6493258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            }
6503258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu            return result;
6513258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu        }
6523258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu    }
653874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
6542f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu    private static TelecomLogClass.Event[] convertLogEventsToProtoEvents(
655a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger            List<EventManager.Event> logEvents) {
656874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        long timeOfLastEvent = -1;
6572f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        ArrayList<TelecomLogClass.Event> events = new ArrayList<>(logEvents.size());
658a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger        for (EventManager.Event logEvent : logEvents) {
659874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            if (sLogEventToAnalyticsEvent.containsKey(logEvent.eventId)) {
6602f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                TelecomLogClass.Event event = new TelecomLogClass.Event();
6612f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                event.setEventName(sLogEventToAnalyticsEvent.get(logEvent.eventId));
6622f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                event.setTimeSinceLastEventMillis(roundToOneSigFig(
6632f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                        timeOfLastEvent < 0 ? -1 : logEvent.time - timeOfLastEvent));
6642f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                events.add(event);
665874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                timeOfLastEvent = logEvent.time;
666874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            }
667874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        }
6682f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        return events.toArray(new TelecomLogClass.Event[events.size()]);
669874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    }
670874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
6712f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu    private static TelecomLogClass.EventTimingEntry logEventTimingToProtoEventTiming(
672a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebinger            EventManager.EventRecord.EventTiming logEventTiming) {
673874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        int analyticsEventTimingName =
674874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                sLogEventTimingToAnalyticsEventTiming.containsKey(logEventTiming.name) ?
675874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        sLogEventTimingToAnalyticsEventTiming.get(logEventTiming.name) :
676874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu                        ParcelableCallAnalytics.EventTiming.INVALID;
6772f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu        return new TelecomLogClass.EventTimingEntry()
6782f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                .setTimingName(analyticsEventTimingName)
6792f4f0a038dbf9f6372ac8c9b1535f8cc8d0f8256Hall Liu                .setTimeMillis(logEventTiming.time);
680874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    }
681874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu
682874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    @VisibleForTesting
683874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    public static long roundToOneSigFig(long val)  {
684874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        if (val == 0) {
685874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu            return val;
686874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        }
687874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        int logVal = (int) Math.floor(Math.log10(val < 0 ? -val : val));
688874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        double s = Math.pow(10, logVal);
689874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        double dec =  val / s;
690874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu        return (long) (Math.round(dec) * s);
691874c0f8fa95a5da5a82e67c1fe39697883d753ebHall Liu    }
6923258720f5526f766aa26c19cf01b32ac20d19d1dHall Liu}
693