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 public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5; 262 public static final long MILLIS_IN_1_SECOND = 1000; 263 264 public static final int STILL_CONNECTED = -1; 265 266 public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCallAnalytics> CREATOR = 267 new Parcelable.Creator<ParcelableCallAnalytics> () { 268 269 @Override 270 public ParcelableCallAnalytics createFromParcel(Parcel in) { 271 return new ParcelableCallAnalytics(in); 272 } 273 274 @Override 275 public ParcelableCallAnalytics[] newArray(int size) { 276 return new ParcelableCallAnalytics[size]; 277 } 278 }; 279 280 // The start time of the call in milliseconds since Jan. 1, 1970, rounded to the nearest 281 // 5 minute increment. 282 private final long startTimeMillis; 283 284 // The duration of the call, in milliseconds. 285 private final long callDurationMillis; 286 287 // ONE OF calltype_unknown, calltype_incoming, or calltype_outgoing 288 private final int callType; 289 290 // true if the call came in while another call was in progress or if the user dialed this call 291 // while in the middle of another call. 292 private final boolean isAdditionalCall; 293 294 // true if the call was interrupted by an incoming or outgoing call. 295 private final boolean isInterrupted; 296 297 // bitmask denoting which technologies a call used. 298 private final int callTechnologies; 299 300 // Any of the DisconnectCause codes, or STILL_CONNECTED. 301 private final int callTerminationCode; 302 303 // Whether the call is an emergency call 304 private final boolean isEmergencyCall; 305 306 // The package name of the connection service that this call used. 307 private final String connectionService; 308 309 // Whether the call object was created from an existing connection. 310 private final boolean isCreatedFromExistingConnection; 311 312 // A list of events that are associated with this call 313 private final List<AnalyticsEvent> analyticsEvents; 314 315 // A map from event-pair names to their durations. 316 private final List<EventTiming> eventTimings; 317 318 // Whether the call has ever been a video call. 319 private boolean isVideoCall = false; 320 321 // A list of video events that have occurred. 322 private List<VideoEvent> videoEvents; 323 324 // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants. 325 private int callSource = TelecomManager.CALL_SOURCE_UNSPECIFIED; 326 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)327 public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType, 328 boolean isAdditionalCall, boolean isInterrupted, int callTechnologies, 329 int callTerminationCode, boolean isEmergencyCall, String connectionService, 330 boolean isCreatedFromExistingConnection, List<AnalyticsEvent> analyticsEvents, 331 List<EventTiming> eventTimings) { 332 this.startTimeMillis = startTimeMillis; 333 this.callDurationMillis = callDurationMillis; 334 this.callType = callType; 335 this.isAdditionalCall = isAdditionalCall; 336 this.isInterrupted = isInterrupted; 337 this.callTechnologies = callTechnologies; 338 this.callTerminationCode = callTerminationCode; 339 this.isEmergencyCall = isEmergencyCall; 340 this.connectionService = connectionService; 341 this.isCreatedFromExistingConnection = isCreatedFromExistingConnection; 342 this.analyticsEvents = analyticsEvents; 343 this.eventTimings = eventTimings; 344 } 345 ParcelableCallAnalytics(Parcel in)346 public ParcelableCallAnalytics(Parcel in) { 347 startTimeMillis = in.readLong(); 348 callDurationMillis = in.readLong(); 349 callType = in.readInt(); 350 isAdditionalCall = readByteAsBoolean(in); 351 isInterrupted = readByteAsBoolean(in); 352 callTechnologies = in.readInt(); 353 callTerminationCode = in.readInt(); 354 isEmergencyCall = readByteAsBoolean(in); 355 connectionService = in.readString(); 356 isCreatedFromExistingConnection = readByteAsBoolean(in); 357 analyticsEvents = new ArrayList<>(); 358 in.readTypedList(analyticsEvents, AnalyticsEvent.CREATOR); 359 eventTimings = new ArrayList<>(); 360 in.readTypedList(eventTimings, EventTiming.CREATOR); 361 isVideoCall = readByteAsBoolean(in); 362 videoEvents = new LinkedList<>(); 363 in.readTypedList(videoEvents, VideoEvent.CREATOR); 364 callSource = in.readInt(); 365 } 366 writeToParcel(Parcel out, int flags)367 public void writeToParcel(Parcel out, int flags) { 368 out.writeLong(startTimeMillis); 369 out.writeLong(callDurationMillis); 370 out.writeInt(callType); 371 writeBooleanAsByte(out, isAdditionalCall); 372 writeBooleanAsByte(out, isInterrupted); 373 out.writeInt(callTechnologies); 374 out.writeInt(callTerminationCode); 375 writeBooleanAsByte(out, isEmergencyCall); 376 out.writeString(connectionService); 377 writeBooleanAsByte(out, isCreatedFromExistingConnection); 378 out.writeTypedList(analyticsEvents); 379 out.writeTypedList(eventTimings); 380 writeBooleanAsByte(out, isVideoCall); 381 out.writeTypedList(videoEvents); 382 out.writeInt(callSource); 383 } 384 385 /** {@hide} */ setIsVideoCall(boolean isVideoCall)386 public void setIsVideoCall(boolean isVideoCall) { 387 this.isVideoCall = isVideoCall; 388 } 389 390 /** {@hide} */ setVideoEvents(List<VideoEvent> videoEvents)391 public void setVideoEvents(List<VideoEvent> videoEvents) { 392 this.videoEvents = videoEvents; 393 } 394 395 /** {@hide} */ setCallSource(int callSource)396 public void setCallSource(int callSource) { 397 this.callSource = callSource; 398 } 399 getStartTimeMillis()400 public long getStartTimeMillis() { 401 return startTimeMillis; 402 } 403 getCallDurationMillis()404 public long getCallDurationMillis() { 405 return callDurationMillis; 406 } 407 getCallType()408 public int getCallType() { 409 return callType; 410 } 411 isAdditionalCall()412 public boolean isAdditionalCall() { 413 return isAdditionalCall; 414 } 415 isInterrupted()416 public boolean isInterrupted() { 417 return isInterrupted; 418 } 419 getCallTechnologies()420 public int getCallTechnologies() { 421 return callTechnologies; 422 } 423 getCallTerminationCode()424 public int getCallTerminationCode() { 425 return callTerminationCode; 426 } 427 isEmergencyCall()428 public boolean isEmergencyCall() { 429 return isEmergencyCall; 430 } 431 getConnectionService()432 public String getConnectionService() { 433 return connectionService; 434 } 435 isCreatedFromExistingConnection()436 public boolean isCreatedFromExistingConnection() { 437 return isCreatedFromExistingConnection; 438 } 439 analyticsEvents()440 public List<AnalyticsEvent> analyticsEvents() { 441 return analyticsEvents; 442 } 443 getEventTimings()444 public List<EventTiming> getEventTimings() { 445 return eventTimings; 446 } 447 448 /** {@hide} */ isVideoCall()449 public boolean isVideoCall() { 450 return isVideoCall; 451 } 452 453 /** {@hide} */ getVideoEvents()454 public List<VideoEvent> getVideoEvents() { 455 return videoEvents; 456 } 457 458 /** {@hide} */ getCallSource()459 public int getCallSource() { 460 return callSource; 461 } 462 463 @Override describeContents()464 public int describeContents() { 465 return 0; 466 } 467 writeBooleanAsByte(Parcel out, boolean b)468 private static void writeBooleanAsByte(Parcel out, boolean b) { 469 out.writeByte((byte) (b ? 1 : 0)); 470 } 471 readByteAsBoolean(Parcel in)472 private static boolean readByteAsBoolean(Parcel in) { 473 return (in.readByte() == 1); 474 } 475 } 476