package android.telecom.Logging;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.Log;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
public class Session {
public static final String START_SESSION = "START_SESSION";
public static final String START_EXTERNAL_SESSION = "START_EXTERNAL_SESSION";
public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION";
public static final String CONTINUE_SUBSESSION = "CONTINUE_SUBSESSION";
public static final String END_SUBSESSION = "END_SUBSESSION";
public static final String END_SESSION = "END_SESSION";
public static final String SUBSESSION_SEPARATION_CHAR = "->";
public static final String SESSION_SEPARATION_CHAR_CHILD = "_";
public static final String EXTERNAL_INDICATOR = "E-";
public static final String TRUNCATE_STRING = "...";
public static final int UNDEFINED = -1;
public static class Info implements Parcelable {
public final String sessionId;
public final String methodPath;
private Info(String id, String path) {
sessionId = id;
methodPath = path;
}
public static Info getInfo (Session s) {
return new Info(s.getFullSessionId(), s.getFullMethodPath(
!Log.DEBUG && s.isSessionExternal()));
}
public static final Parcelable.Creator<Info> CREATOR =
new Parcelable.Creator<Info> () {
@Override
public Info createFromParcel(Parcel source) {
String id = source.readString();
String methodName = source.readString();
return new Info(id, methodName);
}
@Override
public Info[] newArray(int size) {
return new Info[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel destination, int flags) {
destination.writeString(sessionId);
destination.writeString(methodPath);
}
}
private String mSessionId;
private String mShortMethodName;
private long mExecutionStartTimeMs;
private long mExecutionEndTimeMs = UNDEFINED;
private Session mParentSession;
private ArrayList<Session> mChildSessions;
private boolean mIsCompleted = false;
private boolean mIsExternal = false;
private int mChildCounter = 0;
private boolean mIsStartedFromActiveSession = false;
private String mOwnerInfo;
private String mFullMethodPathCache;
public Session(String sessionId, String shortMethodName, long startTimeMs,
boolean isStartedFromActiveSession, String ownerInfo) {
setSessionId(sessionId);
setShortMethodName(shortMethodName);
mExecutionStartTimeMs = startTimeMs;
mParentSession = null;
mChildSessions = new ArrayList<>(5);
mIsStartedFromActiveSession = isStartedFromActiveSession;
mOwnerInfo = ownerInfo;
}
public void setSessionId(@NonNull String sessionId) {
if (sessionId == null) {
mSessionId = "?";
}
mSessionId = sessionId;
}
public String getShortMethodName() {
return mShortMethodName;
}
public void setShortMethodName(String shortMethodName) {
if (shortMethodName == null) {
shortMethodName = "";
}
mShortMethodName = shortMethodName;
}
public void setIsExternal(boolean isExternal) {
mIsExternal = isExternal;
}
public boolean isExternal() {
return mIsExternal;
}
public void setParentSession(Session parentSession) {
mParentSession = parentSession;
}
public void addChild(Session childSession) {
if (childSession != null) {
mChildSessions.add(childSession);
}
}
public void removeChild(Session child) {
if (child != null) {
mChildSessions.remove(child);
}
}
public long getExecutionStartTimeMilliseconds() {
return mExecutionStartTimeMs;
}
public void setExecutionStartTimeMs(long startTimeMs) {
mExecutionStartTimeMs = startTimeMs;
}
public Session getParentSession() {
return mParentSession;
}
public ArrayList<Session> getChildSessions() {
return mChildSessions;
}
public boolean isSessionCompleted() {
return mIsCompleted;
}
public boolean isStartedFromActiveSession() {
return mIsStartedFromActiveSession;
}
public Info getInfo() {
return Info.getInfo(this);
}
@VisibleForTesting
public String getSessionId() {
return mSessionId;
}
public void markSessionCompleted(long executionEndTimeMs) {
mExecutionEndTimeMs = executionEndTimeMs;
mIsCompleted = true;
}
public long getLocalExecutionTime() {
if (mExecutionEndTimeMs == UNDEFINED) {
return UNDEFINED;
}
return mExecutionEndTimeMs - mExecutionStartTimeMs;
}
public synchronized String getNextChildId() {
return String.valueOf(mChildCounter++);
}
private String getFullSessionId() {
Session parentSession = mParentSession;
if (parentSession == null) {
return mSessionId;
} else {
if (Log.VERBOSE) {
return parentSession.getFullSessionId() +
SESSION_SEPARATION_CHAR_CHILD + mSessionId;
} else {
return parentSession.getFullSessionId();
}
}
}
public String printFullSessionTree() {
Session topNode = this;
while (topNode.getParentSession() != null) {
topNode = topNode.getParentSession();
}
return topNode.printSessionTree();
}
public String printSessionTree() {
StringBuilder sb = new StringBuilder();
printSessionTree(0, sb);
return sb.toString();
}
private void printSessionTree(int tabI, StringBuilder sb) {
sb.append(toString());
for (Session child : mChildSessions) {
sb.append("\n");
for (int i = 0; i <= tabI; i++) {
sb.append("\t");
}
child.printSessionTree(tabI + 1, sb);
}
}
public String getFullMethodPath(boolean truncatePath) {
StringBuilder sb = new StringBuilder();
getFullMethodPath(sb, truncatePath);
return sb.toString();
}
private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath) {
if (!TextUtils.isEmpty(mFullMethodPathCache) && !truncatePath) {
sb.append(mFullMethodPathCache);
return;
}
Session parentSession = getParentSession();
boolean isSessionStarted = false;
if (parentSession != null) {
isSessionStarted = !mShortMethodName.equals(parentSession.mShortMethodName);
parentSession.getFullMethodPath(sb, truncatePath);
sb.append(SUBSESSION_SEPARATION_CHAR);
}
if (isExternal()) {
if (truncatePath) {
sb.append(TRUNCATE_STRING);
} else {
sb.append("(");
sb.append(mShortMethodName);
sb.append(")");
}
} else {
sb.append(mShortMethodName);
}
if (isSessionStarted && !truncatePath) {
mFullMethodPathCache = sb.toString();
}
}
private boolean isSessionExternal() {
if (getParentSession() == null) {
return isExternal();
} else {
return getParentSession().isSessionExternal();
}
}
@Override
public int hashCode() {
int result = mSessionId != null ? mSessionId.hashCode() : 0;
result = 31 * result + (mShortMethodName != null ? mShortMethodName.hashCode() : 0);
result = 31 * result + (int) (mExecutionStartTimeMs ^ (mExecutionStartTimeMs >>> 32));
result = 31 * result + (int) (mExecutionEndTimeMs ^ (mExecutionEndTimeMs >>> 32));
result = 31 * result + (mParentSession != null ? mParentSession.hashCode() : 0);
result = 31 * result + (mChildSessions != null ? mChildSessions.hashCode() : 0);
result = 31 * result + (mIsCompleted ? 1 : 0);
result = 31 * result + mChildCounter;
result = 31 * result + (mIsStartedFromActiveSession ? 1 : 0);
result = 31 * result + (mOwnerInfo != null ? mOwnerInfo.hashCode() : 0);
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Session session = (Session) o;
if (mExecutionStartTimeMs != session.mExecutionStartTimeMs) return false;
if (mExecutionEndTimeMs != session.mExecutionEndTimeMs) return false;
if (mIsCompleted != session.mIsCompleted) return false;
if (mChildCounter != session.mChildCounter) return false;
if (mIsStartedFromActiveSession != session.mIsStartedFromActiveSession) return false;
if (mSessionId != null ?
!mSessionId.equals(session.mSessionId) : session.mSessionId != null)
return false;
if (mShortMethodName != null ? !mShortMethodName.equals(session.mShortMethodName)
: session.mShortMethodName != null)
return false;
if (mParentSession != null ? !mParentSession.equals(session.mParentSession)
: session.mParentSession != null)
return false;
if (mChildSessions != null ? !mChildSessions.equals(session.mChildSessions)
: session.mChildSessions != null)
return false;
return mOwnerInfo != null ? mOwnerInfo.equals(session.mOwnerInfo)
: session.mOwnerInfo == null;
}
@Override
public String toString() {
if (mParentSession != null && mIsStartedFromActiveSession) {
return mParentSession.toString();
} else {
StringBuilder methodName = new StringBuilder();
methodName.append(getFullMethodPath(false ));
if (mOwnerInfo != null && !mOwnerInfo.isEmpty()) {
methodName.append("(InCall package: ");
methodName.append(mOwnerInfo);
methodName.append(")");
}
return methodName.toString() + "@" + getFullSessionId();
}
}
}