/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package android.telecom; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * @hide */ @SystemApi public class ParcelableCallAnalytics implements Parcelable { /** {@hide} */ public static final class VideoEvent implements Parcelable { public static final int SEND_LOCAL_SESSION_MODIFY_REQUEST = 0; public static final int SEND_LOCAL_SESSION_MODIFY_RESPONSE = 1; public static final int RECEIVE_REMOTE_SESSION_MODIFY_REQUEST = 2; public static final int RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE = 3; public static final Parcelable.Creator CREATOR = new Parcelable.Creator () { @Override public VideoEvent createFromParcel(Parcel in) { return new VideoEvent(in); } @Override public VideoEvent[] newArray(int size) { return new VideoEvent[size]; } }; private int mEventName; private long mTimeSinceLastEvent; private int mVideoState; public VideoEvent(int eventName, long timeSinceLastEvent, int videoState) { mEventName = eventName; mTimeSinceLastEvent = timeSinceLastEvent; mVideoState = videoState; } VideoEvent(Parcel in) { mEventName = in.readInt(); mTimeSinceLastEvent = in.readLong(); mVideoState = in.readInt(); } public int getEventName() { return mEventName; } public long getTimeSinceLastEvent() { return mTimeSinceLastEvent; } public int getVideoState() { return mVideoState; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mEventName); out.writeLong(mTimeSinceLastEvent); out.writeInt(mVideoState); } } public static final class AnalyticsEvent implements Parcelable { public static final int SET_SELECT_PHONE_ACCOUNT = 0; public static final int SET_ACTIVE = 1; public static final int SET_DISCONNECTED = 2; public static final int START_CONNECTION = 3; public static final int SET_DIALING = 4; public static final int BIND_CS = 5; public static final int CS_BOUND = 6; public static final int REQUEST_ACCEPT = 7; public static final int REQUEST_REJECT = 8; public static final int SCREENING_SENT = 100; public static final int SCREENING_COMPLETED = 101; public static final int DIRECT_TO_VM_INITIATED = 102; public static final int DIRECT_TO_VM_FINISHED = 103; public static final int BLOCK_CHECK_INITIATED = 104; public static final int BLOCK_CHECK_FINISHED = 105; public static final int FILTERING_INITIATED = 106; public static final int FILTERING_COMPLETED = 107; public static final int FILTERING_TIMED_OUT = 108; public static final int SKIP_RINGING = 200; public static final int SILENCE = 201; public static final int MUTE = 202; public static final int UNMUTE = 203; public static final int AUDIO_ROUTE_BT = 204; public static final int AUDIO_ROUTE_EARPIECE = 205; public static final int AUDIO_ROUTE_HEADSET = 206; public static final int AUDIO_ROUTE_SPEAKER = 207; public static final int CONFERENCE_WITH = 300; public static final int SPLIT_CONFERENCE = 301; public static final int SET_PARENT = 302; public static final int REQUEST_HOLD = 400; public static final int REQUEST_UNHOLD = 401; public static final int REMOTELY_HELD = 402; public static final int REMOTELY_UNHELD = 403; public static final int SET_HOLD = 404; public static final int SWAP = 405; public static final int REQUEST_PULL = 500; public static final Parcelable.Creator CREATOR = new Parcelable.Creator () { @Override public AnalyticsEvent createFromParcel(Parcel in) { return new AnalyticsEvent(in); } @Override public AnalyticsEvent[] newArray(int size) { return new AnalyticsEvent[size]; } }; private int mEventName; private long mTimeSinceLastEvent; public AnalyticsEvent(int eventName, long timestamp) { mEventName = eventName; mTimeSinceLastEvent = timestamp; } AnalyticsEvent(Parcel in) { mEventName = in.readInt(); mTimeSinceLastEvent = in.readLong(); } public int getEventName() { return mEventName; } public long getTimeSinceLastEvent() { return mTimeSinceLastEvent; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mEventName); out.writeLong(mTimeSinceLastEvent); } } public static final class EventTiming implements Parcelable { public static final int ACCEPT_TIMING = 0; public static final int REJECT_TIMING = 1; public static final int DISCONNECT_TIMING = 2; public static final int HOLD_TIMING = 3; public static final int UNHOLD_TIMING = 4; public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5; public static final int BIND_CS_TIMING = 6; public static final int SCREENING_COMPLETED_TIMING = 7; public static final int DIRECT_TO_VM_FINISHED_TIMING = 8; public static final int BLOCK_CHECK_FINISHED_TIMING = 9; public static final int FILTERING_COMPLETED_TIMING = 10; public static final int FILTERING_TIMED_OUT_TIMING = 11; public static final int INVALID = 999999; public static final Parcelable.Creator CREATOR = new Parcelable.Creator () { @Override public EventTiming createFromParcel(Parcel in) { return new EventTiming(in); } @Override public EventTiming[] newArray(int size) { return new EventTiming[size]; } }; private int mName; private long mTime; public EventTiming(int name, long time) { this.mName = name; this.mTime = time; } private EventTiming(Parcel in) { mName = in.readInt(); mTime = in.readLong(); } public int getName() { return mName; } public long getTime() { return mTime; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mName); out.writeLong(mTime); } } public static final int CALLTYPE_UNKNOWN = 0; public static final int CALLTYPE_INCOMING = 1; public static final int CALLTYPE_OUTGOING = 2; // Constants for call technology public static final int CDMA_PHONE = 0x1; public static final int GSM_PHONE = 0x2; public static final int IMS_PHONE = 0x4; public static final int SIP_PHONE = 0x8; public static final int THIRD_PARTY_PHONE = 0x10; public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5; public static final long MILLIS_IN_1_SECOND = 1000; public static final int STILL_CONNECTED = -1; public static final Parcelable.Creator CREATOR = new Parcelable.Creator () { @Override public ParcelableCallAnalytics createFromParcel(Parcel in) { return new ParcelableCallAnalytics(in); } @Override public ParcelableCallAnalytics[] newArray(int size) { return new ParcelableCallAnalytics[size]; } }; // The start time of the call in milliseconds since Jan. 1, 1970, rounded to the nearest // 5 minute increment. private final long startTimeMillis; // The duration of the call, in milliseconds. private final long callDurationMillis; // ONE OF calltype_unknown, calltype_incoming, or calltype_outgoing private final int callType; // true if the call came in while another call was in progress or if the user dialed this call // while in the middle of another call. private final boolean isAdditionalCall; // true if the call was interrupted by an incoming or outgoing call. private final boolean isInterrupted; // bitmask denoting which technologies a call used. private final int callTechnologies; // Any of the DisconnectCause codes, or STILL_CONNECTED. private final int callTerminationCode; // Whether the call is an emergency call private final boolean isEmergencyCall; // The package name of the connection service that this call used. private final String connectionService; // Whether the call object was created from an existing connection. private final boolean isCreatedFromExistingConnection; // A list of events that are associated with this call private final List analyticsEvents; // A map from event-pair names to their durations. private final List eventTimings; // Whether the call has ever been a video call. private boolean isVideoCall = false; // A list of video events that have occurred. private List videoEvents; public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType, boolean isAdditionalCall, boolean isInterrupted, int callTechnologies, int callTerminationCode, boolean isEmergencyCall, String connectionService, boolean isCreatedFromExistingConnection, List analyticsEvents, List eventTimings) { this.startTimeMillis = startTimeMillis; this.callDurationMillis = callDurationMillis; this.callType = callType; this.isAdditionalCall = isAdditionalCall; this.isInterrupted = isInterrupted; this.callTechnologies = callTechnologies; this.callTerminationCode = callTerminationCode; this.isEmergencyCall = isEmergencyCall; this.connectionService = connectionService; this.isCreatedFromExistingConnection = isCreatedFromExistingConnection; this.analyticsEvents = analyticsEvents; this.eventTimings = eventTimings; } public ParcelableCallAnalytics(Parcel in) { startTimeMillis = in.readLong(); callDurationMillis = in.readLong(); callType = in.readInt(); isAdditionalCall = readByteAsBoolean(in); isInterrupted = readByteAsBoolean(in); callTechnologies = in.readInt(); callTerminationCode = in.readInt(); isEmergencyCall = readByteAsBoolean(in); connectionService = in.readString(); isCreatedFromExistingConnection = readByteAsBoolean(in); analyticsEvents = new ArrayList<>(); in.readTypedList(analyticsEvents, AnalyticsEvent.CREATOR); eventTimings = new ArrayList<>(); in.readTypedList(eventTimings, EventTiming.CREATOR); isVideoCall = readByteAsBoolean(in); videoEvents = new LinkedList<>(); in.readTypedList(videoEvents, VideoEvent.CREATOR); } public void writeToParcel(Parcel out, int flags) { out.writeLong(startTimeMillis); out.writeLong(callDurationMillis); out.writeInt(callType); writeBooleanAsByte(out, isAdditionalCall); writeBooleanAsByte(out, isInterrupted); out.writeInt(callTechnologies); out.writeInt(callTerminationCode); writeBooleanAsByte(out, isEmergencyCall); out.writeString(connectionService); writeBooleanAsByte(out, isCreatedFromExistingConnection); out.writeTypedList(analyticsEvents); out.writeTypedList(eventTimings); writeBooleanAsByte(out, isVideoCall); out.writeTypedList(videoEvents); } /** {@hide} */ public void setIsVideoCall(boolean isVideoCall) { this.isVideoCall = isVideoCall; } /** {@hide} */ public void setVideoEvents(List videoEvents) { this.videoEvents = videoEvents; } public long getStartTimeMillis() { return startTimeMillis; } public long getCallDurationMillis() { return callDurationMillis; } public int getCallType() { return callType; } public boolean isAdditionalCall() { return isAdditionalCall; } public boolean isInterrupted() { return isInterrupted; } public int getCallTechnologies() { return callTechnologies; } public int getCallTerminationCode() { return callTerminationCode; } public boolean isEmergencyCall() { return isEmergencyCall; } public String getConnectionService() { return connectionService; } public boolean isCreatedFromExistingConnection() { return isCreatedFromExistingConnection; } public List analyticsEvents() { return analyticsEvents; } public List getEventTimings() { return eventTimings; } /** {@hide} */ public boolean isVideoCall() { return isVideoCall; } /** {@hide} */ public List getVideoEvents() { return videoEvents; } @Override public int describeContents() { return 0; } private static void writeBooleanAsByte(Parcel out, boolean b) { out.writeByte((byte) (b ? 1 : 0)); } private static boolean readByteAsBoolean(Parcel in) { return (in.readByte() == 1); } }