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

Commit b63f4ccc authored by wangqi's avatar wangqi Committed by Eric Erfanian
Browse files

Make CallLogCache thread safe.

Methods such as getAccountLabel() is called on different threads which may cause
race condition issue.
This change also delete CallLogCacheLollopopMr1 since it's not necessary that Dialer is targeting M+.

Bug: 63415147,63524435
Test: none
PiperOrigin-RevId: 161440757
Change-Id: Ia609c52e53dabdce78ffb4320f4cd66e38112e47
parent 088b0e71
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -346,7 +346,7 @@ public class CallLogFragment extends Fragment
                activityType == CallLogAdapter.ACTIVITY_TYPE_DIALTACTS
                    ? (CallLogAdapter.OnActionModeStateChangedListener) getActivity()
                    : null,
                CallLogCache.getCallLogCache(getActivity()),
                new CallLogCache(getActivity()),
                mContactInfoCache,
                getVoicemailPlaybackPresenter(),
                new FilteredNumberAsyncQueryHandler(getActivity()),
+1 −1
Original line number Diff line number Diff line
@@ -353,7 +353,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder
      View.OnClickListener expandCollapseListener,
      VoicemailPlaybackPresenter voicemailPlaybackPresenter) {
    Resources resources = context.getResources();
    CallLogCache callLogCache = CallLogCache.getCallLogCache(context);
    CallLogCache callLogCache = new CallLogCache(context);
    PhoneCallDetailsHelper phoneCallDetailsHelper =
        new PhoneCallDetailsHelper(context, resources, callLogCache);

+50 −12
Original line number Diff line number Diff line
@@ -19,8 +19,14 @@ package com.android.dialer.app.calllog.calllogcache;
import android.content.Context;
import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.dialer.app.calllog.CallLogAdapter;
import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.CallUtil;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;

/**
 * This is the base class for the CallLogCaches.
@@ -31,7 +37,8 @@ import com.android.dialer.util.CallUtil;
 *
 * <p>This is designed with the specific use case of the {@link CallLogAdapter} in mind.
 */
public abstract class CallLogCache {
@ThreadSafe
public class CallLogCache {
  // 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.

@@ -39,17 +46,18 @@ public abstract class CallLogCache {

  private boolean mHasCheckedForVideoAvailability;
  private int mVideoAvailability;
  private final Map<PhoneAccountHandle, String> mPhoneAccountLabelCache = new ArrayMap<>();
  private final Map<PhoneAccountHandle, Integer> mPhoneAccountColorCache = new ArrayMap<>();
  private final Map<PhoneAccountHandle, Boolean> mPhoneAccountCallWithNoteCache = new ArrayMap<>();

  public CallLogCache(Context context) {
    mContext = context;
  }

  /** Return the most compatible version of the TelecomCallLogCache. */
  public static CallLogCache getCallLogCache(Context context) {
    return new CallLogCacheLollipopMr1(context);
  }

  public void reset() {
  public synchronized void reset() {
    mPhoneAccountLabelCache.clear();
    mPhoneAccountColorCache.clear();
    mPhoneAccountCallWithNoteCache.clear();
    mHasCheckedForVideoAvailability = false;
    mVideoAvailability = 0;
  }
@@ -58,8 +66,13 @@ public abstract class CallLogCache {
   * 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 abstract boolean isVoicemailNumber(
      PhoneAccountHandle accountHandle, @Nullable CharSequence number);
  public synchronized boolean isVoicemailNumber(
      PhoneAccountHandle accountHandle, @Nullable CharSequence number) {
    if (TextUtils.isEmpty(number)) {
      return false;
    }
    return TelecomUtil.isVoicemailNumber(mContext, accountHandle, number.toString());
  }

  /**
   * Returns {@code true} when the current sim supports checking video calling capabilities via the
@@ -74,10 +87,26 @@ public abstract class CallLogCache {
  }

  /** Extract account label from PhoneAccount object. */
  public abstract String getAccountLabel(PhoneAccountHandle accountHandle);
  public synchronized String getAccountLabel(PhoneAccountHandle accountHandle) {
    if (mPhoneAccountLabelCache.containsKey(accountHandle)) {
      return mPhoneAccountLabelCache.get(accountHandle);
    } else {
      String label = PhoneAccountUtils.getAccountLabel(mContext, accountHandle);
      mPhoneAccountLabelCache.put(accountHandle, label);
      return label;
    }
  }

  /** Extract account color from PhoneAccount object. */
  public abstract int getAccountColor(PhoneAccountHandle accountHandle);
  public synchronized int getAccountColor(PhoneAccountHandle accountHandle) {
    if (mPhoneAccountColorCache.containsKey(accountHandle)) {
      return mPhoneAccountColorCache.get(accountHandle);
    } else {
      Integer color = PhoneAccountUtils.getAccountColor(mContext, accountHandle);
      mPhoneAccountColorCache.put(accountHandle, color);
      return color;
    }
  }

  /**
   * Determines if the PhoneAccount supports specifying a call subject (i.e. calling with a note)
@@ -86,5 +115,14 @@ public abstract class CallLogCache {
   * @param accountHandle The PhoneAccount handle.
   * @return {@code true} if calling with a note is supported, {@code false} otherwise.
   */
  public abstract boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle);
  public synchronized boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle) {
    if (mPhoneAccountCallWithNoteCache.containsKey(accountHandle)) {
      return mPhoneAccountCallWithNoteCache.get(accountHandle);
    } else {
      Boolean supportsCallWithNote =
          PhoneAccountUtils.getAccountSupportsCallSubject(mContext, accountHandle);
      mPhoneAccountCallWithNoteCache.put(accountHandle, supportsCallWithNote);
      return supportsCallWithNote;
    }
  }
}
+0 −96
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 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.dialer.app.calllog.calllogcache;

import android.content.Context;
import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.telecom.TelecomUtil;
import java.util.Map;

/**
 * This is the CallLogCache for versions of dialer Lollipop Mr1 and above with support for multi-SIM
 * devices.
 *
 * <p>This class should not be initialized directly and instead be acquired from {@link
 * CallLogCache#getCallLogCache}.
 */
class CallLogCacheLollipopMr1 extends CallLogCache {

  private final Map<PhoneAccountHandle, String> mPhoneAccountLabelCache = new ArrayMap<>();
  private final Map<PhoneAccountHandle, Integer> mPhoneAccountColorCache = new ArrayMap<>();
  private final Map<PhoneAccountHandle, Boolean> mPhoneAccountCallWithNoteCache = new ArrayMap<>();

  /* package */ CallLogCacheLollipopMr1(Context context) {
    super(context);
  }

  @Override
  public void reset() {
    mPhoneAccountLabelCache.clear();
    mPhoneAccountColorCache.clear();
    mPhoneAccountCallWithNoteCache.clear();

    super.reset();
  }

  @Override
  public boolean isVoicemailNumber(
      PhoneAccountHandle accountHandle, @Nullable CharSequence number) {
    if (TextUtils.isEmpty(number)) {
      return false;
    }
    return TelecomUtil.isVoicemailNumber(mContext, accountHandle, number.toString());
  }

  @Override
  public String getAccountLabel(PhoneAccountHandle accountHandle) {
    if (mPhoneAccountLabelCache.containsKey(accountHandle)) {
      return mPhoneAccountLabelCache.get(accountHandle);
    } else {
      String label = PhoneAccountUtils.getAccountLabel(mContext, accountHandle);
      mPhoneAccountLabelCache.put(accountHandle, label);
      return label;
    }
  }

  @Override
  public int getAccountColor(PhoneAccountHandle accountHandle) {
    if (mPhoneAccountColorCache.containsKey(accountHandle)) {
      return mPhoneAccountColorCache.get(accountHandle);
    } else {
      Integer color = PhoneAccountUtils.getAccountColor(mContext, accountHandle);
      mPhoneAccountColorCache.put(accountHandle, color);
      return color;
    }
  }

  @Override
  public boolean doesAccountSupportCallSubject(PhoneAccountHandle accountHandle) {
    if (mPhoneAccountCallWithNoteCache.containsKey(accountHandle)) {
      return mPhoneAccountCallWithNoteCache.get(accountHandle);
    } else {
      Boolean supportsCallWithNote =
          PhoneAccountUtils.getAccountSupportsCallSubject(mContext, accountHandle);
      mPhoneAccountCallWithNoteCache.put(accountHandle, supportsCallWithNote);
      return supportsCallWithNote;
    }
  }
}