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 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 @android.annotation.NonNull 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 AnalyticsEvent(int eventName, long timestamp)155 public AnalyticsEvent(int eventName, long timestamp) { 156 mEventName = eventName; 157 mTimeSinceLastEvent = timestamp; 158 } 159 AnalyticsEvent(Parcel in)160 AnalyticsEvent(Parcel in) { 161 mEventName = in.readInt(); 162 mTimeSinceLastEvent = in.readLong(); 163 } 164 getEventName()165 public int getEventName() { 166 return mEventName; 167 } 168 getTimeSinceLastEvent()169 public long getTimeSinceLastEvent() { 170 return mTimeSinceLastEvent; 171 } 172 173 @Override describeContents()174 public int describeContents() { 175 return 0; 176 } 177 178 @Override writeToParcel(Parcel out, int flags)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 /** {@hide} */ 199 public static final int START_CONNECTION_TO_REQUEST_DISCONNECT_TIMING = 12; 200 201 public static final int INVALID = 999999; 202 203 public static final @android.annotation.NonNull Parcelable.Creator<EventTiming> CREATOR = 204 new Parcelable.Creator<EventTiming> () { 205 206 @Override 207 public EventTiming createFromParcel(Parcel in) { 208 return new EventTiming(in); 209 } 210 211 @Override 212 public EventTiming[] newArray(int size) { 213 return new EventTiming[size]; 214 } 215 }; 216 217 private int mName; 218 private long mTime; 219 EventTiming(int name, long time)220 public EventTiming(int name, long time) { 221 this.mName = name; 222 this.mTime = time; 223 } 224 EventTiming(Parcel in)225 private EventTiming(Parcel in) { 226 mName = in.readInt(); 227 mTime = in.readLong(); 228 } 229 getName()230 public int getName() { 231 return mName; 232 } 233 getTime()234 public long getTime() { 235 return mTime; 236 } 237 238 @Override describeContents()239 public int describeContents() { 240 return 0; 241 } 242 243 @Override writeToParcel(Parcel out, int flags)244 public void writeToParcel(Parcel out, int flags) { 245 out.writeInt(mName); 246 out.writeLong(mTime); 247 } 248 } 249 250 public static final int CALLTYPE_UNKNOWN = 0; 251 public static final int CALLTYPE_INCOMING = 1; 252 public static final int CALLTYPE_OUTGOING = 2; 253 254 // Constants for call technology 255 public static final int CDMA_PHONE = 0x1; 256 public static final int GSM_PHONE = 0x2; 257 public static final int IMS_PHONE = 0x4; 258 public static final int SIP_PHONE = 0x8; 259 public static final int THIRD_PARTY_PHONE = 0x10; 260 261 /** 262 * Indicating the call source is not specified. 263 * 264 * @hide 265 */ 266 public static final int CALL_SOURCE_UNSPECIFIED = 0; 267 268 /** 269 * Indicating the call is initiated via emergency dialer's dialpad. 270 * 271 * @hide 272 */ 273 public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; 274 275 /** 276 * Indicating the call is initiated via emergency dialer's shortcut button. 277 * 278 * @hide 279 */ 280 public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; 281 282 public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5; 283 public static final long MILLIS_IN_1_SECOND = 1000; 284 285 public static final int STILL_CONNECTED = -1; 286 287 public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCallAnalytics> CREATOR = 288 new Parcelable.Creator<ParcelableCallAnalytics> () { 289 290 @Override 291 public ParcelableCallAnalytics createFromParcel(Parcel in) { 292 return new ParcelableCallAnalytics(in); 293 } 294 295 @Override 296 public ParcelableCallAnalytics[] newArray(int size) { 297 return new ParcelableCallAnalytics[size]; 298 } 299 }; 300 301 // The start time of the call in milliseconds since Jan. 1, 1970, rounded to the nearest 302 // 5 minute increment. 303 private final long startTimeMillis; 304 305 // The duration of the call, in milliseconds. 306 private final long callDurationMillis; 307 308 // ONE OF calltype_unknown, calltype_incoming, or calltype_outgoing 309 private final int callType; 310 311 // true if the call came in while another call was in progress or if the user dialed this call 312 // while in the middle of another call. 313 private final boolean isAdditionalCall; 314 315 // true if the call was interrupted by an incoming or outgoing call. 316 private final boolean isInterrupted; 317 318 // bitmask denoting which technologies a call used. 319 private final int callTechnologies; 320 321 // Any of the DisconnectCause codes, or STILL_CONNECTED. 322 private final int callTerminationCode; 323 324 // Whether the call is an emergency call 325 private final boolean isEmergencyCall; 326 327 // The package name of the connection service that this call used. 328 private final String connectionService; 329 330 // Whether the call object was created from an existing connection. 331 private final boolean isCreatedFromExistingConnection; 332 333 // A list of events that are associated with this call 334 private final List<AnalyticsEvent> analyticsEvents; 335 336 // A map from event-pair names to their durations. 337 private final List<EventTiming> eventTimings; 338 339 // Whether the call has ever been a video call. 340 private boolean isVideoCall = false; 341 342 // A list of video events that have occurred. 343 private List<VideoEvent> videoEvents; 344 345 // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants. 346 private int callSource = CALL_SOURCE_UNSPECIFIED; 347 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)348 public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType, 349 boolean isAdditionalCall, boolean isInterrupted, int callTechnologies, 350 int callTerminationCode, boolean isEmergencyCall, String connectionService, 351 boolean isCreatedFromExistingConnection, List<AnalyticsEvent> analyticsEvents, 352 List<EventTiming> eventTimings) { 353 this.startTimeMillis = startTimeMillis; 354 this.callDurationMillis = callDurationMillis; 355 this.callType = callType; 356 this.isAdditionalCall = isAdditionalCall; 357 this.isInterrupted = isInterrupted; 358 this.callTechnologies = callTechnologies; 359 this.callTerminationCode = callTerminationCode; 360 this.isEmergencyCall = isEmergencyCall; 361 this.connectionService = connectionService; 362 this.isCreatedFromExistingConnection = isCreatedFromExistingConnection; 363 this.analyticsEvents = analyticsEvents; 364 this.eventTimings = eventTimings; 365 } 366 ParcelableCallAnalytics(Parcel in)367 public ParcelableCallAnalytics(Parcel in) { 368 startTimeMillis = in.readLong(); 369 callDurationMillis = in.readLong(); 370 callType = in.readInt(); 371 isAdditionalCall = readByteAsBoolean(in); 372 isInterrupted = readByteAsBoolean(in); 373 callTechnologies = in.readInt(); 374 callTerminationCode = in.readInt(); 375 isEmergencyCall = readByteAsBoolean(in); 376 connectionService = in.readString(); 377 isCreatedFromExistingConnection = readByteAsBoolean(in); 378 analyticsEvents = new ArrayList<>(); 379 in.readTypedList(analyticsEvents, AnalyticsEvent.CREATOR); 380 eventTimings = new ArrayList<>(); 381 in.readTypedList(eventTimings, EventTiming.CREATOR); 382 isVideoCall = readByteAsBoolean(in); 383 videoEvents = new LinkedList<>(); 384 in.readTypedList(videoEvents, VideoEvent.CREATOR); 385 callSource = in.readInt(); 386 } 387 writeToParcel(Parcel out, int flags)388 public void writeToParcel(Parcel out, int flags) { 389 out.writeLong(startTimeMillis); 390 out.writeLong(callDurationMillis); 391 out.writeInt(callType); 392 writeBooleanAsByte(out, isAdditionalCall); 393 writeBooleanAsByte(out, isInterrupted); 394 out.writeInt(callTechnologies); 395 out.writeInt(callTerminationCode); 396 writeBooleanAsByte(out, isEmergencyCall); 397 out.writeString(connectionService); 398 writeBooleanAsByte(out, isCreatedFromExistingConnection); 399 out.writeTypedList(analyticsEvents); 400 out.writeTypedList(eventTimings); 401 writeBooleanAsByte(out, isVideoCall); 402 out.writeTypedList(videoEvents); 403 out.writeInt(callSource); 404 } 405 406 /** {@hide} */ setIsVideoCall(boolean isVideoCall)407 public void setIsVideoCall(boolean isVideoCall) { 408 this.isVideoCall = isVideoCall; 409 } 410 411 /** {@hide} */ setVideoEvents(List<VideoEvent> videoEvents)412 public void setVideoEvents(List<VideoEvent> videoEvents) { 413 this.videoEvents = videoEvents; 414 } 415 416 /** {@hide} */ setCallSource(int callSource)417 public void setCallSource(int callSource) { 418 this.callSource = callSource; 419 } 420 getStartTimeMillis()421 public long getStartTimeMillis() { 422 return startTimeMillis; 423 } 424 getCallDurationMillis()425 public long getCallDurationMillis() { 426 return callDurationMillis; 427 } 428 getCallType()429 public int getCallType() { 430 return callType; 431 } 432 isAdditionalCall()433 public boolean isAdditionalCall() { 434 return isAdditionalCall; 435 } 436 isInterrupted()437 public boolean isInterrupted() { 438 return isInterrupted; 439 } 440 getCallTechnologies()441 public int getCallTechnologies() { 442 return callTechnologies; 443 } 444 getCallTerminationCode()445 public int getCallTerminationCode() { 446 return callTerminationCode; 447 } 448 isEmergencyCall()449 public boolean isEmergencyCall() { 450 return isEmergencyCall; 451 } 452 getConnectionService()453 public String getConnectionService() { 454 return connectionService; 455 } 456 isCreatedFromExistingConnection()457 public boolean isCreatedFromExistingConnection() { 458 return isCreatedFromExistingConnection; 459 } 460 analyticsEvents()461 public List<AnalyticsEvent> analyticsEvents() { 462 return analyticsEvents; 463 } 464 getEventTimings()465 public List<EventTiming> getEventTimings() { 466 return eventTimings; 467 } 468 469 /** {@hide} */ isVideoCall()470 public boolean isVideoCall() { 471 return isVideoCall; 472 } 473 474 /** {@hide} */ getVideoEvents()475 public List<VideoEvent> getVideoEvents() { 476 return videoEvents; 477 } 478 479 /** {@hide} */ getCallSource()480 public int getCallSource() { 481 return callSource; 482 } 483 484 @Override describeContents()485 public int describeContents() { 486 return 0; 487 } 488 writeBooleanAsByte(Parcel out, boolean b)489 private static void writeBooleanAsByte(Parcel out, boolean b) { 490 out.writeByte((byte) (b ? 1 : 0)); 491 } 492 readByteAsBoolean(Parcel in)493 private static boolean readByteAsBoolean(Parcel in) { 494 return (in.readByte() == 1); 495 } 496 } 497