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