1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.telecom;
18 
19 import android.annotation.SystemApi;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 import java.util.ArrayList;
24 import java.util.LinkedList;
25 import java.util.List;
26 
27 /**
28  * @hide
29  */
30 @SystemApi
31 public class ParcelableCallAnalytics implements Parcelable {
32     /** {@hide} */
33     public static final class VideoEvent implements Parcelable {
34         public static final int SEND_LOCAL_SESSION_MODIFY_REQUEST = 0;
35         public static final int SEND_LOCAL_SESSION_MODIFY_RESPONSE = 1;
36         public static final int RECEIVE_REMOTE_SESSION_MODIFY_REQUEST = 2;
37         public static final int RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE = 3;
38 
39         public static final @android.annotation.NonNull Parcelable.Creator<VideoEvent> CREATOR =
40                 new Parcelable.Creator<VideoEvent> () {
41 
42                     @Override
43                     public VideoEvent createFromParcel(Parcel in) {
44                         return new VideoEvent(in);
45                     }
46 
47                     @Override
48                     public VideoEvent[] newArray(int size) {
49                         return new VideoEvent[size];
50                     }
51                 };
52 
53         private int mEventName;
54         private long mTimeSinceLastEvent;
55         private int mVideoState;
56 
VideoEvent(int eventName, long timeSinceLastEvent, int videoState)57         public VideoEvent(int eventName, long timeSinceLastEvent, int videoState) {
58             mEventName = eventName;
59             mTimeSinceLastEvent = timeSinceLastEvent;
60             mVideoState = videoState;
61         }
62 
VideoEvent(Parcel in)63         VideoEvent(Parcel in) {
64             mEventName = in.readInt();
65             mTimeSinceLastEvent = in.readLong();
66             mVideoState = in.readInt();
67         }
68 
getEventName()69         public int getEventName() {
70             return mEventName;
71         }
72 
getTimeSinceLastEvent()73         public long getTimeSinceLastEvent() {
74             return mTimeSinceLastEvent;
75         }
76 
getVideoState()77         public int getVideoState() {
78             return mVideoState;
79         }
80 
81         @Override
describeContents()82         public int describeContents() {
83             return 0;
84         }
85 
86         @Override
writeToParcel(Parcel out, int flags)87         public void writeToParcel(Parcel out, int flags) {
88             out.writeInt(mEventName);
89             out.writeLong(mTimeSinceLastEvent);
90             out.writeInt(mVideoState);
91         }
92     }
93 
94     public static final class AnalyticsEvent implements Parcelable {
95         public static final int SET_SELECT_PHONE_ACCOUNT = 0;
96         public static final int SET_ACTIVE = 1;
97         public static final int SET_DISCONNECTED = 2;
98         public static final int START_CONNECTION = 3;
99         public static final int SET_DIALING = 4;
100         public static final int BIND_CS = 5;
101         public static final int CS_BOUND = 6;
102         public static final int REQUEST_ACCEPT = 7;
103         public static final int REQUEST_REJECT = 8;
104 
105         public static final int SCREENING_SENT = 100;
106         public static final int SCREENING_COMPLETED = 101;
107         public static final int DIRECT_TO_VM_INITIATED = 102;
108         public static final int DIRECT_TO_VM_FINISHED = 103;
109         public static final int BLOCK_CHECK_INITIATED = 104;
110         public static final int BLOCK_CHECK_FINISHED = 105;
111         public static final int FILTERING_INITIATED = 106;
112         public static final int FILTERING_COMPLETED = 107;
113         public static final int FILTERING_TIMED_OUT = 108;
114         public static final int DND_CHECK_INITIATED = 109;
115         public static final int DND_CHECK_COMPLETED = 110;
116 
117         public static final int SKIP_RINGING = 200;
118         public static final int SILENCE = 201;
119         public static final int MUTE = 202;
120         public static final int UNMUTE = 203;
121         public static final int AUDIO_ROUTE_BT = 204;
122         public static final int AUDIO_ROUTE_EARPIECE = 205;
123         public static final int AUDIO_ROUTE_HEADSET = 206;
124         public static final int AUDIO_ROUTE_SPEAKER = 207;
125 
126         public static final int CONFERENCE_WITH = 300;
127         public static final int SPLIT_CONFERENCE = 301;
128         public static final int SET_PARENT = 302;
129 
130         public static final int REQUEST_HOLD = 400;
131         public static final int REQUEST_UNHOLD = 401;
132         public static final int REMOTELY_HELD = 402;
133         public static final int REMOTELY_UNHELD = 403;
134         public static final int SET_HOLD = 404;
135         public static final int SWAP = 405;
136 
137         public static final int REQUEST_PULL = 500;
138 
139 
140         public static final @android.annotation.NonNull Parcelable.Creator<AnalyticsEvent> CREATOR =
141                 new Parcelable.Creator<AnalyticsEvent> () {
142 
143                     @Override
144                     public AnalyticsEvent createFromParcel(Parcel in) {
145                         return new AnalyticsEvent(in);
146                     }
147 
148                     @Override
149                     public AnalyticsEvent[] newArray(int size) {
150                         return new AnalyticsEvent[size];
151                     }
152                 };
153 
154         private int mEventName;
155         private long mTimeSinceLastEvent;
156 
AnalyticsEvent(int eventName, long timestamp)157         public AnalyticsEvent(int eventName, long timestamp) {
158             mEventName = eventName;
159             mTimeSinceLastEvent = timestamp;
160         }
161 
AnalyticsEvent(Parcel in)162         AnalyticsEvent(Parcel in) {
163             mEventName = in.readInt();
164             mTimeSinceLastEvent = in.readLong();
165         }
166 
getEventName()167         public int getEventName() {
168             return mEventName;
169         }
170 
getTimeSinceLastEvent()171         public long getTimeSinceLastEvent() {
172             return mTimeSinceLastEvent;
173         }
174 
175         @Override
describeContents()176         public int describeContents() {
177             return 0;
178         }
179 
180         @Override
writeToParcel(Parcel out, int flags)181         public void writeToParcel(Parcel out, int flags) {
182             out.writeInt(mEventName);
183             out.writeLong(mTimeSinceLastEvent);
184         }
185     }
186 
187     public static final class EventTiming implements Parcelable {
188         public static final int ACCEPT_TIMING = 0;
189         public static final int REJECT_TIMING = 1;
190         public static final int DISCONNECT_TIMING = 2;
191         public static final int HOLD_TIMING = 3;
192         public static final int UNHOLD_TIMING = 4;
193         public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5;
194         public static final int BIND_CS_TIMING = 6;
195         public static final int SCREENING_COMPLETED_TIMING = 7;
196         public static final int DIRECT_TO_VM_FINISHED_TIMING = 8;
197         public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
198         public static final int FILTERING_COMPLETED_TIMING = 10;
199         public static final int FILTERING_TIMED_OUT_TIMING = 11;
200         public static final int DND_PRE_CALL_PRE_CHECK_TIMING = 12;
201         /** {@hide} */
202         public static final int START_CONNECTION_TO_REQUEST_DISCONNECT_TIMING = 12;
203 
204         public static final int INVALID = 999999;
205 
206         public static final @android.annotation.NonNull Parcelable.Creator<EventTiming> CREATOR =
207                 new Parcelable.Creator<EventTiming> () {
208 
209                     @Override
210                     public EventTiming createFromParcel(Parcel in) {
211                         return new EventTiming(in);
212                     }
213 
214                     @Override
215                     public EventTiming[] newArray(int size) {
216                         return new EventTiming[size];
217                     }
218                 };
219 
220         private int mName;
221         private long mTime;
222 
EventTiming(int name, long time)223         public EventTiming(int name, long time) {
224             this.mName = name;
225             this.mTime = time;
226         }
227 
EventTiming(Parcel in)228         private EventTiming(Parcel in) {
229             mName = in.readInt();
230             mTime = in.readLong();
231         }
232 
getName()233         public int getName() {
234             return mName;
235         }
236 
getTime()237         public long getTime() {
238             return mTime;
239         }
240 
241         @Override
describeContents()242         public int describeContents() {
243             return 0;
244         }
245 
246         @Override
writeToParcel(Parcel out, int flags)247         public void writeToParcel(Parcel out, int flags) {
248             out.writeInt(mName);
249             out.writeLong(mTime);
250         }
251     }
252 
253     public static final int CALLTYPE_UNKNOWN = 0;
254     public static final int CALLTYPE_INCOMING = 1;
255     public static final int CALLTYPE_OUTGOING = 2;
256 
257     // Constants for call technology
258     public static final int CDMA_PHONE = 0x1;
259     public static final int GSM_PHONE = 0x2;
260     public static final int IMS_PHONE = 0x4;
261     public static final int SIP_PHONE = 0x8;
262     public static final int THIRD_PARTY_PHONE = 0x10;
263 
264     public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
265     public static final long MILLIS_IN_1_SECOND = 1000;
266 
267     public static final int STILL_CONNECTED = -1;
268 
269     public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCallAnalytics> CREATOR =
270             new Parcelable.Creator<ParcelableCallAnalytics> () {
271 
272                 @Override
273                 public ParcelableCallAnalytics createFromParcel(Parcel in) {
274                     return new ParcelableCallAnalytics(in);
275                 }
276 
277                 @Override
278                 public ParcelableCallAnalytics[] newArray(int size) {
279                     return new ParcelableCallAnalytics[size];
280                 }
281             };
282 
283     // The start time of the call in milliseconds since Jan. 1, 1970, rounded to the nearest
284     // 5 minute increment.
285     private final long startTimeMillis;
286 
287     // The duration of the call, in milliseconds.
288     private final long callDurationMillis;
289 
290     // ONE OF calltype_unknown, calltype_incoming, or calltype_outgoing
291     private final int callType;
292 
293     // true if the call came in while another call was in progress or if the user dialed this call
294     // while in the middle of another call.
295     private final boolean isAdditionalCall;
296 
297     // true if the call was interrupted by an incoming or outgoing call.
298     private final boolean isInterrupted;
299 
300     // bitmask denoting which technologies a call used.
301     private final int callTechnologies;
302 
303     // Any of the DisconnectCause codes, or STILL_CONNECTED.
304     private final int callTerminationCode;
305 
306     // Whether the call is an emergency call
307     private final boolean isEmergencyCall;
308 
309     // The package name of the connection service that this call used.
310     private final String connectionService;
311 
312     // Whether the call object was created from an existing connection.
313     private final boolean isCreatedFromExistingConnection;
314 
315     // A list of events that are associated with this call
316     private final List<AnalyticsEvent> analyticsEvents;
317 
318     // A map from event-pair names to their durations.
319     private final List<EventTiming> eventTimings;
320 
321     // Whether the call has ever been a video call.
322     private boolean isVideoCall = false;
323 
324     // A list of video events that have occurred.
325     private List<VideoEvent> videoEvents;
326 
327     // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants.
328     private int callSource = TelecomManager.CALL_SOURCE_UNSPECIFIED;
329 
ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType, boolean isAdditionalCall, boolean isInterrupted, int callTechnologies, int callTerminationCode, boolean isEmergencyCall, String connectionService, boolean isCreatedFromExistingConnection, List<AnalyticsEvent> analyticsEvents, List<EventTiming> eventTimings)330     public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
331             boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
332             int callTerminationCode, boolean isEmergencyCall, String connectionService,
333             boolean isCreatedFromExistingConnection, List<AnalyticsEvent> analyticsEvents,
334             List<EventTiming> eventTimings) {
335         this.startTimeMillis = startTimeMillis;
336         this.callDurationMillis = callDurationMillis;
337         this.callType = callType;
338         this.isAdditionalCall = isAdditionalCall;
339         this.isInterrupted = isInterrupted;
340         this.callTechnologies = callTechnologies;
341         this.callTerminationCode = callTerminationCode;
342         this.isEmergencyCall = isEmergencyCall;
343         this.connectionService = connectionService;
344         this.isCreatedFromExistingConnection = isCreatedFromExistingConnection;
345         this.analyticsEvents = analyticsEvents;
346         this.eventTimings = eventTimings;
347     }
348 
ParcelableCallAnalytics(Parcel in)349     public ParcelableCallAnalytics(Parcel in) {
350         startTimeMillis = in.readLong();
351         callDurationMillis = in.readLong();
352         callType = in.readInt();
353         isAdditionalCall = readByteAsBoolean(in);
354         isInterrupted = readByteAsBoolean(in);
355         callTechnologies = in.readInt();
356         callTerminationCode = in.readInt();
357         isEmergencyCall = readByteAsBoolean(in);
358         connectionService = in.readString();
359         isCreatedFromExistingConnection = readByteAsBoolean(in);
360         analyticsEvents = new ArrayList<>();
361         in.readTypedList(analyticsEvents, AnalyticsEvent.CREATOR);
362         eventTimings = new ArrayList<>();
363         in.readTypedList(eventTimings, EventTiming.CREATOR);
364         isVideoCall = readByteAsBoolean(in);
365         videoEvents = new ArrayList<>();
366         in.readTypedList(videoEvents, VideoEvent.CREATOR);
367         callSource = in.readInt();
368     }
369 
writeToParcel(Parcel out, int flags)370     public void writeToParcel(Parcel out, int flags) {
371         out.writeLong(startTimeMillis);
372         out.writeLong(callDurationMillis);
373         out.writeInt(callType);
374         writeBooleanAsByte(out, isAdditionalCall);
375         writeBooleanAsByte(out, isInterrupted);
376         out.writeInt(callTechnologies);
377         out.writeInt(callTerminationCode);
378         writeBooleanAsByte(out, isEmergencyCall);
379         out.writeString(connectionService);
380         writeBooleanAsByte(out, isCreatedFromExistingConnection);
381         out.writeTypedList(analyticsEvents);
382         out.writeTypedList(eventTimings);
383         writeBooleanAsByte(out, isVideoCall);
384         out.writeTypedList(videoEvents);
385         out.writeInt(callSource);
386     }
387 
388     /** {@hide} */
setIsVideoCall(boolean isVideoCall)389     public void setIsVideoCall(boolean isVideoCall) {
390         this.isVideoCall = isVideoCall;
391     }
392 
393     /** {@hide} */
setVideoEvents(List<VideoEvent> videoEvents)394     public void setVideoEvents(List<VideoEvent> videoEvents) {
395         this.videoEvents = videoEvents;
396     }
397 
398     /** {@hide} */
setCallSource(int callSource)399     public void setCallSource(int callSource) {
400         this.callSource = callSource;
401     }
402 
getStartTimeMillis()403     public long getStartTimeMillis() {
404         return startTimeMillis;
405     }
406 
getCallDurationMillis()407     public long getCallDurationMillis() {
408         return callDurationMillis;
409     }
410 
getCallType()411     public int getCallType() {
412         return callType;
413     }
414 
isAdditionalCall()415     public boolean isAdditionalCall() {
416         return isAdditionalCall;
417     }
418 
isInterrupted()419     public boolean isInterrupted() {
420         return isInterrupted;
421     }
422 
getCallTechnologies()423     public int getCallTechnologies() {
424         return callTechnologies;
425     }
426 
getCallTerminationCode()427     public int getCallTerminationCode() {
428         return callTerminationCode;
429     }
430 
isEmergencyCall()431     public boolean isEmergencyCall() {
432         return isEmergencyCall;
433     }
434 
getConnectionService()435     public String getConnectionService() {
436         return connectionService;
437     }
438 
isCreatedFromExistingConnection()439     public boolean isCreatedFromExistingConnection() {
440         return isCreatedFromExistingConnection;
441     }
442 
analyticsEvents()443     public List<AnalyticsEvent> analyticsEvents() {
444         return analyticsEvents;
445     }
446 
getEventTimings()447     public List<EventTiming> getEventTimings() {
448         return eventTimings;
449     }
450 
451     /** {@hide} */
isVideoCall()452     public boolean isVideoCall() {
453         return isVideoCall;
454     }
455 
456     /** {@hide} */
getVideoEvents()457     public List<VideoEvent> getVideoEvents() {
458         return videoEvents;
459     }
460 
461     /** {@hide} */
getCallSource()462     public int getCallSource() {
463         return callSource;
464     }
465 
466     @Override
describeContents()467     public int describeContents() {
468         return 0;
469     }
470 
writeBooleanAsByte(Parcel out, boolean b)471     private static void writeBooleanAsByte(Parcel out, boolean b) {
472         out.writeByte((byte) (b ? 1 : 0));
473     }
474 
readByteAsBoolean(Parcel in)475     private static boolean readByteAsBoolean(Parcel in) {
476         return (in.readByte() == 1);
477     }
478 }
479