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

Commit 8730ff59 authored by Santos Cordon's avatar Santos Cordon Committed by Etan Cohen
Browse files

Add cache for isVoicemail check.

bindView() gets called many times at dialer startup and layout updates.
Besides being costly, it invokes cross-process TelecomManager methods.
This change addresses the cross-process issues by adding a short-lived
cache to isVoicemail() method invocations.

Change-Id: Ib69c0eb3969a1b7d77c9fd1a2aa6e578a31fb5e9
parent d04f11f0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -633,6 +633,8 @@ public class CallLogAdapter extends GroupingListAdapter

    /**
     * Binds the views in the entry to the data in the call log.
     * TODO: This gets called 20-30 times when Dialer starts up for a single call log entry and
     * should not. It invokes cross-process methods and the repeat execution can get costly.
     *
     * @param callLogItemView the view corresponding to this entry
     * @param c the cursor pointing to the entry in the call log
+44 −7
Original line number Diff line number Diff line
@@ -20,13 +20,15 @@ import android.content.Context;
import android.provider.CallLog;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import com.android.contacts.common.util.PhoneNumberHelper;

import com.google.common.collect.Sets;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
@@ -34,8 +36,20 @@ import java.util.Set;
 */
public class PhoneNumberUtilsWrapper {
    private static final Set<String> LEGACY_UNKNOWN_NUMBERS = Sets.newHashSet("-1", "-2", "-3");
    private static final long MAX_VOICEMAIL_CACHE_AGE_IN_MS = 60 * 1000;  // 60 seconds
    private final Context mContext;

    // Keeps a cache of recently-made voicemail queries.  The entire point of this cache is to
    // reduce the number of cross-process requests to TelecomManager.
    // Maps from a phone-account/number pair to a boolean because multiple numbers could return true
    // for the voicemail number if those numbers are not pre-normalized.
    //
    // TODO: Dialer should be fixed so as not to check isVoicemail() so often but at the time of
    // this writing, that was a much larger undertaking than creating this cache.
    private final Map<Pair<PhoneAccountHandle, CharSequence>, Boolean> mVoicemailQueryCache =
            new HashMap<>();
    private long mVoicemailCacheTimestamp = 0;

    public PhoneNumberUtilsWrapper(Context context) {
        mContext = context;
    }
@@ -50,11 +64,34 @@ public class PhoneNumberUtilsWrapper {
     * Returns true if the given number is the number of the configured voicemail. To be able to
     * mock-out this, it is not a static method.
     */
    public boolean isVoicemailNumber(PhoneAccountHandle accountHandle,
            CharSequence number) {
    public boolean isVoicemailNumber(PhoneAccountHandle accountHandle, CharSequence number) {
        if (TextUtils.isEmpty(number)) {
            return false;
        }

        long currentTime = System.currentTimeMillis();
        // check the age of the voicemail cache first.
        if (currentTime - mVoicemailCacheTimestamp > MAX_VOICEMAIL_CACHE_AGE_IN_MS) {
            mVoicemailQueryCache.clear();

            // We set the timestamp of the voicemail cache to the point where the cache is recreated
            // instead of when an item is added.
            // 1) This is easier to write
            // 2) Ensures that the oldest entry is never older than MAX_VOICEMAIL_CACHE_AGE
            mVoicemailCacheTimestamp = currentTime;
        }

        Pair<PhoneAccountHandle, CharSequence> key = new Pair<>(accountHandle, number);
        if (mVoicemailQueryCache.containsKey(key)) {
            return mVoicemailQueryCache.get(key);
        } else {
            final TelecomManager telecomManager =
                    (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
        return number!= null && telecomManager.isVoiceMailNumber(accountHandle, number.toString());
            Boolean isVoicemail =
                    telecomManager.isVoiceMailNumber(accountHandle, number.toString());
            mVoicemailQueryCache.put(key, isVoicemail);
            return isVoicemail;
        }
    }

    /**