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

Commit 4d15f772 authored by Youming Ye's avatar Youming Ye Committed by android-build-merger
Browse files

Merge "Cache the connectTime when merging calls into a conference."

am: 6d52d692

Change-Id: I8095669a90e3eb726cb1c320bff254e496adf69f
parents c306319b 6d52d692
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.telephony.imsphone;

import static com.android.internal.telephony.Phone.CS_FALLBACK;

import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -52,6 +53,7 @@ import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
@@ -109,6 +111,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

@@ -290,6 +295,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {

    private static final int TIMEOUT_REDIAL_WIFI_E911_MS = 10000;

    private static final int TIMEOUT_PARTICIPANT_CONNECT_TIME_CACHE_MS = 60000; //ms

    // Following values are for mHoldSwitchingState
    private enum HoldSwapState {
        // Not in the middle of a hold/swap operation
@@ -323,6 +330,20 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    // Hold aggregated video call data usage for each video call since boot.
    // The ImsCall's call id is the key of the map.
    private final HashMap<Integer, Long> mVtDataUsageMap = new HashMap<>();
    private final Map<String, CacheEntry> mPhoneNumAndConnTime = new ConcurrentHashMap<>();
    private final Queue<CacheEntry> mUnknownPeerConnTime = new LinkedBlockingQueue<>();

    private static class CacheEntry {
        private long mCachedTime;
        private long mConnectTime;
        private long mConnectElapsedTime;

        CacheEntry(long cachedTime, long connectTime, long connectElapsedTime) {
            mCachedTime = cachedTime;
            mConnectTime = connectTime;
            mConnectElapsedTime = connectElapsedTime;
        }
    }

    private volatile NetworkStats mVtDataUsageSnapshot = null;
    private volatile NetworkStats mVtDataUsageUidSnapshot = null;
@@ -1247,6 +1268,79 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        }
    }

    // Clean up expired cache entries.
    private void maintainConnectTimeCache() {
        long threshold = SystemClock.elapsedRealtime() - TIMEOUT_PARTICIPANT_CONNECT_TIME_CACHE_MS;
        // The cached time is the system elapsed millisecond when the CacheEntry is created.
        mPhoneNumAndConnTime.entrySet().removeIf(e -> e.getValue().mCachedTime < threshold);
        // Remove all the cached records which are older than current caching threshold. Since the
        // queue is FIFO, keep polling records until the queue is empty or the head of the queue is
        // fresh enough.
        while (!mUnknownPeerConnTime.isEmpty()
                && mUnknownPeerConnTime.peek().mCachedTime < threshold) {
            mUnknownPeerConnTime.poll();
        }
    }

    private void cacheConnectionTimeWithPhoneNumber(@NonNull ImsPhoneConnection connection) {
        CacheEntry cachedConnectTime = new CacheEntry(SystemClock.elapsedRealtime(),
                connection.getConnectTime(), connection.getConnectTimeReal());
        maintainConnectTimeCache();
        if (PhoneConstants.PRESENTATION_ALLOWED == connection.getNumberPresentation()) {
            // In case of merging calls with the same number, use the latest connect time. Since
            // that call might be dropped and re-connected. So if the connectTime is earlier than
            // the cache, skip.
            String phoneNumber = getFormattedPhoneNumber(connection.getAddress());
            if (mPhoneNumAndConnTime.containsKey(phoneNumber)
                    && connection.getConnectTime()
                        <= mPhoneNumAndConnTime.get(phoneNumber).mConnectTime) {
                // Use the latest connect time.
                return;
            }
            mPhoneNumAndConnTime.put(phoneNumber, cachedConnectTime);
        } else {
            mUnknownPeerConnTime.add(cachedConnectTime);
        }
    }

    private CacheEntry findConnectionTimeUsePhoneNumber(
            @NonNull ConferenceParticipant participant) {
        maintainConnectTimeCache();
        if (PhoneConstants.PRESENTATION_ALLOWED == participant.getParticipantPresentation()) {
            if (participant.getHandle() == null
                    || participant.getHandle().getSchemeSpecificPart() == null) {
                return null;
            }

            String numParts = PhoneNumberUtils
                    .extractNetworkPortion(participant.getHandle().getSchemeSpecificPart());
            if (TextUtils.isEmpty(numParts)) {
                return null;
            }

            String formattedNumber = getFormattedPhoneNumber(numParts);
            return mPhoneNumAndConnTime.get(formattedNumber);
        } else {
            return mUnknownPeerConnTime.poll();
        }
    }

    private String getFormattedPhoneNumber(String number) {
        String countryIso = getCountryIso();
        if (countryIso == null) {
            return number;
        }
        String phoneNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
        return phoneNumber == null ? number : phoneNumber;
    }

    private String getCountryIso() {
        int subId = mPhone.getSubId();
        SubscriptionInfo info =
                SubscriptionManager.from(mPhone.getContext()).getActiveSubscriptionInfo(subId);
        return info == null ? null : info.getCountryIso();
    }

    public void
    conference() {
        ImsCall fgImsCall = mForegroundCall.getImsCall();
@@ -1294,12 +1388,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            foregroundConnection.setConferenceConnectTime(conferenceConnectTime);
            foregroundConnection.handleMergeStart();
            foregroundId = foregroundConnection.getTelecomCallId();
            cacheConnectionTimeWithPhoneNumber(foregroundConnection);
        }
        String backgroundId = "";
        ImsPhoneConnection backgroundConnection = findConnection(bgImsCall);
        if (backgroundConnection != null) {
            backgroundConnection.handleMergeStart();
            backgroundId = backgroundConnection.getTelecomCallId();
            cacheConnectionTimeWithPhoneNumber(backgroundConnection);
        }
        log("conference: fgCallId=" + foregroundId + ", bgCallId=" + backgroundId);

@@ -2551,6 +2647,17 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            }
        }

        private void updateConferenceParticipantsTiming(List<ConferenceParticipant> participants) {
            for (ConferenceParticipant participant : participants) {
                // Every time participants are newly created from parcel, update their connect time.
                CacheEntry cachedConnectTime = findConnectionTimeUsePhoneNumber(participant);
                if (cachedConnectTime != null) {
                    participant.setConnectTime(cachedConnectTime.mConnectTime);
                    participant.setConnectElapsedTime(cachedConnectTime.mConnectElapsedTime);
                }
            }
        }

        /**
         * Called when the state of IMS conference participant(s) has changed.
         *
@@ -2564,6 +2671,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {

            ImsPhoneConnection conn = findConnection(call);
            if (conn != null) {
                updateConferenceParticipantsTiming(participants);
                conn.updateConferenceParticipants(participants);
            }
        }