Record video call events in analytics

Record whether the call was ever a video call and a list of video
session upgrade/downgrade requests in Analytics.

Bug: 29239768
Change-Id: I50c7a3044f7ad4c13638bb7b493e97f3c1325a18
diff --git a/src/com/android/server/telecom/Analytics.java b/src/com/android/server/telecom/Analytics.java
index 50e7efa..6a22883 100644
--- a/src/com/android/server/telecom/Analytics.java
+++ b/src/com/android/server/telecom/Analytics.java
@@ -19,7 +19,6 @@
 import android.telecom.DisconnectCause;
 import android.telecom.ParcelableCallAnalytics;
 import android.telecom.TelecomAnalytics;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
@@ -165,6 +164,12 @@
 
         public void setCallEvents(Log.CallEventRecord records) {
         }
+
+        public void setCallIsVideo(boolean isVideo) {
+        }
+
+        public void addVideoEvent(int eventId, int videoState) {
+        }
     }
 
     /**
@@ -194,6 +199,10 @@
 
         public Log.CallEventRecord callEvents;
 
+        public boolean isVideo = false;
+        public List<ParcelableCallAnalytics.VideoEvent> videoEvents;
+        private long mTimeOfLastVideoEvent = -1;
+
         CallInfoImpl(String callId, int callDirection) {
             this.callId = callId;
             startTime = 0;
@@ -201,6 +210,7 @@
             this.callDirection = callDirection;
             callTechnologies = 0;
             connectionService = "";
+            videoEvents = new LinkedList<>();
         }
 
         CallInfoImpl(CallInfoImpl other) {
@@ -215,6 +225,8 @@
             this.connectionService = other.connectionService;
             this.isEmergency = other.isEmergency;
             this.callEvents = other.callEvents;
+            this.isVideo = other.isVideo;
+            this.videoEvents = other.videoEvents;
 
             if (other.callTerminationReason != null) {
                 this.callTerminationReason = new DisconnectCause(
@@ -284,6 +296,26 @@
         }
 
         @Override
+        public void setCallIsVideo(boolean isVideo) {
+            this.isVideo = isVideo;
+        }
+
+        @Override
+        public void addVideoEvent(int eventId, int videoState) {
+            long timeSinceLastEvent;
+            long currentTime = System.currentTimeMillis();
+            if (mTimeOfLastVideoEvent < 0) {
+                timeSinceLastEvent = -1;
+            } else {
+                timeSinceLastEvent = roundToOneSigFig(currentTime - mTimeOfLastVideoEvent);
+            }
+            mTimeOfLastVideoEvent = currentTime;
+
+            videoEvents.add(new ParcelableCallAnalytics.VideoEvent(
+                    eventId, timeSinceLastEvent, videoState));
+        }
+
+        @Override
         public String toString() {
             return "{\n"
                     + "    startTime: " + startTime + '\n'
@@ -294,6 +326,7 @@
                     + "    callTechnologies: " + getCallTechnologiesAsString() + '\n'
                     + "    callTerminationReason: " + getCallDisconnectReasonString() + '\n'
                     + "    connectionService: " + connectionService + '\n'
+                    + "    isVideoCall: " + isVideo + '\n'
                     + "}\n";
         }
 
@@ -314,7 +347,7 @@
                 events = Collections.emptyList();
                 timings = Collections.emptyList();
             }
-            return new ParcelableCallAnalytics(
+            ParcelableCallAnalytics result = new ParcelableCallAnalytics(
                     // rounds down to nearest 5 minute mark
                     startTime - startTime % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES,
                     callDuration,
@@ -330,6 +363,9 @@
                     createdFromExistingConnection,
                     events,
                     timings);
+            result.setIsVideoCall(isVideo);
+            result.setVideoEvents(videoEvents);
+            return result;
         }
 
         private String getCallDirectionString() {
@@ -379,6 +415,16 @@
     public static final int SIP_PHONE = ParcelableCallAnalytics.SIP_PHONE;
     public static final int THIRD_PARTY_PHONE = ParcelableCallAnalytics.THIRD_PARTY_PHONE;
 
+    // Constants for video events
+    public static final int SEND_LOCAL_SESSION_MODIFY_REQUEST =
+            ParcelableCallAnalytics.VideoEvent.SEND_LOCAL_SESSION_MODIFY_REQUEST;
+    public static final int SEND_LOCAL_SESSION_MODIFY_RESPONSE =
+            ParcelableCallAnalytics.VideoEvent.SEND_LOCAL_SESSION_MODIFY_RESPONSE;
+    public static final int RECEIVE_REMOTE_SESSION_MODIFY_REQUEST =
+            ParcelableCallAnalytics.VideoEvent.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST;
+    public static final int RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE =
+            ParcelableCallAnalytics.VideoEvent.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE;
+
     public static final long MILLIS_IN_1_SECOND = ParcelableCallAnalytics.MILLIS_IN_1_SECOND;
 
     private static final Object sLock = new Object(); // Coarse lock for all of analytics
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 6bb9bdb..a6d791e 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -1901,6 +1901,10 @@
         for (Listener l : mListeners) {
             l.onVideoStateChanged(this);
         }
+
+        if (VideoProfile.isVideo(videoState)) {
+            mAnalytics.setCallIsVideo(true);
+        }
     }
 
     public boolean getIsVoipAudioMode() {
diff --git a/src/com/android/server/telecom/VideoProviderProxy.java b/src/com/android/server/telecom/VideoProviderProxy.java
index 7569399..c8adc6e 100644
--- a/src/com/android/server/telecom/VideoProviderProxy.java
+++ b/src/com/android/server/telecom/VideoProviderProxy.java
@@ -29,7 +29,6 @@
 import com.android.internal.telecom.IVideoProvider;
 
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -133,6 +132,9 @@
                     Log.event(mCall, Log.Events.RECEIVE_VIDEO_REQUEST,
                             VideoProfile.videoStateToString(videoProfile.getVideoState()));
 
+                    mCall.getAnalytics().addVideoEvent(
+                            Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST,
+                            videoProfile.getVideoState());
                     // Inform other Telecom components of the session modification request.
                     for (Listener listener : mListeners) {
                         listener.onSessionModifyRequestReceived(mCall, videoProfile);
@@ -157,6 +159,9 @@
         public void receiveSessionModifyResponse(int status, VideoProfile requestProfile,
                 VideoProfile responseProfile) {
             synchronized (mLock) {
+                mCall.getAnalytics().addVideoEvent(
+                        Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE,
+                        requestProfile.getVideoState());
                 logFromVideoProvider("receiveSessionModifyResponse: status=" + status +
                         " requestProfile=" + requestProfile + " responseProfile=" +
                         responseProfile);
@@ -343,6 +348,9 @@
             logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
             Log.event(mCall, Log.Events.SEND_VIDEO_REQUEST,
                     VideoProfile.videoStateToString(toProfile.getVideoState()));
+            mCall.getAnalytics().addVideoEvent(
+                    Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST,
+                    toProfile.getVideoState());
             try {
                 mConectionServiceVideoProvider.sendSessionModifyRequest(fromProfile, toProfile);
             } catch (RemoteException e) {
@@ -362,6 +370,9 @@
             logFromInCall("sendSessionModifyResponse: " + responseProfile);
             Log.event(mCall, Log.Events.SEND_VIDEO_RESPONSE,
                     VideoProfile.videoStateToString(responseProfile.getVideoState()));
+            mCall.getAnalytics().addVideoEvent(
+                    Analytics.SEND_LOCAL_SESSION_MODIFY_RESPONSE,
+                    responseProfile.getVideoState());
             try {
                 mConectionServiceVideoProvider.sendSessionModifyResponse(responseProfile);
             } catch (RemoteException e) {