Merge "Add CallAttributes and PhoneStateListener method"
am: 7bc14fcc38

Change-Id: If50be34f53e898a9b14ab7562338d419c9aa9f60
diff --git a/api/system-current.txt b/api/system-current.txt
index 25f35bb..5a04ff0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5054,6 +5054,40 @@
     field public static final int WWAN = 1; // 0x1
   }
 
+  public class CallAttributes implements android.os.Parcelable {
+    ctor public CallAttributes(android.telephony.PreciseCallState, int, android.telephony.CallQuality);
+    method public int describeContents();
+    method public android.telephony.CallQuality getCallQuality();
+    method public int getNetworkType();
+    method public android.telephony.PreciseCallState getPreciseCallState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
+  }
+
+  public final class CallQuality implements android.os.Parcelable {
+    ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int);
+    method public int describeContents();
+    method public int getAverageRelativeJitter();
+    method public int getAverageRoundTripTime();
+    method public int getCallDuration();
+    method public int getCodecType();
+    method public int getDownlinkCallQualityLevel();
+    method public int getMaxRelativeJitter();
+    method public int getNumRtpPacketsNotReceived();
+    method public int getNumRtpPacketsReceived();
+    method public int getNumRtpPacketsTransmitted();
+    method public int getNumRtpPacketsTransmittedLost();
+    method public int getUplinkCallQualityLevel();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CALL_QUALITY_BAD = 4; // 0x4
+    field public static final int CALL_QUALITY_EXCELLENT = 0; // 0x0
+    field public static final int CALL_QUALITY_FAIR = 2; // 0x2
+    field public static final int CALL_QUALITY_GOOD = 1; // 0x1
+    field public static final int CALL_QUALITY_NOT_AVAILABLE = 5; // 0x5
+    field public static final int CALL_QUALITY_POOR = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.telephony.CallQuality> CREATOR;
+  }
+
   public class CarrierConfigManager {
     method public static android.os.PersistableBundle getDefaultConfig();
     method public void overrideConfig(int, android.os.PersistableBundle);
@@ -5319,12 +5353,14 @@
   }
 
   public class PhoneStateListener {
+    method public void onCallAttributesChanged(android.telephony.CallAttributes);
     method public void onCallDisconnectCauseChanged(int, int);
     method public void onPreciseCallStateChanged(android.telephony.PreciseCallState);
     method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
     method public void onRadioPowerStateChanged(int);
     method public void onSrvccStateChanged(int);
     method public void onVoiceActivationStateChanged(int);
+    field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
     field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
     field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
     field public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
diff --git a/telephony/java/android/telephony/CallAttributes.aidl b/telephony/java/android/telephony/CallAttributes.aidl
new file mode 100644
index 0000000..69127df
--- /dev/null
+++ b/telephony/java/android/telephony/CallAttributes.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+parcelable CallAttributes;
+
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
new file mode 100644
index 0000000..2b99ce1
--- /dev/null
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkType;
+
+import java.util.Objects;
+
+/**
+ * Contains information about a call's attributes as passed up from the HAL. If there are multiple
+ * ongoing calls, the CallAttributes will pertain to the call in the foreground.
+ * @hide
+ */
+@SystemApi
+public class CallAttributes implements Parcelable {
+    private PreciseCallState mPreciseCallState;
+    @NetworkType
+    private int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints
+    private CallQuality mCallQuality;
+
+
+    public CallAttributes(PreciseCallState state, @NetworkType int networkType,
+            CallQuality callQuality) {
+        this.mPreciseCallState = state;
+        this.mNetworkType = networkType;
+        this.mCallQuality = callQuality;
+    }
+
+    @Override
+    public String toString() {
+        return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType
+                + " mCallQuality=" + mCallQuality;
+    }
+
+    private CallAttributes(Parcel in) {
+        mPreciseCallState = (PreciseCallState) in.readValue(mPreciseCallState.getClass()
+                .getClassLoader());
+        mNetworkType = in.readInt();
+        mCallQuality = (CallQuality) in.readValue(mCallQuality.getClass().getClassLoader());
+    }
+
+    // getters
+    /**
+     * Returns the {@link PreciseCallState} of the call.
+     */
+    public PreciseCallState getPreciseCallState() {
+        return mPreciseCallState;
+    }
+
+    /**
+     * Returns the {@link TelephonyManager#NetworkType} of the call.
+     *
+     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+     * @see TelephonyManager#NETWORK_TYPE_GPRS
+     * @see TelephonyManager#NETWORK_TYPE_EDGE
+     * @see TelephonyManager#NETWORK_TYPE_UMTS
+     * @see TelephonyManager#NETWORK_TYPE_CDMA
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+     * @see TelephonyManager#NETWORK_TYPE_1xRTT
+     * @see TelephonyManager#NETWORK_TYPE_HSDPA
+     * @see TelephonyManager#NETWORK_TYPE_HSUPA
+     * @see TelephonyManager#NETWORK_TYPE_HSPA
+     * @see TelephonyManager#NETWORK_TYPE_IDEN
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+     * @see TelephonyManager#NETWORK_TYPE_LTE
+     * @see TelephonyManager#NETWORK_TYPE_EHRPD
+     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     * @see TelephonyManager#NETWORK_TYPE_GSM
+     * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA
+     * @see TelephonyManager#NETWORK_TYPE_IWLAN
+     * @see TelephonyManager#NETWORK_TYPE_LTE_CA
+     * @see TelephonyManager#NETWORK_TYPE_NR
+     */
+    @NetworkType
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * Returns the {#link CallQuality} of the call.
+     */
+    public CallQuality getCallQuality() {
+        return mCallQuality;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof CallAttributes) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        CallAttributes s = (CallAttributes) o;
+
+        return (mPreciseCallState == s.mPreciseCallState
+                && mNetworkType == s.mNetworkType
+                && mCallQuality == s.mCallQuality);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public @Parcelable.ContentsFlags int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel dest, @Parcelable.WriteFlags int flags) {
+        mPreciseCallState.writeToParcel(dest, flags);
+        dest.writeInt(mNetworkType);
+        mCallQuality.writeToParcel(dest, flags);
+    }
+
+    public static final Parcelable.Creator<CallAttributes> CREATOR = new Parcelable.Creator() {
+        public CallAttributes createFromParcel(Parcel in) {
+            return new CallAttributes(in);
+        }
+
+        public CallAttributes[] newArray(int size) {
+            return new CallAttributes[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/CallQuality.aidl b/telephony/java/android/telephony/CallQuality.aidl
new file mode 100644
index 0000000..f54355f
--- /dev/null
+++ b/telephony/java/android/telephony/CallQuality.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+parcelable CallQuality;
+
diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java
new file mode 100644
index 0000000..b27f6b4
--- /dev/null
+++ b/telephony/java/android/telephony/CallQuality.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Parcelable object to handle call quality.
+ * <p>
+ * Currently this supports IMS calls.
+ * <p>
+ * It provides the call quality level, duration, and additional information related to RTP packets,
+ * jitter and delay.
+ * <p>
+ * If there are multiple active calls, the CallQuality will pertain to the call in the foreground.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CallQuality implements Parcelable {
+
+    // Constants representing the call quality level (see #CallQuality);
+    public static final int CALL_QUALITY_EXCELLENT = 0;
+    public static final int CALL_QUALITY_GOOD = 1;
+    public static final int CALL_QUALITY_FAIR = 2;
+    public static final int CALL_QUALITY_POOR = 3;
+    public static final int CALL_QUALITY_BAD = 4;
+    public static final int CALL_QUALITY_NOT_AVAILABLE = 5;
+
+    /**
+     * Call quality
+     * @hide
+     */
+    @IntDef(prefix = { "CALL_QUALITY_" }, value = {
+            CALL_QUALITY_EXCELLENT,
+            CALL_QUALITY_GOOD,
+            CALL_QUALITY_FAIR,
+            CALL_QUALITY_POOR,
+            CALL_QUALITY_BAD,
+            CALL_QUALITY_NOT_AVAILABLE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallQualityLevel {}
+
+    @CallQualityLevel
+    private int mDownlinkCallQualityLevel;
+    @CallQualityLevel
+    private int mUplinkCallQualityLevel;
+    private int mCallDuration;
+    private int mNumRtpPacketsTransmitted;
+    private int mNumRtpPacketsReceived;
+    private int mNumRtpPacketsTransmittedLost;
+    private int mNumRtpPacketsNotReceived;
+    private int mAverageRelativeJitter;
+    private int mMaxRelativeJitter;
+    private int mAverageRoundTripTime;
+    private int mCodecType;
+
+    /** @hide **/
+    public CallQuality(Parcel in) {
+        mDownlinkCallQualityLevel = in.readInt();
+        mUplinkCallQualityLevel = in.readInt();
+        mCallDuration = in.readInt();
+        mNumRtpPacketsTransmitted = in.readInt();
+        mNumRtpPacketsReceived = in.readInt();
+        mNumRtpPacketsTransmittedLost = in.readInt();
+        mNumRtpPacketsNotReceived = in.readInt();
+        mAverageRelativeJitter = in.readInt();
+        mMaxRelativeJitter = in.readInt();
+        mAverageRoundTripTime = in.readInt();
+        mCodecType = in.readInt();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param callQualityLevel the call quality level (see #CallQualityLevel)
+     * @param callDuration the call duration in milliseconds
+     * @param numRtpPacketsTransmitted RTP packets sent to network
+     * @param numRtpPacketsReceived RTP packets received from network
+     * @param numRtpPacketsTransmittedLost RTP packets which were lost in network and never
+     * transmitted
+     * @param numRtpPacketsNotReceived RTP packets which were lost in network and never recieved
+     * @param averageRelativeJitter average relative jitter in milliseconds
+     * @param maxRelativeJitter maximum relative jitter in milliseconds
+     * @param averageRoundTripTime average round trip delay in milliseconds
+     * @param codecType the codec type
+     */
+    public CallQuality(
+            @CallQualityLevel int downlinkCallQualityLevel,
+            @CallQualityLevel int uplinkCallQualityLevel,
+            int callDuration,
+            int numRtpPacketsTransmitted,
+            int numRtpPacketsReceived,
+            int numRtpPacketsTransmittedLost,
+            int numRtpPacketsNotReceived,
+            int averageRelativeJitter,
+            int maxRelativeJitter,
+            int averageRoundTripTime,
+            int codecType) {
+        this.mDownlinkCallQualityLevel = downlinkCallQualityLevel;
+        this.mUplinkCallQualityLevel = uplinkCallQualityLevel;
+        this.mCallDuration = callDuration;
+        this.mNumRtpPacketsTransmitted = numRtpPacketsTransmitted;
+        this.mNumRtpPacketsReceived = numRtpPacketsReceived;
+        this.mNumRtpPacketsTransmittedLost = numRtpPacketsTransmittedLost;
+        this.mNumRtpPacketsNotReceived = numRtpPacketsNotReceived;
+        this.mAverageRelativeJitter = averageRelativeJitter;
+        this.mMaxRelativeJitter = maxRelativeJitter;
+        this.mAverageRoundTripTime = averageRoundTripTime;
+        this.mCodecType = codecType;
+    }
+
+    // getters
+    /**
+     * Returns the downlink CallQualityLevel for a given ongoing call.
+     */
+    @CallQualityLevel
+    public int getDownlinkCallQualityLevel() {
+        return mDownlinkCallQualityLevel;
+    }
+
+    /**
+     * Returns the uplink CallQualityLevel for a given ongoing call.
+     */
+    @CallQualityLevel
+    public int getUplinkCallQualityLevel() {
+        return mUplinkCallQualityLevel;
+    }
+
+    /**
+     * Returns the duration of the call, in milliseconds.
+     */
+    public int getCallDuration() {
+        return mCallDuration;
+    }
+
+    /**
+     * Returns the total number of RTP packets transmitted by this device for a given ongoing call.
+     */
+    public int getNumRtpPacketsTransmitted() {
+        return mNumRtpPacketsTransmitted;
+    }
+
+    /**
+     * Returns the total number of RTP packets received by this device for a given ongoing call.
+     */
+    public int getNumRtpPacketsReceived() {
+        return mNumRtpPacketsReceived;
+    }
+
+    /**
+     * Returns the number of RTP packets which were sent by this device but were lost in the
+     * network before reaching the other party.
+     */
+    public int getNumRtpPacketsTransmittedLost() {
+        return mNumRtpPacketsTransmittedLost;
+    }
+
+    /**
+     * Returns the number of RTP packets which were sent by the other party but were lost in the
+     * network before reaching this device.
+     */
+    public int getNumRtpPacketsNotReceived() {
+        return mNumRtpPacketsNotReceived;
+    }
+
+    /**
+     * Returns the average relative jitter in milliseconds. Jitter represents the amount of variance
+     * in interarrival time of packets, for example, if two packets are sent 2 milliseconds apart
+     * but received 3 milliseconds apart, the relative jitter between those packets is 1
+     * millisecond.
+     *
+     * <p>See RFC 3550 for more information on jitter calculations.
+     */
+    public int getAverageRelativeJitter() {
+        return mAverageRelativeJitter;
+    }
+
+    /**
+     * Returns the maximum relative jitter for a given ongoing call. Jitter represents the amount of
+     * variance in interarrival time of packets, for example, if two packets are sent 2 milliseconds
+     * apart but received 3 milliseconds apart, the relative jitter between those packets is 1
+     * millisecond.
+     *
+     * <p>See RFC 3550 for more information on jitter calculations.
+     */
+    public int getMaxRelativeJitter() {
+        return mMaxRelativeJitter;
+    }
+
+    /**
+     * Returns the average round trip time in milliseconds.
+     */
+    public int getAverageRoundTripTime() {
+        return mAverageRoundTripTime;
+    }
+
+    /**
+     * Returns the codec type. This value corresponds to the AUDIO_QUALITY_* constants in
+     * {@link ImsStreamMediaProfile}.
+     *
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_NONE
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_AMR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_AMR_WB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_QCELP13K
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC_B
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC_WB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC_NW
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_GSM_EFR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_GSM_FR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_GSM_HR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G711U
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G723
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G711A
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G722
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G711AB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G729
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_NB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_WB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_SWB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_FB
+     */
+    public int getCodecType() {
+        return mCodecType;
+    }
+
+    // Parcelable things
+    @Override
+    public String toString() {
+        return "CallQuality: {downlinkCallQualityLevel=" + mDownlinkCallQualityLevel
+                + " uplinkCallQualityLevel=" + mUplinkCallQualityLevel
+                + " callDuration=" + mCallDuration
+                + " numRtpPacketsTransmitted=" + mNumRtpPacketsTransmitted
+                + " numRtpPacketsReceived=" + mNumRtpPacketsReceived
+                + " numRtpPacketsTransmittedLost=" + mNumRtpPacketsTransmittedLost
+                + " numRtpPacketsNotReceived=" + mNumRtpPacketsNotReceived
+                + " averageRelativeJitter=" + mAverageRelativeJitter
+                + " maxRelativeJitter=" + mMaxRelativeJitter
+                + " averageRoundTripTime=" + mAverageRoundTripTime
+                + " codecType=" + mCodecType
+                + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mDownlinkCallQualityLevel,
+                mUplinkCallQualityLevel,
+                mCallDuration,
+                mNumRtpPacketsTransmitted,
+                mNumRtpPacketsReceived,
+                mNumRtpPacketsTransmittedLost,
+                mNumRtpPacketsNotReceived,
+                mAverageRelativeJitter,
+                mMaxRelativeJitter,
+                mAverageRoundTripTime,
+                mCodecType);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof CallQuality) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        CallQuality s = (CallQuality) o;
+
+        return (mDownlinkCallQualityLevel == s.mDownlinkCallQualityLevel
+                && mUplinkCallQualityLevel == s.mUplinkCallQualityLevel
+                && mCallDuration == s.mCallDuration
+                && mNumRtpPacketsTransmitted == s.mNumRtpPacketsTransmitted
+                && mNumRtpPacketsReceived == s.mNumRtpPacketsReceived
+                && mNumRtpPacketsTransmittedLost == s.mNumRtpPacketsTransmittedLost
+                && mNumRtpPacketsNotReceived == s.mNumRtpPacketsNotReceived
+                && mAverageRelativeJitter == s.mAverageRelativeJitter
+                && mMaxRelativeJitter == s.mMaxRelativeJitter
+                && mAverageRoundTripTime == s.mAverageRoundTripTime
+                && mCodecType == s.mCodecType);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public @Parcelable.ContentsFlags int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel dest, @Parcelable.WriteFlags int flags) {
+        dest.writeInt(mDownlinkCallQualityLevel);
+        dest.writeInt(mUplinkCallQualityLevel);
+        dest.writeInt(mCallDuration);
+        dest.writeInt(mNumRtpPacketsTransmitted);
+        dest.writeInt(mNumRtpPacketsReceived);
+        dest.writeInt(mNumRtpPacketsTransmittedLost);
+        dest.writeInt(mNumRtpPacketsNotReceived);
+        dest.writeInt(mAverageRelativeJitter);
+        dest.writeInt(mMaxRelativeJitter);
+        dest.writeInt(mAverageRoundTripTime);
+        dest.writeInt(mCodecType);
+    }
+
+    public static final Parcelable.Creator<CallQuality> CREATOR = new Parcelable.Creator() {
+        public CallQuality createFromParcel(Parcel in) {
+            return new CallQuality(in);
+        }
+
+        public CallQuality[] newArray(int size) {
+            return new CallQuality[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index e27b385..a16d7eb 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -335,6 +335,18 @@
     @SystemApi
     public static final int LISTEN_CALL_DISCONNECT_CAUSES                  = 0x02000000;
 
+    /**
+     * Listen for changes to the call attributes of a currently active call.
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE}
+     *
+     * @see #onCallAttributesChanged
+     * @hide
+     */
+    @SystemApi
+    public static final int LISTEN_CALL_ATTRIBUTES_CHANGED                 = 0x04000000;
+
     /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -683,6 +695,17 @@
     }
 
     /**
+     * Callback invoked when the call attributes changes. Requires
+     * the READ_PRIVILEGED_PHONE_STATE permission.
+     * @param callAttributes the call attributes
+     * @hide
+     */
+    @SystemApi
+    public void onCallAttributesChanged(CallAttributes callAttributes) {
+        // default implementation empty
+    }
+
+    /**
      * Callback invoked when modem radio power state changes. Requires
      * the READ_PRIVILEGED_PHONE_STATE permission.
      * @param state the modem radio power state
@@ -941,6 +964,14 @@
                     () -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state)));
         }
 
+        public void onCallAttributesChanged(CallAttributes callAttributes) {
+            PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
+            if (psl == null) return;
+
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> psl.onCallAttributesChanged(callAttributes)));
+        }
+
         public void onPreferredDataSubIdChanged(int subId) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 00cf9c3..3dbebe8 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -17,14 +17,15 @@
 package com.android.internal.telephony;
 
 import android.os.Bundle;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
+import android.telephony.CallAttributes;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.telephony.emergency.EmergencyNumber;
 
 oneway interface IPhoneStateListener {
@@ -54,6 +55,7 @@
     void onPhoneCapabilityChanged(in PhoneCapability capability);
     void onPreferredDataSubIdChanged(in int subId);
     void onRadioPowerStateChanged(in int state);
+    void onCallAttributesChanged(in CallAttributes callAttributes);
     void onEmergencyNumberListChanged(in Map emergencyNumberList);
     void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
 }