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
17package android.telecom;
18
19import android.annotation.SystemApi;
20import android.os.Parcel;
21import android.os.Parcelable;
22
23import java.util.ArrayList;
24import java.util.LinkedList;
25import java.util.List;
26
27/**
28 * @hide
29 */
30@SystemApi
31public 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 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
57        public VideoEvent(int eventName, long timeSinceLastEvent, int videoState) {
58            mEventName = eventName;
59            mTimeSinceLastEvent = timeSinceLastEvent;
60            mVideoState = videoState;
61        }
62
63        VideoEvent(Parcel in) {
64            mEventName = in.readInt();
65            mTimeSinceLastEvent = in.readLong();
66            mVideoState = in.readInt();
67        }
68
69        public int getEventName() {
70            return mEventName;
71        }
72
73        public long getTimeSinceLastEvent() {
74            return mTimeSinceLastEvent;
75        }
76
77        public int getVideoState() {
78            return mVideoState;
79        }
80
81        @Override
82        public int describeContents() {
83            return 0;
84        }
85
86        @Override
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
115        public static final int SKIP_RINGING = 200;
116        public static final int SILENCE = 201;
117        public static final int MUTE = 202;
118        public static final int UNMUTE = 203;
119        public static final int AUDIO_ROUTE_BT = 204;
120        public static final int AUDIO_ROUTE_EARPIECE = 205;
121        public static final int AUDIO_ROUTE_HEADSET = 206;
122        public static final int AUDIO_ROUTE_SPEAKER = 207;
123
124        public static final int CONFERENCE_WITH = 300;
125        public static final int SPLIT_CONFERENCE = 301;
126        public static final int SET_PARENT = 302;
127
128        public static final int REQUEST_HOLD = 400;
129        public static final int REQUEST_UNHOLD = 401;
130        public static final int REMOTELY_HELD = 402;
131        public static final int REMOTELY_UNHELD = 403;
132        public static final int SET_HOLD = 404;
133        public static final int SWAP = 405;
134
135        public static final int REQUEST_PULL = 500;
136
137
138        public static final Parcelable.Creator<AnalyticsEvent> CREATOR =
139                new Parcelable.Creator<AnalyticsEvent> () {
140
141                    @Override
142                    public AnalyticsEvent createFromParcel(Parcel in) {
143                        return new AnalyticsEvent(in);
144                    }
145
146                    @Override
147                    public AnalyticsEvent[] newArray(int size) {
148                        return new AnalyticsEvent[size];
149                    }
150                };
151
152        private int mEventName;
153        private long mTimeSinceLastEvent;
154
155        public AnalyticsEvent(int eventName, long timestamp) {
156            mEventName = eventName;
157            mTimeSinceLastEvent = timestamp;
158        }
159
160        AnalyticsEvent(Parcel in) {
161            mEventName = in.readInt();
162            mTimeSinceLastEvent = in.readLong();
163        }
164
165        public int getEventName() {
166            return mEventName;
167        }
168
169        public long getTimeSinceLastEvent() {
170            return mTimeSinceLastEvent;
171        }
172
173        @Override
174        public int describeContents() {
175            return 0;
176        }
177
178        @Override
179        public void writeToParcel(Parcel out, int flags) {
180            out.writeInt(mEventName);
181            out.writeLong(mTimeSinceLastEvent);
182        }
183    }
184
185    public static final class EventTiming implements Parcelable {
186        public static final int ACCEPT_TIMING = 0;
187        public static final int REJECT_TIMING = 1;
188        public static final int DISCONNECT_TIMING = 2;
189        public static final int HOLD_TIMING = 3;
190        public static final int UNHOLD_TIMING = 4;
191        public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5;
192        public static final int BIND_CS_TIMING = 6;
193        public static final int SCREENING_COMPLETED_TIMING = 7;
194        public static final int DIRECT_TO_VM_FINISHED_TIMING = 8;
195        public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
196        public static final int FILTERING_COMPLETED_TIMING = 10;
197        public static final int FILTERING_TIMED_OUT_TIMING = 11;
198
199        public static final int INVALID = 999999;
200
201        public static final Parcelable.Creator<EventTiming> CREATOR =
202                new Parcelable.Creator<EventTiming> () {
203
204                    @Override
205                    public EventTiming createFromParcel(Parcel in) {
206                        return new EventTiming(in);
207                    }
208
209                    @Override
210                    public EventTiming[] newArray(int size) {
211                        return new EventTiming[size];
212                    }
213                };
214
215        private int mName;
216        private long mTime;
217
218        public EventTiming(int name, long time) {
219            this.mName = name;
220            this.mTime = time;
221        }
222
223        private EventTiming(Parcel in) {
224            mName = in.readInt();
225            mTime = in.readLong();
226        }
227
228        public int getName() {
229            return mName;
230        }
231
232        public long getTime() {
233            return mTime;
234        }
235
236        @Override
237        public int describeContents() {
238            return 0;
239        }
240
241        @Override
242        public void writeToParcel(Parcel out, int flags) {
243            out.writeInt(mName);
244            out.writeLong(mTime);
245        }
246    }
247
248    public static final int CALLTYPE_UNKNOWN = 0;
249    public static final int CALLTYPE_INCOMING = 1;
250    public static final int CALLTYPE_OUTGOING = 2;
251
252    // Constants for call technology
253    public static final int CDMA_PHONE = 0x1;
254    public static final int GSM_PHONE = 0x2;
255    public static final int IMS_PHONE = 0x4;
256    public static final int SIP_PHONE = 0x8;
257    public static final int THIRD_PARTY_PHONE = 0x10;
258
259    public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
260    public static final long MILLIS_IN_1_SECOND = 1000;
261
262    public static final int STILL_CONNECTED = -1;
263
264    public static final Parcelable.Creator<ParcelableCallAnalytics> CREATOR =
265            new Parcelable.Creator<ParcelableCallAnalytics> () {
266
267                @Override
268                public ParcelableCallAnalytics createFromParcel(Parcel in) {
269                    return new ParcelableCallAnalytics(in);
270                }
271
272                @Override
273                public ParcelableCallAnalytics[] newArray(int size) {
274                    return new ParcelableCallAnalytics[size];
275                }
276            };
277
278    // The start time of the call in milliseconds since Jan. 1, 1970, rounded to the nearest
279    // 5 minute increment.
280    private final long startTimeMillis;
281
282    // The duration of the call, in milliseconds.
283    private final long callDurationMillis;
284
285    // ONE OF calltype_unknown, calltype_incoming, or calltype_outgoing
286    private final int callType;
287
288    // true if the call came in while another call was in progress or if the user dialed this call
289    // while in the middle of another call.
290    private final boolean isAdditionalCall;
291
292    // true if the call was interrupted by an incoming or outgoing call.
293    private final boolean isInterrupted;
294
295    // bitmask denoting which technologies a call used.
296    private final int callTechnologies;
297
298    // Any of the DisconnectCause codes, or STILL_CONNECTED.
299    private final int callTerminationCode;
300
301    // Whether the call is an emergency call
302    private final boolean isEmergencyCall;
303
304    // The package name of the connection service that this call used.
305    private final String connectionService;
306
307    // Whether the call object was created from an existing connection.
308    private final boolean isCreatedFromExistingConnection;
309
310    // A list of events that are associated with this call
311    private final List<AnalyticsEvent> analyticsEvents;
312
313    // A map from event-pair names to their durations.
314    private final List<EventTiming> eventTimings;
315
316    // Whether the call has ever been a video call.
317    private boolean isVideoCall = false;
318
319    // A list of video events that have occurred.
320    private List<VideoEvent> videoEvents;
321
322    public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
323            boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
324            int callTerminationCode, boolean isEmergencyCall, String connectionService,
325            boolean isCreatedFromExistingConnection, List<AnalyticsEvent> analyticsEvents,
326            List<EventTiming> eventTimings) {
327        this.startTimeMillis = startTimeMillis;
328        this.callDurationMillis = callDurationMillis;
329        this.callType = callType;
330        this.isAdditionalCall = isAdditionalCall;
331        this.isInterrupted = isInterrupted;
332        this.callTechnologies = callTechnologies;
333        this.callTerminationCode = callTerminationCode;
334        this.isEmergencyCall = isEmergencyCall;
335        this.connectionService = connectionService;
336        this.isCreatedFromExistingConnection = isCreatedFromExistingConnection;
337        this.analyticsEvents = analyticsEvents;
338        this.eventTimings = eventTimings;
339    }
340
341    public ParcelableCallAnalytics(Parcel in) {
342        startTimeMillis = in.readLong();
343        callDurationMillis = in.readLong();
344        callType = in.readInt();
345        isAdditionalCall = readByteAsBoolean(in);
346        isInterrupted = readByteAsBoolean(in);
347        callTechnologies = in.readInt();
348        callTerminationCode = in.readInt();
349        isEmergencyCall = readByteAsBoolean(in);
350        connectionService = in.readString();
351        isCreatedFromExistingConnection = readByteAsBoolean(in);
352        analyticsEvents = new ArrayList<>();
353        in.readTypedList(analyticsEvents, AnalyticsEvent.CREATOR);
354        eventTimings = new ArrayList<>();
355        in.readTypedList(eventTimings, EventTiming.CREATOR);
356        isVideoCall = readByteAsBoolean(in);
357        videoEvents = new LinkedList<>();
358        in.readTypedList(videoEvents, VideoEvent.CREATOR);
359    }
360
361    public void writeToParcel(Parcel out, int flags) {
362        out.writeLong(startTimeMillis);
363        out.writeLong(callDurationMillis);
364        out.writeInt(callType);
365        writeBooleanAsByte(out, isAdditionalCall);
366        writeBooleanAsByte(out, isInterrupted);
367        out.writeInt(callTechnologies);
368        out.writeInt(callTerminationCode);
369        writeBooleanAsByte(out, isEmergencyCall);
370        out.writeString(connectionService);
371        writeBooleanAsByte(out, isCreatedFromExistingConnection);
372        out.writeTypedList(analyticsEvents);
373        out.writeTypedList(eventTimings);
374        writeBooleanAsByte(out, isVideoCall);
375        out.writeTypedList(videoEvents);
376    }
377
378    /** {@hide} */
379    public void setIsVideoCall(boolean isVideoCall) {
380        this.isVideoCall = isVideoCall;
381    }
382
383    /** {@hide} */
384    public void setVideoEvents(List<VideoEvent> videoEvents) {
385        this.videoEvents = videoEvents;
386    }
387
388    public long getStartTimeMillis() {
389        return startTimeMillis;
390    }
391
392    public long getCallDurationMillis() {
393        return callDurationMillis;
394    }
395
396    public int getCallType() {
397        return callType;
398    }
399
400    public boolean isAdditionalCall() {
401        return isAdditionalCall;
402    }
403
404    public boolean isInterrupted() {
405        return isInterrupted;
406    }
407
408    public int getCallTechnologies() {
409        return callTechnologies;
410    }
411
412    public int getCallTerminationCode() {
413        return callTerminationCode;
414    }
415
416    public boolean isEmergencyCall() {
417        return isEmergencyCall;
418    }
419
420    public String getConnectionService() {
421        return connectionService;
422    }
423
424    public boolean isCreatedFromExistingConnection() {
425        return isCreatedFromExistingConnection;
426    }
427
428    public List<AnalyticsEvent> analyticsEvents() {
429        return analyticsEvents;
430    }
431
432    public List<EventTiming> getEventTimings() {
433        return eventTimings;
434    }
435
436    /** {@hide} */
437    public boolean isVideoCall() {
438        return isVideoCall;
439    }
440
441    /** {@hide} */
442    public List<VideoEvent> getVideoEvents() {
443        return videoEvents;
444    }
445
446    @Override
447    public int describeContents() {
448        return 0;
449    }
450
451    private static void writeBooleanAsByte(Parcel out, boolean b) {
452        out.writeByte((byte) (b ? 1 : 0));
453    }
454
455    private static boolean readByteAsBoolean(Parcel in) {
456        return (in.readByte() == 1);
457    }
458}
459