Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66c8e691 authored by Jordan Liu's avatar Jordan Liu Committed by Android (Google) Code Review
Browse files

Merge "Send call quality metrics"

parents 57863485 3482cf4f
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.dataconnection.DataEnabledSettings;
import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.metrics.CallQualityMetrics;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
@@ -114,6 +115,7 @@ import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
@@ -151,6 +153,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            new MmTelFeature.MmTelCapabilities();

    private TelephonyMetrics mMetrics;
    private final Map<String, CallQualityMetrics> mCallQualityMetrics = new ConcurrentHashMap<>();
    private final ConcurrentLinkedQueue<String> mLeastRecentCallId = new ConcurrentLinkedQueue<>();
    private boolean mCarrierConfigLoaded = false;

    private final MmTelFeatureListener mMmTelFeatureListener = new MmTelFeatureListener();
@@ -278,6 +282,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    static final int MAX_CONNECTIONS = 7;
    static final int MAX_CONNECTIONS_PER_CALL = 5;

    // Max number of calls we will keep call quality history for (the history is saved in-memory and
    // included in bug reports).
    private static final int MAX_CALL_QUALITY_HISTORY = 10;

    private static final int EVENT_HANGUP_PENDINGMO = 18;
    private static final int EVENT_DIAL_PENDINGMO = 20;
    private static final int EVENT_EXIT_ECBM_BEFORE_PENDINGMO = 21;
@@ -2322,8 +2330,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
                cause = DisconnectCause.IMS_MERGED_SUCCESSFULLY;
            }

            String callId = imsCall.getSession().getCallId();
            mMetrics.writeOnImsCallTerminated(mPhone.getPhoneId(), imsCall.getCallSession(),
                    reasonInfo);
                    reasonInfo, mCallQualityMetrics.get(callId));
            pruneCallQualityMetricsHistory();
            mPhone.notifyImsReason(reasonInfo);

            if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL
@@ -2951,6 +2961,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            // convert ServiceState.radioTech to TelephonyManager.NetworkType constant
            mPhone.onCallQualityChanged(callQuality,
                    ServiceState.rilRadioTechnologyToNetworkType(imsCall.getRadioTechnology()));
            String callId = imsCall.getSession().getCallId();
            CallQualityMetrics cqm = mCallQualityMetrics.get(callId);
            if (cqm == null) {
                cqm = new CallQualityMetrics(mPhone);
                mLeastRecentCallId.add(callId);
            }
            cqm.saveCallQuality(callQuality);
            mCallQualityMetrics.put(callId, cqm);
        }
    };

@@ -3503,6 +3521,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        pw.println(" mDefaultDialerUid=" + mDefaultDialerUid.get());
        pw.println(" mVtDataUsageSnapshot=" + mVtDataUsageSnapshot);
        pw.println(" mVtDataUsageUidSnapshot=" + mVtDataUsageUidSnapshot);
        pw.println(" mCallQualityMetrics=" + mCallQualityMetrics);

        pw.flush();
        pw.println("++++++++++++++++++++++++++++++++");
@@ -4079,6 +4098,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        mIsDataEnabled = isDataEnabled;
    }

    // Removes old call quality metrics if mCallQualityMetrics exceeds its max size
    private void pruneCallQualityMetricsHistory() {
        if (mCallQualityMetrics.size() > MAX_CALL_QUALITY_HISTORY) {
            mCallQualityMetrics.remove(mLeastRecentCallId.poll());
        }
    }

    private void handleFeatureCapabilityChanged(ImsFeature.Capabilities capabilities) {
        boolean tmpIsVideoCallEnabled = isVideoCallEnabled();
        // Check enabledFeatures to determine capabilities. We ignore disabledFeatures.
+345 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 com.android.internal.telephony.metrics;

import static com.android.internal.telephony.metrics.TelephonyMetrics.toCallQualityProto;

import android.os.Build;
import android.telephony.CallQuality;
import android.telephony.CellInfo;
import android.telephony.CellSignalStrengthLte;
import android.telephony.Rlog;
import android.telephony.SignalStrength;
import android.util.Pair;

import com.android.internal.telephony.Phone;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;

import java.util.ArrayList;

/**
 * CallQualityMetrics is a utility for tracking the CallQuality during an ongoing call session. It
 * processes snapshots throughout the call to keep track of info like the best and worst
 * ServiceStates, durations of good and bad quality, and other summary statistics.
 */
public class CallQualityMetrics {

    private static final String TAG = CallQualityMetrics.class.getSimpleName();

    // certain metrics are only logged on userdebug
    private static final boolean USERDEBUG_MODE = Build.IS_USERDEBUG;

    // We only log the first MAX_SNAPSHOTS changes to CallQuality
    private static final int MAX_SNAPSHOTS = 5;

    // value of mCallQualityState which means the CallQuality is EXCELLENT/GOOD/FAIR
    private static final int GOOD_QUALITY = 0;

    // value of mCallQualityState which means the CallQuality is BAD/POOR
    private static final int BAD_QUALITY = 1;

    private Phone mPhone;

    /** Snapshots of the call quality and SignalStrength (LTE-SNR for IMS calls) */
    // mUlSnapshots holds snapshots from uplink call quality changes. We log take snapshots of the
    // first MAX_SNAPSHOTS transitions between good and bad quality
    private ArrayList<Pair<CallQuality, Integer>> mUlSnapshots = new ArrayList<>();
    // mDlSnapshots holds snapshots from downlink call quality changes. We log take snapshots of
    // the first MAX_SNAPSHOTS transitions between good and bad quality
    private ArrayList<Pair<CallQuality, Integer>> mDlSnapshots = new ArrayList<>();

    // Current downlink call quality
    private int mDlCallQualityState = GOOD_QUALITY;

    // Current uplink call quality
    private int mUlCallQualityState = GOOD_QUALITY;

    // The last logged CallQuality
    private CallQuality mLastCallQuality;

    /** Snapshots taken at best and worst SignalStrengths*/
    private Pair<CallQuality, Integer> mWorstSsWithGoodDlQuality;
    private Pair<CallQuality, Integer> mBestSsWithGoodDlQuality;
    private Pair<CallQuality, Integer> mWorstSsWithBadDlQuality;
    private Pair<CallQuality, Integer> mBestSsWithBadDlQuality;
    private Pair<CallQuality, Integer> mWorstSsWithGoodUlQuality;
    private Pair<CallQuality, Integer> mBestSsWithGoodUlQuality;
    private Pair<CallQuality, Integer> mWorstSsWithBadUlQuality;
    private Pair<CallQuality, Integer> mBestSsWithBadUlQuality;

    /** Total durations of good and bad quality time for uplink and downlink */
    private int mTotalDlGoodQualityTimeMs = 0;
    private int mTotalDlBadQualityTimeMs = 0;
    private int mTotalUlGoodQualityTimeMs = 0;
    private int mTotalUlBadQualityTimeMs = 0;

    /**
     * Construct a CallQualityMetrics object to be used to keep track of call quality for a single
     * call session.
     */
    public CallQualityMetrics(Phone phone) {
        mPhone = phone;
        mLastCallQuality = new CallQuality();
    }

    /**
     * Called when call quality changes.
     */
    public void saveCallQuality(CallQuality cq) {
        if (cq.getUplinkCallQualityLevel() == CallQuality.CALL_QUALITY_NOT_AVAILABLE
                || cq.getDownlinkCallQualityLevel() == CallQuality.CALL_QUALITY_NOT_AVAILABLE) {
            return;
        }

        // uplink and downlink call quality are tracked separately
        int newUlCallQualityState = BAD_QUALITY;
        int newDlCallQualityState = BAD_QUALITY;
        if (isGoodQuality(cq.getUplinkCallQualityLevel())) {
            newUlCallQualityState = GOOD_QUALITY;
        }
        if (isGoodQuality(cq.getDownlinkCallQualityLevel())) {
            newDlCallQualityState = GOOD_QUALITY;
        }

        if (USERDEBUG_MODE) {
            if (newUlCallQualityState != mUlCallQualityState) {
                mUlSnapshots = addSnapshot(cq, mUlSnapshots);
            }
            if (newDlCallQualityState != mDlCallQualityState) {
                mDlSnapshots = addSnapshot(cq, mDlSnapshots);
            }
        }

        updateTotalDurations(newDlCallQualityState, newUlCallQualityState, cq);

        updateMinAndMaxSignalStrengthSnapshots(newDlCallQualityState, newUlCallQualityState, cq);

        mUlCallQualityState = newUlCallQualityState;
        mDlCallQualityState = newDlCallQualityState;
        mLastCallQuality = cq;
    }

    private static boolean isGoodQuality(int callQualityLevel) {
        return callQualityLevel < CallQuality.CALL_QUALITY_BAD;
    }

    /**
     * Save a snapshot of the call quality and signal strength. This can be called with uplink or
     * downlink call quality level.
     */
    private ArrayList<Pair<CallQuality, Integer>> addSnapshot(CallQuality cq,
            ArrayList<Pair<CallQuality, Integer>> snapshots) {
        if (snapshots.size() < MAX_SNAPSHOTS) {
            Integer ss = getLteSnr();
            snapshots.add(Pair.create(cq, ss));
        }
        return snapshots;
    }

    /**
     * Updates the running total duration of good and bad call quality for uplink and downlink.
     */
    private void updateTotalDurations(int newDlCallQualityState, int newUlCallQualityState,
            CallQuality cq) {
        int timePassed = cq.getCallDuration() - mLastCallQuality.getCallDuration();
        if (newDlCallQualityState == GOOD_QUALITY) {
            mTotalDlGoodQualityTimeMs += timePassed;
        } else {
            mTotalDlBadQualityTimeMs += timePassed;
        }

        if (newUlCallQualityState == GOOD_QUALITY) {
            mTotalUlGoodQualityTimeMs += timePassed;
        } else {
            mTotalUlBadQualityTimeMs += timePassed;
        }
    }

    /**
     * Updates the snapshots saved when signal strength is highest and lowest while the call quality
     * is good and bad for both uplink and downlink call quality.
     * <p>
     * At the end of the call we should have:
     *  - for both UL and DL:
     *     - snapshot of the best signal strength with bad call quality
     *     - snapshot of the worst signal strength with bad call quality
     *     - snapshot of the best signal strength with good call quality
     *     - snapshot of the worst signal strength with good call quality
     */
    private void updateMinAndMaxSignalStrengthSnapshots(int newDlCallQualityState,
            int newUlCallQualityState, CallQuality cq) {
        Integer ss = getLteSnr();
        if (ss.equals(CellInfo.UNAVAILABLE)) {
            return;
        }

        // downlink
        if (newDlCallQualityState == GOOD_QUALITY) {
            if (mWorstSsWithGoodDlQuality == null || ss < mWorstSsWithGoodDlQuality.second) {
                mWorstSsWithGoodDlQuality = Pair.create(cq, ss);
            }
            if (mBestSsWithGoodDlQuality == null || ss > mBestSsWithGoodDlQuality.second) {
                mBestSsWithGoodDlQuality = Pair.create(cq, ss);
            }
        } else {
            if (mWorstSsWithBadDlQuality == null || ss < mWorstSsWithBadDlQuality.second) {
                mWorstSsWithBadDlQuality = Pair.create(cq, ss);
            }
            if (mBestSsWithBadDlQuality == null || ss > mBestSsWithBadDlQuality.second) {
                mBestSsWithBadDlQuality = Pair.create(cq, ss);
            }
        }

        // uplink
        if (newUlCallQualityState == GOOD_QUALITY) {
            if (mWorstSsWithGoodUlQuality == null || ss < mWorstSsWithGoodUlQuality.second) {
                mWorstSsWithGoodUlQuality = Pair.create(cq, ss);
            }
            if (mBestSsWithGoodUlQuality == null || ss > mBestSsWithGoodUlQuality.second) {
                mBestSsWithGoodUlQuality = Pair.create(cq, ss);
            }
        } else {
            if (mWorstSsWithBadUlQuality == null || ss < mWorstSsWithBadUlQuality.second) {
                mWorstSsWithBadUlQuality = Pair.create(cq, ss);
            }
            if (mBestSsWithBadUlQuality == null || ss > mBestSsWithBadUlQuality.second) {
                mBestSsWithBadUlQuality = Pair.create(cq, ss);
            }
        }
    }

    // Returns the LTE signal to noise ratio, or 0 if unavailable
    private Integer getLteSnr() {
        ServiceStateTracker sst = mPhone.getServiceStateTracker();
        if (sst == null) {
            Rlog.e(TAG, "getLteSnr: unable to get SST for phone " + mPhone.getPhoneId());
            return CellInfo.UNAVAILABLE;
        }

        SignalStrength ss = sst.getSignalStrength();
        if (ss == null) {
            Rlog.e(TAG, "getLteSnr: unable to get SignalStrength for phone " + mPhone.getPhoneId());
            return CellInfo.UNAVAILABLE;
        }

        // There may be multiple CellSignalStrengthLte, so try to use one with available SNR
        for (CellSignalStrengthLte lteSs : ss.getCellSignalStrengths(CellSignalStrengthLte.class)) {
            int snr = lteSs.getRssnr();
            if (snr != CellInfo.UNAVAILABLE) {
                return snr;
            }
        }

        return CellInfo.UNAVAILABLE;
    }

    private static TelephonyCallSession.Event.SignalStrength toProto(int ss) {
        TelephonyCallSession.Event.SignalStrength ret =
                new TelephonyCallSession.Event.SignalStrength();
        ret.lteSnr = ss;
        return ret;
    }

    /**
     * Return the full downlink CallQualitySummary using the saved CallQuality records.
     */
    public TelephonyCallSession.Event.CallQualitySummary getCallQualitySummaryDl() {
        TelephonyCallSession.Event.CallQualitySummary summary =
                new TelephonyCallSession.Event.CallQualitySummary();
        summary.totalGoodQualityDurationInSeconds = mTotalDlGoodQualityTimeMs / 1000;
        summary.totalBadQualityDurationInSeconds = mTotalDlBadQualityTimeMs / 1000;
        // This value could be different from mLastCallQuality.getCallDuration if we support
        // handover from IMS->CS->IMS, but this is currently not possible
        // TODO(b/130302396) this also may be possible when we put a call on hold and continue with
        // another call
        summary.totalDurationWithQualityInformationInSeconds = mLastCallQuality.getCallDuration();
        summary.snapshotOfWorstSsWithGoodQuality =
                toCallQualityProto(mWorstSsWithGoodDlQuality.first);
        summary.snapshotOfBestSsWithGoodQuality =
                toCallQualityProto(mBestSsWithGoodDlQuality.first);
        summary.snapshotOfWorstSsWithBadQuality =
                toCallQualityProto(mWorstSsWithBadDlQuality.first);
        summary.snapshotOfBestSsWithBadQuality = toCallQualityProto(mBestSsWithBadDlQuality.first);
        summary.worstSsWithGoodQuality = toProto(mWorstSsWithGoodDlQuality.second);
        summary.bestSsWithGoodQuality = toProto(mBestSsWithGoodDlQuality.second);
        summary.worstSsWithBadQuality = toProto(mWorstSsWithBadDlQuality.second);
        summary.bestSsWithBadQuality = toProto(mBestSsWithBadDlQuality.second);
        summary.snapshotOfEnd = toCallQualityProto(mLastCallQuality);
        return summary;
    }

    /**
     * Return the full uplink CallQualitySummary using the saved CallQuality records.
     */
    public TelephonyCallSession.Event.CallQualitySummary getCallQualitySummaryUl() {
        TelephonyCallSession.Event.CallQualitySummary summary =
                new TelephonyCallSession.Event.CallQualitySummary();
        summary.totalGoodQualityDurationInSeconds = mTotalUlGoodQualityTimeMs / 1000;
        summary.totalBadQualityDurationInSeconds = mTotalUlBadQualityTimeMs / 1000;
        // This value could be different from mLastCallQuality.getCallDuration if we support
        // handover from IMS->CS->IMS, but this is currently not possible
        // TODO(b/130302396) this also may be possible when we put a call on hold and continue with
        // another call
        summary.totalDurationWithQualityInformationInSeconds = mLastCallQuality.getCallDuration();
        summary.snapshotOfWorstSsWithGoodQuality =
                toCallQualityProto(mWorstSsWithGoodUlQuality.first);
        summary.snapshotOfBestSsWithGoodQuality =
                toCallQualityProto(mBestSsWithGoodUlQuality.first);
        summary.snapshotOfWorstSsWithBadQuality =
                toCallQualityProto(mWorstSsWithBadUlQuality.first);
        summary.snapshotOfBestSsWithBadQuality = toCallQualityProto(mBestSsWithBadUlQuality.first);
        summary.worstSsWithGoodQuality = toProto(mWorstSsWithGoodUlQuality.second);
        summary.bestSsWithGoodQuality = toProto(mBestSsWithGoodUlQuality.second);
        summary.worstSsWithBadQuality = toProto(mWorstSsWithBadUlQuality.second);
        summary.bestSsWithBadQuality = toProto(mBestSsWithBadUlQuality.second);
        summary.snapshotOfEnd = toCallQualityProto(mLastCallQuality);
        return summary;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[CallQualityMetrics phone ");
        sb.append(mPhone.getPhoneId());
        sb.append(" mUlSnapshots: {");
        for (Pair<CallQuality, Integer> snapshot : mUlSnapshots) {
            sb.append(" {");
            sb.append(snapshot.first);
            sb.append("}");
        }
        sb.append("}");
        sb.append(" mDlSnapshots:{");
        for (Pair<CallQuality, Integer> snapshot : mDlSnapshots) {
            sb.append(" {");
            sb.append(snapshot.first);
            sb.append("}");
        }
        sb.append("}");
        sb.append(" ");
        sb.append(" mTotalDlGoodQualityTimeMs: ");
        sb.append(mTotalDlGoodQualityTimeMs);
        sb.append(" mTotalDlBadQualityTimeMs: ");
        sb.append(mTotalDlBadQualityTimeMs);
        sb.append(" mTotalUlGoodQualityTimeMs: ");
        sb.append(mTotalUlGoodQualityTimeMs);
        sb.append(" mTotalUlBadQualityTimeMs: ");
        sb.append(mTotalUlBadQualityTimeMs);
        sb.append("]");
        return sb.toString();
    }
}
+65 −6
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.os.Build;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Telephony.Sms.Intents;
import android.telephony.CallQuality;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsManager;
@@ -1988,6 +1989,53 @@ public class TelephonyMetrics {
        return ri;
    }

    /**
     * Convert CallQuality to proto.
     *
     * @param callQuality call quality to convert
     * @return Coverted proto
     */
    public static TelephonyCallSession.Event.CallQuality toCallQualityProto(
            CallQuality callQuality) {
        TelephonyCallSession.Event.CallQuality cq = new TelephonyCallSession.Event.CallQuality();
        if (callQuality != null) {
            cq.downlinkLevel = callQualityLevelToProtoEnum(callQuality
                    .getDownlinkCallQualityLevel());
            cq.uplinkLevel = callQualityLevelToProtoEnum(callQuality.getUplinkCallQualityLevel());
            // callDuration is reported in millis, so convert to seconds
            cq.durationInSeconds = callQuality.getCallDuration() / 1000;
            cq.rtpPacketsTransmitted = callQuality.getNumRtpPacketsTransmitted();
            cq.rtpPacketsReceived = callQuality.getNumRtpPacketsReceived();
            cq.rtpPacketsTransmittedLost = callQuality.getNumRtpPacketsTransmittedLost();
            cq.rtpPacketsNotReceived = callQuality.getNumRtpPacketsNotReceived();
            cq.averageRelativeJitterMillis = callQuality.getAverageRelativeJitter();
            cq.maxRelativeJitterMillis = callQuality.getMaxRelativeJitter();
            cq.codecType = convertImsCodec(callQuality.getCodecType());
        }
        return cq;
    }

    /**
     * Convert Call quality level into proto defined value.
     */
    private static int callQualityLevelToProtoEnum(int level) {
        if (level == CallQuality.CALL_QUALITY_EXCELLENT) {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.EXCELLENT;
        } else if (level == CallQuality.CALL_QUALITY_GOOD) {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.GOOD;
        } else if (level == CallQuality.CALL_QUALITY_FAIR) {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.FAIR;
        } else if (level == CallQuality.CALL_QUALITY_POOR) {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.POOR;
        } else if (level == CallQuality.CALL_QUALITY_BAD) {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.BAD;
        } else if (level == CallQuality.CALL_QUALITY_NOT_AVAILABLE) {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.NOT_AVAILABLE;
        } else {
            return TelephonyCallSession.Event.CallQuality.CallQualityLevel.UNDEFINED;
        }
    }

    /**
     * Write IMS call end event
     *
@@ -1996,17 +2044,28 @@ public class TelephonyMetrics {
     * @param reasonInfo Call end reason
     */
    public void writeOnImsCallTerminated(int phoneId, ImsCallSession session,
                                         ImsReasonInfo reasonInfo) {
                                         ImsReasonInfo reasonInfo, CallQualityMetrics cqm) {
        InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
        if (callSession == null) {
            Rlog.e(TAG, "Call session is missing");
        } else {
            if (cqm != null) {
                callSession.addEvent(
                    new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED)
                        new CallSessionEventBuilder(
                                TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED)
                        .setCallIndex(getCallId(session))
                        .setImsReasonInfo(toImsReasonInfoProto(reasonInfo))
                        .setCallQualitySummaryDl(cqm.getCallQualitySummaryDl())
                        .setCallQualitySummaryUl(cqm.getCallQualitySummaryUl()));
            } else {
                callSession.addEvent(
                        new CallSessionEventBuilder(
                                TelephonyCallSession.Event.Type.IMS_CALL_TERMINATED)
                        .setCallIndex(getCallId(session))
                        .setImsReasonInfo(toImsReasonInfoProto(reasonInfo)));
            }
        }
    }

    /**
     * Write IMS call hangover event
@@ -2394,7 +2453,7 @@ public class TelephonyMetrics {
     * @param c IMS codec value
     * @return Codec value defined in call session proto
     */
    private int convertImsCodec(int c) {
    private static int convertImsCodec(int c) {
        switch (c) {
            case ImsStreamMediaProfile.AUDIO_QUALITY_AMR:
                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR;
+1 −0
Original line number Diff line number Diff line
@@ -174,6 +174,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        }).when(imsCall).hold();

        imsCall.attachSession(mImsCallSession);
        doReturn("1").when(mImsCallSession).getCallId();
    }

    @Before