Define APIs for fetching QoS parameters

- Define AIDL APIs for fetching QoS parameters
- Define classes to map HAL structures for QoS params

Change-Id: Ie6adc4e98189ded58abdb9d2a232093a8cb33602
CRs-Fixed: 3293236
diff --git a/extphone/Android.bp b/extphone/Android.bp
index b451b90..0e2dd51 100644
--- a/extphone/Android.bp
+++ b/extphone/Android.bp
@@ -11,6 +11,11 @@
         "src/com/**/*.java",
         "src/com/**/I*.aidl",
     ],
+
+    static_libs: [
+        "android.hardware.radio-V1.6-java",
+    ],
+
     system_ext_specific: true,
 }
 
@@ -26,6 +31,11 @@
         "src/com/**/*.java",
         "src/com/**/I*.aidl",
     ],
+
+    static_libs: [
+        "android.hardware.radio-V1.6-java",
+    ],
+
     product_specific: true,
 }
 
diff --git a/extphone/src/com/qti/extphone/EpsQos.java b/extphone/src/com/qti/extphone/EpsQos.java
new file mode 100644
index 0000000..7c10624
--- /dev/null
+++ b/extphone/src/com/qti/extphone/EpsQos.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright 2020 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.
+ */
+
+/**
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+
+/**
+ * Class that stores information specific to NR QOS.
+ */
+public final class EpsQos extends Qos implements Parcelable {
+
+    int qosClassId;
+
+    public EpsQos() {
+        super(Qos.QOS_TYPE_EPS,
+                new android.hardware.radio.V1_6.QosBandwidth(),
+                new android.hardware.radio.V1_6.QosBandwidth());
+    }
+
+    public EpsQos(/* @NonNull */ android.hardware.radio.V1_6.EpsQos qos) {
+        super(Qos.QOS_TYPE_EPS, qos.downlink, qos.uplink);
+        qosClassId = qos.qci;
+    }
+
+    private EpsQos(Parcel source) {
+        super(source);
+        qosClassId = source.readInt();
+    }
+
+    public int getQci() {
+        return qosClassId;
+    }
+
+    // @NonNull
+    public static EpsQos createFromParcelBody(/* @NonNull */ Parcel in) {
+        return new EpsQos(in);
+    }
+
+    @Override
+    public void writeToParcel(/* @NonNull */ Parcel dest, int flags) {
+        super.writeToParcel(Qos.QOS_TYPE_EPS, dest, flags);
+        dest.writeInt(qosClassId);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), qosClassId);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || !(o instanceof EpsQos)) {
+            return false;
+        }
+
+        EpsQos other = (EpsQos) o;
+
+        return this.qosClassId == other.qosClassId
+               && super.equals(other);
+    }
+
+    @Override
+    public String toString() {
+        return "EpsQos {"
+                + " qosClassId=" + qosClassId
+                + " downlink=" + downlink
+                + " uplink=" + uplink + "}";
+    }
+
+    // @NonNull
+    public static final Parcelable.Creator<EpsQos> CREATOR =
+            new Parcelable.Creator<EpsQos>() {
+                @Override
+                public EpsQos createFromParcel(Parcel source) {
+                    return new EpsQos(source);
+                }
+
+                @Override
+                public EpsQos[] newArray(int size) {
+                    return new EpsQos[size];
+                }
+            };
+}
diff --git a/extphone/src/com/qti/extphone/ExtPhoneCallbackBase.java b/extphone/src/com/qti/extphone/ExtPhoneCallbackBase.java
index 0c84ab6..3a77c0a 100644
--- a/extphone/src/com/qti/extphone/ExtPhoneCallbackBase.java
+++ b/extphone/src/com/qti/extphone/ExtPhoneCallbackBase.java
@@ -120,6 +120,11 @@
                 " token = " + token + " status" + status + " raf = " + raf);
     }
 
+    @Override
+    public void getQosParametersResponse(int slotId, Token token, Status status,
+                QosParametersResult result) throws RemoteException {
+    }
+
     public void onNrDcParam(int slotId, Token token, Status status, DcParam dcParam) throws
             RemoteException {
         Log.d(TAG, "UNIMPLEMENTED: onNrDcParam: slotId = " + slotId +
@@ -251,4 +256,9 @@
     @Override
     public void setMsimPreferenceResponse(Token token, Status status) throws RemoteException {
     }
+
+    @Override
+    public void onQosParametersChanged(int slotId, int cid, QosParametersResult result)
+            throws RemoteException {
+    }
 }
diff --git a/extphone/src/com/qti/extphone/ExtTelephonyManager.java b/extphone/src/com/qti/extphone/ExtTelephonyManager.java
index 115eb87..8390999 100644
--- a/extphone/src/com/qti/extphone/ExtTelephonyManager.java
+++ b/extphone/src/com/qti/extphone/ExtTelephonyManager.java
@@ -976,6 +976,21 @@
         return support;
     }
 
+    public Token getQosParameters(int slotId, int cid, Client client) throws RemoteException {
+        Log.d(LOG_TAG, "[" + slotId + "] getQosParameters, cid: " + cid);
+        Token token = null;
+        if (!isServiceConnected()) {
+            Log.e(LOG_TAG, "service not connected!");
+            return token;
+        }
+        try {
+            token = mExtTelephonyService.getQosParameters(slotId, cid, client);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "getQosParameters ended in remote exception", e);
+        }
+        return token;
+    }
+
     public Token getSecureModeStatus(Client client) throws RemoteException {
         Token token = null;
         if (!isServiceConnected()) {
diff --git a/extphone/src/com/qti/extphone/IExtPhone.aidl b/extphone/src/com/qti/extphone/IExtPhone.aidl
index 470d072..5bc5345 100644
--- a/extphone/src/com/qti/extphone/IExtPhone.aidl
+++ b/extphone/src/com/qti/extphone/IExtPhone.aidl
@@ -519,6 +519,15 @@
      boolean isEpdgOverCellularDataSupported(int slotId);
 
     /**
+     * Request for QoS parameters for a particular data call.
+     *
+     * @param - slotId slot ID
+     * @param - cid connection id of the data call for which the QoS parameters are requested
+     * @return - Integer Token to be used to map the response.
+     */
+     Token getQosParameters(int slot, int cid, in Client client);
+
+    /**
      * Query the status of Secure Mode
      *
      * @param client - Client registered with package name to receive callbacks
diff --git a/extphone/src/com/qti/extphone/IExtPhoneCallback.aidl b/extphone/src/com/qti/extphone/IExtPhoneCallback.aidl
index 7389073..90d6f6b 100644
--- a/extphone/src/com/qti/extphone/IExtPhoneCallback.aidl
+++ b/extphone/src/com/qti/extphone/IExtPhoneCallback.aidl
@@ -43,8 +43,9 @@
 import com.qti.extphone.NrConfig;
 import com.qti.extphone.NrConfigType;
 import com.qti.extphone.NrIconType;
-import com.qti.extphone.QtiCallForwardInfo;
 import com.qti.extphone.QRadioResponseInfo;
+import com.qti.extphone.QosParametersResult;
+import com.qti.extphone.QtiCallForwardInfo;
 import com.qti.extphone.QtiImeiInfo;
 import com.qti.extphone.SignalStrength;
 import com.qti.extphone.SmsResult;
@@ -247,6 +248,26 @@
     void onEpdgOverCellularDataSupported(int slotId, boolean support);
 
     /**
+     * Response to IExtPhone.getQosParameters() request
+     *
+     * @param slotId
+     * @param token is the same token which is received in getQosParameters request
+     * @param status SUCCESS/FAILURE based on the modem result code
+     * @param result QosParametersResult containing the requested QoS parameters
+     */
+    void getQosParametersResponse(int slotId, in Token token, in Status status,
+                                  in QosParametersResult result);
+
+    /**
+     * Indication received when QoS parameters have changed for a given connection id
+     *
+     * @param slotId
+     * @param cid Connection id for which the QoS parameters have changed
+     * @param result QosParametersResult containing the updated QoS parameters
+     */
+    void onQosParametersChanged(int slotId, int cid, in QosParametersResult result);
+
+    /**
      * Response to getSecureModeStatus
      * @param - token is the same token which is received in setSmartDdsSwitchToggle
      * @param - status SUCCESS/FAILURE based on RIL data module response
diff --git a/extphone/src/com/qti/extphone/NrQos.java b/extphone/src/com/qti/extphone/NrQos.java
new file mode 100644
index 0000000..e45d7de
--- /dev/null
+++ b/extphone/src/com/qti/extphone/NrQos.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright 2020 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.
+ */
+
+/**
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Class that stores information specific to NR QOS.
+ */
+public final class NrQos extends Qos implements Parcelable {
+    int qosFlowId;
+    int fiveQi;
+    int averagingWindowMs;
+
+    public NrQos(/* @NonNull */ android.hardware.radio.V1_6.NrQos qos) {
+        super(Qos.QOS_TYPE_NR, qos.downlink, qos.uplink);
+        fiveQi = qos.fiveQi;
+        qosFlowId = qos.qfi;
+        averagingWindowMs = qos.averagingWindowMs;
+    }
+
+    private NrQos(Parcel source) {
+        super(source);
+        this.qosFlowId = source.readInt();
+        this.fiveQi = source.readInt();
+        this.averagingWindowMs = source.readInt();
+    }
+
+    // @NonNull
+    public static NrQos createFromParcelBody(/* @NonNull */ Parcel in) {
+        return new NrQos(in);
+    }
+
+    public int get5Qi() {
+        return fiveQi;
+    }
+
+    public int getQfi() {
+        return qosFlowId;
+    }
+
+    public int getAveragingWindow() {
+        return averagingWindowMs;
+    }
+
+    @Override
+    public void writeToParcel(/* @NonNull */ Parcel dest, int flags) {
+        super.writeToParcel(Qos.QOS_TYPE_NR, dest, flags);
+        dest.writeInt(qosFlowId);
+        dest.writeInt(fiveQi);
+        dest.writeInt(averagingWindowMs);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), qosFlowId, fiveQi, averagingWindowMs);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || !(o instanceof NrQos)) {
+            return false;
+        }
+
+        NrQos other = (NrQos) o;
+
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        return this.qosFlowId == other.qosFlowId
+            && this.fiveQi == other.fiveQi
+            && this.averagingWindowMs == other.averagingWindowMs;
+    }
+
+    @Override
+    public String toString() {
+        return "NrQos {"
+                + " fiveQi=" + fiveQi
+                + " downlink=" + downlink
+                + " uplink=" + uplink
+                + " qosFlowId=" + qosFlowId
+                + " averagingWindowMs=" + averagingWindowMs + "}";
+    }
+
+    // @NonNull
+    public static final Parcelable.Creator<NrQos> CREATOR =
+            new Parcelable.Creator<NrQos>() {
+                @Override
+                public NrQos createFromParcel(Parcel source) {
+                    return new NrQos(source);
+                }
+
+                @Override
+                public NrQos[] newArray(int size) {
+                    return new NrQos[size];
+                }
+            };
+}
diff --git a/extphone/src/com/qti/extphone/Qos.java b/extphone/src/com/qti/extphone/Qos.java
new file mode 100644
index 0000000..af17698
--- /dev/null
+++ b/extphone/src/com/qti/extphone/Qos.java
@@ -0,0 +1,199 @@
+/**
+ * Copyright 2020 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.
+ */
+
+/**
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class that stores information specific to QOS.
+ */
+public abstract class Qos {
+
+    /**
+     * @hide
+     * @Retention(RetentionPolicy.SOURCE)
+     * @IntDef(prefix = "QOS_TYPE_",
+     *         value = {QOS_TYPE_EPS, QOS_TYPE_NR})
+     */
+    public @interface QosType {}
+
+    @QosType
+    final int type;
+
+    public static final int QOS_TYPE_EPS = 1;
+    public static final int QOS_TYPE_NR = 2;
+
+    final QosBandwidth downlink;
+    final QosBandwidth uplink;
+
+    Qos(int type,
+            /* @NonNull */ android.hardware.radio.V1_6.QosBandwidth downlink,
+            /* @NonNull */ android.hardware.radio.V1_6.QosBandwidth uplink) {
+        this.type = type;
+        this.downlink = new QosBandwidth(downlink.maxBitrateKbps, downlink.guaranteedBitrateKbps);
+        this.uplink = new QosBandwidth(uplink.maxBitrateKbps, uplink.guaranteedBitrateKbps);
+    }
+
+    public QosBandwidth getDownlinkBandwidth() {
+        return downlink;
+    }
+
+    public QosBandwidth getUplinkBandwidth() {
+        return uplink;
+    }
+
+    public static class QosBandwidth implements Parcelable {
+        int maxBitrateKbps;
+        int guaranteedBitrateKbps;
+
+        QosBandwidth() {
+        }
+
+        QosBandwidth(int maxBitrateKbps, int guaranteedBitrateKbps) {
+            this.maxBitrateKbps = maxBitrateKbps;
+            this.guaranteedBitrateKbps = guaranteedBitrateKbps;
+        }
+
+        private QosBandwidth(Parcel source) {
+            maxBitrateKbps = source.readInt();
+            guaranteedBitrateKbps = source.readInt();
+        }
+
+        public int getMaxBitrateKbps() {
+            return maxBitrateKbps;
+        }
+
+        public int getGuaranteedBitrateKbps() {
+            return guaranteedBitrateKbps;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(maxBitrateKbps);
+            dest.writeInt(guaranteedBitrateKbps);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(maxBitrateKbps, guaranteedBitrateKbps);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+
+            if (o == null || !(o instanceof QosBandwidth)) {
+                return false;
+            }
+
+            QosBandwidth other = (QosBandwidth) o;
+            return maxBitrateKbps == other.maxBitrateKbps
+                    && guaranteedBitrateKbps == other.guaranteedBitrateKbps;
+        }
+
+        @Override
+        public String toString() {
+            return "Bandwidth {"
+                    + " maxBitrateKbps=" + maxBitrateKbps
+                    + " guaranteedBitrateKbps=" + guaranteedBitrateKbps + "}";
+        }
+
+        // @NonNull
+        public static final Parcelable.Creator<QosBandwidth> CREATOR =
+                new Parcelable.Creator<QosBandwidth>() {
+                    @Override
+                    public QosBandwidth createFromParcel(Parcel source) {
+                        return new QosBandwidth(source);
+                    }
+
+                    @Override
+                    public QosBandwidth[] newArray(int size) {
+                        return new QosBandwidth[size];
+                    }
+                };
+    };
+
+    protected Qos(/* @NonNull */ Parcel source) {
+        type = source.readInt();
+        downlink = source.readParcelable(QosBandwidth.class.getClassLoader());
+        uplink = source.readParcelable(QosBandwidth.class.getClassLoader());
+    }
+
+    /**
+     * Used by child classes for parceling.
+     *
+     * @hide
+     * @CallSuper
+     */
+    public void writeToParcel(@QosType int type, Parcel dest, int flags) {
+        dest.writeInt(type);
+        dest.writeParcelable(downlink, flags);
+        dest.writeParcelable(uplink, flags);
+    }
+
+    /**
+     * @hide
+     * @NonNull
+     */
+    public static Qos create(/* @NonNull */ android.hardware.radio.V1_6.Qos qos) {
+        switch (qos.getDiscriminator()) {
+            case android.hardware.radio.V1_6.Qos.hidl_discriminator.eps:
+                  return new EpsQos(qos.eps());
+            case android.hardware.radio.V1_6.Qos.hidl_discriminator.nr:
+                  return new NrQos(qos.nr());
+            default:
+                  return null;
+        }
+    }
+
+    /** @hide */
+    public @QosType int getType() {
+        return type;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(downlink, uplink);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        Qos other = (Qos) o;
+        return type == other.type
+                && downlink.equals(other.downlink)
+                && uplink.equals(other.uplink);
+    }
+}
\ No newline at end of file
diff --git a/extphone/src/com/qti/extphone/QosBearerFilter.java b/extphone/src/com/qti/extphone/QosBearerFilter.java
new file mode 100644
index 0000000..a682e63
--- /dev/null
+++ b/extphone/src/com/qti/extphone/QosBearerFilter.java
@@ -0,0 +1,455 @@
+/**
+ * Copyright 2020 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.
+ */
+
+/**
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+import android.net.InetAddresses;
+import android.net.LinkAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class that stores QOS filter parameters as defined in
+ * 3gpp 24.008 10.5.6.12 and 3gpp 24.501 9.11.4.13.
+ */
+public final class QosBearerFilter implements Parcelable {
+    private /* @NonNull */ List<LinkAddress> localAddresses;
+    private /* @NonNull */ List<LinkAddress> remoteAddresses;
+    private /* @Nullable */ PortRange localPort;
+    private /* @Nullable */ PortRange remotePort;
+
+    /**
+     * @hide
+     * @Retention(RetentionPolicy.SOURCE)
+     * @IntDef(prefix = "QOS_PROTOCOL_",
+     *         value = {QOS_PROTOCOL_UNSPECIFIED, QOS_PROTOCOL_TCP, QOS_PROTOCOL_UDP,
+     *                 QOS_PROTOCOL_ESP, QOS_PROTOCOL_AH})
+     */
+    public @interface QosProtocol {}
+
+    public static final int QOS_PROTOCOL_UNSPECIFIED =
+            android.hardware.radio.V1_6.QosProtocol.UNSPECIFIED;
+    public static final int QOS_PROTOCOL_TCP =
+            android.hardware.radio.V1_6.QosProtocol.TCP;
+    public static final int QOS_PROTOCOL_UDP =
+            android.hardware.radio.V1_6.QosProtocol.UDP;
+    public static final int QOS_PROTOCOL_ESP =
+            android.hardware.radio.V1_6.QosProtocol.ESP;
+    public static final int QOS_PROTOCOL_AH =
+            android.hardware.radio.V1_6.QosProtocol.AH;
+    public static final int QOS_MIN_PORT =
+            android.hardware.radio.V1_6.QosPortRange.MIN;
+    /**
+     * Hardcoded in place of android.hardware.radio.V1_6.QosPortRange.MAX as it
+     * returns -1 due to uint16_t to int conversion in java. (TODO: Fix the HAL)
+     */
+    public static final int QOS_MAX_PORT = 65535;
+
+    private @QosProtocol int protocol;
+
+    private int typeOfServiceMask;
+
+    private long flowLabel;
+
+    /** IPSec security parameter index */
+    private long securityParameterIndex;
+
+    /**
+     * @hide
+     * @Retention(RetentionPolicy.SOURCE)
+     * @IntDef(prefix = "QOS_FILTER_DIRECTION_",
+     *         value = {QOS_FILTER_DIRECTION_DOWNLINK, QOS_FILTER_DIRECTION_UPLINK,
+     *                 QOS_FILTER_DIRECTION_BIDIRECTIONAL})
+     */
+    public @interface QosBearerFilterDirection {}
+
+    public static final int QOS_FILTER_DIRECTION_DOWNLINK =
+            android.hardware.radio.V1_6.QosFilterDirection.DOWNLINK;
+    public static final int QOS_FILTER_DIRECTION_UPLINK =
+            android.hardware.radio.V1_6.QosFilterDirection.UPLINK;
+    public static final int QOS_FILTER_DIRECTION_BIDIRECTIONAL =
+            android.hardware.radio.V1_6.QosFilterDirection.BIDIRECTIONAL;
+
+    private @QosBearerFilterDirection int filterDirection;
+
+    /**
+     * Specified the order in which the filter needs to be matched.
+     * A Lower numerical value has a higher precedence.
+     */
+    private int precedence;
+
+    QosBearerFilter() {
+        localAddresses = new ArrayList<>();
+        remoteAddresses = new ArrayList<>();
+        localPort = new PortRange();
+        remotePort = new PortRange();
+        protocol = QOS_PROTOCOL_UNSPECIFIED;
+        filterDirection = QOS_FILTER_DIRECTION_BIDIRECTIONAL;
+    }
+
+    public QosBearerFilter(/* @NonNull */ List<LinkAddress> localAddresses,
+            /* @NonNull */ List<LinkAddress> remoteAddresses, /* @Nullable */ PortRange localPort,
+            /* @Nullable */ PortRange remotePort, @QosProtocol int protocol, int tos,
+            long flowLabel, long spi, @QosBearerFilterDirection int direction, int precedence) {
+        this.localAddresses = localAddresses;
+        this.remoteAddresses = remoteAddresses;
+        this.localPort = localPort;
+        this.remotePort = remotePort;
+        this.protocol = protocol;
+        this.typeOfServiceMask = tos;
+        this.flowLabel = flowLabel;
+        this.securityParameterIndex = spi;
+        this.filterDirection = direction;
+        this.precedence = precedence;
+    }
+
+    // @NonNull
+    public List<LinkAddress> getLocalAddresses() {
+        return localAddresses;
+    }
+
+    // @NonNull
+    public List<LinkAddress> getRemoteAddresses() {
+        return remoteAddresses;
+    }
+
+    // @Nullable
+    public PortRange getLocalPortRange() {
+        return localPort;
+    }
+
+    // @Nullable
+    public PortRange getRemotePortRange() {
+        return remotePort;
+    }
+
+    public int getProtocol() {
+        return protocol;
+    }
+
+    public int getTypeOfServiceMask() {
+        return typeOfServiceMask;
+    }
+
+    public long getFlowLabel() {
+        return flowLabel;
+    }
+
+    public long getSpi() {
+        return securityParameterIndex;
+    }
+
+    public int getDirection() {
+        return filterDirection;
+    }
+
+    public int getPrecedence() {
+        return precedence;
+    }
+
+    /*
+     * @hide
+     * @NonNull
+     */
+    public static QosBearerFilter create(
+            /* @NonNull */ android.hardware.radio.V1_6.QosFilter qosFilter) {
+        QosBearerFilter ret = new QosBearerFilter();
+
+        String[] localAddresses = qosFilter.localAddresses.stream().toArray(String[]::new);
+        if (localAddresses != null) {
+            for (String address : localAddresses) {
+                ret.localAddresses.add(createLinkAddressFromString(address));
+            }
+        }
+
+        String[] remoteAddresses = qosFilter.remoteAddresses.stream().toArray(String[]::new);
+        if (remoteAddresses != null) {
+            for (String address : remoteAddresses) {
+                ret.remoteAddresses.add(createLinkAddressFromString(address));
+            }
+        }
+
+        if (qosFilter.localPort != null) {
+            if (qosFilter.localPort.getDiscriminator()
+                    == android.hardware.radio.V1_6.MaybePort.hidl_discriminator.range) {
+                final android.hardware.radio.V1_6.PortRange portRange =
+                        qosFilter.localPort.range();
+                ret.localPort.start = portRange.start;
+                ret.localPort.end = portRange.end;
+            }
+        }
+
+        if (qosFilter.remotePort != null) {
+            if (qosFilter.remotePort.getDiscriminator()
+                    == android.hardware.radio.V1_6.MaybePort.hidl_discriminator.range) {
+                final android.hardware.radio.V1_6.PortRange portRange
+                        = qosFilter.remotePort.range();
+                ret.remotePort.start = portRange.start;
+                ret.remotePort.end = portRange.end;
+            }
+        }
+
+        ret.protocol = qosFilter.protocol;
+
+        if (qosFilter.tos != null) {
+            if (qosFilter.tos.getDiscriminator()
+                    == android.hardware.radio.V1_6.QosFilter.TypeOfService.
+                            hidl_discriminator.value) {
+                ret.typeOfServiceMask = qosFilter.tos.value();
+            }
+        }
+
+        if (qosFilter.flowLabel != null) {
+            if (qosFilter.flowLabel.getDiscriminator()
+                    == android.hardware.radio.V1_6.QosFilter.Ipv6FlowLabel.
+                            hidl_discriminator.value) {
+                ret.flowLabel = qosFilter.flowLabel.value();
+            }
+        }
+
+        if (qosFilter.spi != null) {
+            if (qosFilter.spi.getDiscriminator()
+                    == android.hardware.radio.V1_6.QosFilter.IpsecSpi.
+                            hidl_discriminator.value) {
+                ret.securityParameterIndex = qosFilter.spi.value();
+            }
+        }
+
+        ret.filterDirection = qosFilter.direction;
+        ret.precedence = qosFilter.precedence;
+
+        return ret;
+    }
+
+    public static class PortRange implements Parcelable {
+        int start;
+        int end;
+
+        PortRange() {
+            start = -1;
+            end = -1;
+        }
+
+        private PortRange(Parcel source) {
+            start = source.readInt();
+            end = source.readInt();
+        }
+
+        public PortRange(int start, int end) {
+            this.start = start;
+            this.end = end;
+        }
+
+        public int getStart() {
+            return start;
+        }
+
+        public int getEnd() {
+            return end;
+        }
+
+        public boolean isValid() {
+            return start >= QOS_MIN_PORT && start <= QOS_MAX_PORT
+                    && end >= QOS_MIN_PORT && end <= QOS_MAX_PORT
+                    && start <= end;
+        }
+
+        @Override
+        public void writeToParcel(/* @NonNull */ Parcel dest, int flags) {
+            dest.writeInt(start);
+            dest.writeInt(end);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        // @NonNull
+        public static final Parcelable.Creator<PortRange> CREATOR =
+                new Parcelable.Creator<PortRange>() {
+                    @Override
+                    public PortRange createFromParcel(Parcel source) {
+                        return new PortRange(source);
+                    }
+
+                    @Override
+                    public PortRange[] newArray(int size) {
+                        return new PortRange[size];
+                    }
+                };
+
+        @Override
+        public String toString() {
+            return "PortRange {"
+                    + " start=" + start
+                    + " end=" + end + "}";
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+
+            if (o == null || !(o instanceof PortRange)) {
+              return false;
+            }
+
+            PortRange other = (PortRange) o;
+            return start == other.start
+                    && end == other.end;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(start, end);
+        }
+    };
+
+    @Override
+    public String toString() {
+        return "QosBearerFilter {"
+                + " localAddresses=" + localAddresses
+                + " remoteAddresses=" + remoteAddresses
+                + " localPort=" + localPort
+                + " remotePort=" + remotePort
+                + " protocol=" + protocol
+                + " typeOfServiceMask=" + typeOfServiceMask
+                + " flowLabel=" + flowLabel
+                + " securityParameterIndex=" + securityParameterIndex
+                + " filterDirection=" + filterDirection
+                + " precedence=" + precedence + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(localAddresses, remoteAddresses, localPort,
+                remotePort, protocol, typeOfServiceMask, flowLabel,
+                securityParameterIndex, filterDirection, precedence);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || !(o instanceof QosBearerFilter)) {
+            return false;
+        }
+
+        QosBearerFilter other = (QosBearerFilter) o;
+
+        return localAddresses.size() == other.localAddresses.size()
+                && localAddresses.containsAll(other.localAddresses)
+                && remoteAddresses.size() == other.remoteAddresses.size()
+                && remoteAddresses.containsAll(other.remoteAddresses)
+                && Objects.equals(localPort, other.localPort)
+                && Objects.equals(remotePort, other.remotePort)
+                && protocol == other.protocol
+                && typeOfServiceMask == other.typeOfServiceMask
+                && flowLabel == other.flowLabel
+                && securityParameterIndex == other.securityParameterIndex
+                && filterDirection == other.filterDirection
+                && precedence == other.precedence;
+    }
+
+    private static LinkAddress createLinkAddressFromString(String addressString) {
+        addressString = addressString.trim();
+        InetAddress address = null;
+        int prefixLength = -1;
+        try {
+            String[] pieces = addressString.split("/", 2);
+            address = InetAddresses.parseNumericAddress(pieces[0]);
+            if (pieces.length == 1) {
+                prefixLength = (address instanceof Inet4Address) ? 32 : 128;
+            } else if (pieces.length == 2) {
+                prefixLength = Integer.parseInt(pieces[1]);
+            }
+        } catch (NullPointerException e) {            // Null string.
+        } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
+        } catch (NumberFormatException e) {           // Non-numeric prefix.
+        } catch (IllegalArgumentException e) {        // Invalid IP address.
+        }
+
+        if (address == null || prefixLength == -1) {
+            throw new IllegalArgumentException("Invalid link address " + addressString);
+        }
+
+        return new LinkAddress(address, prefixLength, 0, 0,
+                LinkAddress.LIFETIME_UNKNOWN, LinkAddress.LIFETIME_UNKNOWN);
+    }
+
+    private QosBearerFilter(Parcel source) {
+        localAddresses = new ArrayList<>();
+        source.readList(localAddresses, LinkAddress.class.getClassLoader());
+        remoteAddresses = new ArrayList<>();
+        source.readList(remoteAddresses, LinkAddress.class.getClassLoader());
+        localPort = source.readParcelable(PortRange.class.getClassLoader());
+        remotePort = source.readParcelable(PortRange.class.getClassLoader());
+        protocol = source.readInt();
+        typeOfServiceMask = source.readInt();
+        flowLabel = source.readLong();
+        securityParameterIndex = source.readLong();
+        filterDirection = source.readInt();
+        precedence = source.readInt();
+    }
+
+    @Override
+    public void writeToParcel(/* @NonNull */ Parcel dest, int flags) {
+        dest.writeList(localAddresses);
+        dest.writeList(remoteAddresses);
+        dest.writeParcelable(localPort, flags);
+        dest.writeParcelable(remotePort, flags);
+        dest.writeInt(protocol);
+        dest.writeInt(typeOfServiceMask);
+        dest.writeLong(flowLabel);
+        dest.writeLong(securityParameterIndex);
+        dest.writeInt(filterDirection);
+        dest.writeInt(precedence);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // @NonNull
+    public static final Parcelable.Creator<QosBearerFilter> CREATOR =
+            new Parcelable.Creator<QosBearerFilter>() {
+                @Override
+                public QosBearerFilter createFromParcel(Parcel source) {
+                    return new QosBearerFilter(source);
+                }
+
+                @Override
+                public QosBearerFilter[] newArray(int size) {
+                    return new QosBearerFilter[size];
+                }
+            };
+}
diff --git a/extphone/src/com/qti/extphone/QosBearerSession.java b/extphone/src/com/qti/extphone/QosBearerSession.java
new file mode 100644
index 0000000..da3261a
--- /dev/null
+++ b/extphone/src/com/qti/extphone/QosBearerSession.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright 2020 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.
+ */
+
+/**
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * Class that stores information specific to QOS session.
+ */
+public final class QosBearerSession implements Parcelable{
+
+    final int qosBearerSessionId;
+    final Qos qos;
+    final List<QosBearerFilter> qosBearerFilterList;
+
+    public QosBearerSession(int qosBearerSessionId,
+                            /* @NonNull */ Qos qos,
+                            /* @NonNull */ List<QosBearerFilter> qosBearerFilterList) {
+        this.qosBearerSessionId = qosBearerSessionId;
+        this.qos = qos;
+        this.qosBearerFilterList = qosBearerFilterList;
+    }
+
+    private QosBearerSession(Parcel source) {
+        qosBearerSessionId = source.readInt();
+        qos = source.readParcelable(Qos.class.getClassLoader());
+        qosBearerFilterList = new ArrayList<>();
+        source.readList(qosBearerFilterList, QosBearerFilter.class.getClassLoader());
+    }
+
+    public int getQosBearerSessionId() {
+        return qosBearerSessionId;
+    }
+
+    public Qos getQos() {
+        return qos;
+    }
+
+    public List<QosBearerFilter> getQosBearerFilterList() {
+        return qosBearerFilterList;
+    }
+
+    @Override
+    public void writeToParcel(/* @NonNull */ Parcel dest, int flags) {
+        dest.writeInt(qosBearerSessionId);
+        if (qos.getType() == Qos.QOS_TYPE_EPS) {
+            dest.writeParcelable((EpsQos)qos, flags);
+        } else {
+            dest.writeParcelable((NrQos)qos, flags);
+        }
+        dest.writeList(qosBearerFilterList);
+    }
+
+    // @NonNull
+    public static QosBearerSession create(
+            /* @NonNull */ android.hardware.radio.V1_6.QosSession qosSession) {
+        List<QosBearerFilter> qosBearerFilters = new ArrayList<>();
+
+        if (qosSession.qosFilters != null) {
+            for (android.hardware.radio.V1_6.QosFilter filter : qosSession.qosFilters) {
+                qosBearerFilters.add(QosBearerFilter.create(filter));
+            }
+        }
+
+        return new QosBearerSession(
+                        qosSession.qosSessionId,
+                        Qos.create(qosSession.qos),
+                        qosBearerFilters);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "QosBearerSession {"
+                + " qosBearerSessionId=" + qosBearerSessionId
+                + " qos=" + qos
+                + " qosBearerFilterList=" + qosBearerFilterList + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(qosBearerSessionId, qos, qosBearerFilterList);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || !(o instanceof QosBearerSession)) {
+            return false;
+        }
+
+        QosBearerSession other = (QosBearerSession) o;
+        return this.qosBearerSessionId == other.qosBearerSessionId
+                && this.qos.equals(other.qos)
+                && this.qosBearerFilterList.size() == other.qosBearerFilterList.size()
+                && this.qosBearerFilterList.containsAll(other.qosBearerFilterList);
+    }
+
+
+    // @NonNull
+    public static final Parcelable.Creator<QosBearerSession> CREATOR =
+            new Parcelable.Creator<QosBearerSession>() {
+                @Override
+                public QosBearerSession createFromParcel(Parcel source) {
+                    return new QosBearerSession(source);
+                }
+
+                @Override
+                public QosBearerSession[] newArray(int size) {
+                    return new QosBearerSession[size];
+                }
+            };
+}
diff --git a/extphone/src/com/qti/extphone/QosParametersResult.aidl b/extphone/src/com/qti/extphone/QosParametersResult.aidl
new file mode 100644
index 0000000..7867243
--- /dev/null
+++ b/extphone/src/com/qti/extphone/QosParametersResult.aidl
@@ -0,0 +1,8 @@
+/**
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+parcelable QosParametersResult;
\ No newline at end of file
diff --git a/extphone/src/com/qti/extphone/QosParametersResult.java b/extphone/src/com/qti/extphone/QosParametersResult.java
new file mode 100644
index 0000000..ac8fca3
--- /dev/null
+++ b/extphone/src/com/qti/extphone/QosParametersResult.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+package com.qti.extphone;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class QosParametersResult implements Parcelable {
+
+    private static final String TAG = "QosParametersResult";
+
+    public static final int QOS_TYPE_EPS = Qos.QOS_TYPE_EPS;
+    public static final int QOS_TYPE_NR = Qos.QOS_TYPE_NR;
+
+    private final Qos mDefaultQos;
+    private final List<QosBearerSession> mQosBearerSessions;
+
+    public QosParametersResult() {
+        mDefaultQos = null;
+        mQosBearerSessions = new ArrayList<>();
+    }
+
+
+    public QosParametersResult(/* @Nullable */ Qos defaultQos,
+                               /* @Nullable */  List<QosBearerSession> qosBearerSessions) {
+        mDefaultQos = defaultQos;
+        mQosBearerSessions = (qosBearerSessions == null)
+                ? new ArrayList<>() : new ArrayList<>(qosBearerSessions);
+    }
+
+    public QosParametersResult(Parcel source) {
+        mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
+        mQosBearerSessions = new ArrayList<>();
+        source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader());
+    }
+
+    /**
+     * @return default QOS of the data connection received from the network
+     *
+     * @hide
+     * @Nullable
+     */
+    public Qos getDefaultQos() {
+        return mDefaultQos;
+    }
+
+    /**
+     * @return All the dedicated bearer QOS sessions of the data connection received from the
+     * network.
+     *
+     * @hide
+     * @NonNull
+     */
+    public List<QosBearerSession> getQosBearerSessions() {
+        return mQosBearerSessions;
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("QosParametersResult: {")
+           .append(" defaultQos=").append(mDefaultQos)
+           .append(" qosBearerSessions=").append(mQosBearerSessions)
+           .append("}");
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(/* @Nullable */ Object o) {
+        if (this == o) return true;
+
+        if (!(o instanceof QosParametersResult)) {
+            return false;
+        }
+
+        QosParametersResult other = (QosParametersResult) o;
+
+        final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null)
+                ? mDefaultQos == other.mDefaultQos
+                : mDefaultQos.equals(other.mDefaultQos);
+
+        final boolean isQosBearerSessionsSame =
+                (mQosBearerSessions == null || other.mQosBearerSessions == null)
+                ? mQosBearerSessions == other.mQosBearerSessions
+                : mQosBearerSessions.size() == other.mQosBearerSessions.size()
+                && mQosBearerSessions.containsAll(other.mQosBearerSessions);
+
+        return isQosSame && isQosBearerSessionsSame;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mDefaultQos, mQosBearerSessions);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mDefaultQos != null) {
+            if (mDefaultQos.getType() == Qos.QOS_TYPE_EPS) {
+                dest.writeParcelable((EpsQos) mDefaultQos, flags);
+            } else {
+                dest.writeParcelable((NrQos) mDefaultQos, flags);
+            }
+        } else {
+            dest.writeParcelable(null, flags);
+        }
+        dest.writeList(mQosBearerSessions);
+    }
+
+    // @NonNull
+    public static final Parcelable.Creator<QosParametersResult> CREATOR =
+            new Parcelable.Creator<QosParametersResult>() {
+                @Override
+                public QosParametersResult createFromParcel(Parcel source) {
+                    return new QosParametersResult(source);
+                }
+
+                @Override
+                public QosParametersResult[] newArray(int size) {
+                    return new QosParametersResult[size];
+                }
+            };
+
+    /**
+     * Provides a convenient way to set the fields of a {@link QosParametersResult} when
+     * creating a new instance.
+     *
+     * <p>The example below shows how you might create a new {@code QosParametersResult}:
+     *
+     * <pre><code>
+     *
+     * QosParametersResult response = new QosParametersResult.Builder()
+     *     .setAddresses(Arrays.asList("192.168.1.2"))
+     *     .setProtocolType(ApnSetting.PROTOCOL_IPV4V6)
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        private Qos mDefaultQos;
+        private List<QosBearerSession> mQosBearerSessions = new ArrayList<>();
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Set the default QOS for this data connection.
+         *
+         * @param defaultQos QOS (Quality Of Service) received from network.
+         *
+         * @return The same instance of the builder.
+         *
+         * @hide
+         * @NonNull
+         */
+        public Builder setDefaultQos(/* Nullable */ Qos defaultQos) {
+            mDefaultQos = defaultQos;
+            return this;
+        }
+
+        /**
+         * Set the dedicated bearer QOS sessions for this data connection.
+         *
+         * @param qosBearerSessions Dedicated bearer QOS (Quality Of Service) sessions received
+         * from network.
+         *
+         * @return The same instance of the builder.
+         *
+         * @hide
+         * @NonNull
+         */
+        public Builder setQosBearerSessions(
+                /* @NonNull */ List<QosBearerSession> qosBearerSessions) {
+            mQosBearerSessions = qosBearerSessions;
+            return this;
+        }
+
+       /**
+         * Build the QosParametersResult.
+         *
+         * @return the QosParametersResult object.
+         * @NonNull
+         */
+        public QosParametersResult build() {
+            return new QosParametersResult(mDefaultQos, mQosBearerSessions);
+        }
+    }
+}
\ No newline at end of file