Merge changes I0e8549cf,I12ac7b89,I2c77f0c6,I3ba5795b

* changes:
  Lazy loading animation of hd icon.
  Use TelecomManager#isInManagedCall starting from O.
  Setup SMS filter during activation if legacy mode is used
  Last contact in search is now visible when dialpad is closed.
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java
index 3e6b50c..a4c075c 100644
--- a/java/com/android/dialer/app/DialtactsActivity.java
+++ b/java/com/android/dialer/app/DialtactsActivity.java
@@ -1410,7 +1410,7 @@
   }
 
   private boolean phoneIsInUse() {
-    return TelecomUtil.isInCall(this);
+    return TelecomUtil.isInManagedCall(this);
   }
 
   private boolean canIntentBeHandled(Intent intent) {
diff --git a/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java b/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
index de4e1cc..685357a 100644
--- a/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
+++ b/java/com/android/dialer/app/voicemail/VoicemailPlaybackPresenter.java
@@ -516,7 +516,7 @@
     mView.disableUiElements();
     mIsPrepared = false;
 
-    if (mContext != null && TelecomUtil.isInCall(mContext)) {
+    if (mContext != null && TelecomUtil.isInManagedCall(mContext)) {
       handleError(new IllegalStateException("Cannot play voicemail when call is in progress"));
       return;
     }
diff --git a/java/com/android/dialer/callcomposer/CallComposerActivity.java b/java/com/android/dialer/callcomposer/CallComposerActivity.java
index fa380cc..4a6cdbb 100644
--- a/java/com/android/dialer/callcomposer/CallComposerActivity.java
+++ b/java/com/android/dialer/callcomposer/CallComposerActivity.java
@@ -438,7 +438,7 @@
     maybeShowPrivacyToast(data);
     if (data.hasImageData()
         && ConfigProviderBindings.get(this).getBoolean("enable_delayed_ec_images", true)
-        && !TelecomUtil.isInCall(this)) {
+        && !TelecomUtil.isInManagedCall(this)) {
       timeoutHandler.postDelayed(placeTelecomCallRunnable, getRCSTimeoutMillis());
       startActivity(
           CallPendingActivity.getIntent(
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index e22250c..86a8379 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -1278,7 +1278,7 @@
    *     or ringing or dialing, or on hold).
    */
   private boolean isPhoneInUse() {
-    return getContext() != null && TelecomUtil.isInCall(getContext());
+    return getContext() != null && TelecomUtil.isInManagedCall(getContext());
   }
 
   /** @return true if the phone is a CDMA phone type */
diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
index 910e454..5b3532c 100644
--- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
+++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java
@@ -32,6 +32,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
 import com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor;
 import com.android.dialer.animation.AnimUtils;
 import com.android.dialer.callintent.CallInitiationType;
@@ -198,6 +200,7 @@
     }
   }
 
+  /** Translate the search fragment and resize it to fit on the screen. */
   public void animatePosition(int start, int end, int duration) {
     // Called before the view is ready, prepare a runnable to run in onCreateView
     if (getView() == null) {
@@ -206,11 +209,30 @@
     }
     boolean slideUp = start > end;
     Interpolator interpolator = slideUp ? AnimUtils.EASE_IN : AnimUtils.EASE_OUT;
+    int startHeight = getView().getHeight();
+    int endHeight = startHeight - (end - start);
     getView().setTranslationY(start);
-    getView().animate().translationY(end).setInterpolator(interpolator).setDuration(duration);
+    getView()
+        .animate()
+        .translationY(end)
+        .setInterpolator(interpolator)
+        .setDuration(duration)
+        .setUpdateListener(
+            animation -> setHeight(startHeight, endHeight, animation.getAnimatedFraction()));
     updatePositionRunnable = null;
   }
 
+  private void setHeight(int start, int end, float percentage) {
+    View view = getView();
+    if (view == null) {
+      return;
+    }
+
+    FrameLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
+    params.height = (int) (start + (end - start) * percentage);
+    view.setLayoutParams(params);
+  }
+
   @Override
   public void onDestroy() {
     super.onDestroy();
diff --git a/java/com/android/dialer/telecom/TelecomUtil.java b/java/com/android/dialer/telecom/TelecomUtil.java
index 573bfe2..8ff4b39 100644
--- a/java/com/android/dialer/telecom/TelecomUtil.java
+++ b/java/com/android/dialer/telecom/TelecomUtil.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
 import android.provider.CallLog.Calls;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
@@ -140,7 +142,11 @@
     return new ArrayList<>();
   }
 
-  public static boolean isInCall(Context context) {
+  /**
+   * Returns true if there is a dialer managed call in progress. Self managed calls starting from O
+   * are not included.
+   */
+  public static boolean isInManagedCall(Context context) {
     return instance.isInCall(context);
   }
 
@@ -234,7 +240,19 @@
 
     public boolean isInCall(Context context) {
       if (hasReadPhoneStatePermission(context)) {
-        return getTelecomManager(context).isInCall();
+        // The TelecomManager#isInCall method returns true anytime the user is in a call.
+        // Starting in O, the APIs include support for self-managed ConnectionServices so that other
+        // apps like Duo can tell Telecom about its calls.  So, if the user is in a Duo call,
+        // isInCall would return true.
+        // Dialer uses this to determine whether to show the "return to call in progress" when
+        // Dialer is launched.
+        // Instead, Dialer should use TelecomManager#isInManagedCall, which only returns true if the
+        // device is in a managed call which Dialer would know about.
+        if (VERSION.SDK_INT >= VERSION_CODES.O) {
+          return getTelecomManager(context).isInManagedCall();
+        } else {
+          return getTelecomManager(context).isInCall();
+        }
       }
       return false;
     }
diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java
index 9b92b48..7bac6d3 100644
--- a/java/com/android/incallui/ContactInfoCache.java
+++ b/java/com/android/incallui/ContactInfoCache.java
@@ -25,6 +25,7 @@
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.DisplayNameSources;
@@ -123,8 +124,10 @@
   }
 
   private ContactInfoCache(Context context) {
+    Trace.beginSection("ContactInfoCache constructor");
     mContext = context;
     mPhoneNumberService = Bindings.get(context).newPhoneNumberService(context);
+    Trace.endSection();
   }
 
   public static synchronized ContactInfoCache getInstance(Context mContext) {
@@ -343,6 +346,7 @@
       @NonNull final DialerCall call,
       final boolean isIncoming,
       @NonNull ContactInfoCacheCallback callback) {
+    Trace.beginSection("ContactInfoCache.findInfo");
     Assert.isMainThread();
     Objects.requireNonNull(callback);
 
@@ -364,6 +368,7 @@
       callback.onContactInfoComplete(callId, cacheEntry);
       // If no other callbacks are in flight, we're done.
       if (callBacks == null) {
+        Trace.endSection();
         return;
       }
     }
@@ -374,6 +379,7 @@
       callBacks.add(callback);
       if (!forceQuery) {
         Log.d(TAG, "No need to query again, just return and wait for existing query to finish");
+        Trace.endSection();
         return;
       }
     } else {
@@ -412,6 +418,7 @@
               callId, call.getNumberPresentation(), callerInfo, false, queryToken);
       sendInfoNotifications(callId, initialCacheEntry);
     }
+    Trace.endSection();
   }
 
   @AnyThread
@@ -421,6 +428,7 @@
       CallerInfo callerInfo,
       boolean didLocalLookup,
       CallerInfoQueryToken queryToken) {
+    Trace.beginSection("ContactInfoCache.updateCallerInfoInCacheOnAnyThread");
     Log.d(
         TAG,
         "updateCallerInfoInCacheOnAnyThread: callId = "
@@ -488,6 +496,7 @@
       Log.d(TAG, "put entry into map if not exists: " + cacheEntry);
       mInfoMap.putIfAbsent(callId, cacheEntry);
     }
+    Trace.endSection();
     return cacheEntry;
   }
 
@@ -644,6 +653,7 @@
   /** Sends the updated information to call the callbacks for the entry. */
   @MainThread
   private void sendInfoNotifications(String callId, ContactCacheEntry entry) {
+    Trace.beginSection("ContactInfoCache.sendInfoNotifications");
     Assert.isMainThread();
     final Set<ContactInfoCacheCallback> callBacks = mCallBacks.get(callId);
     if (callBacks != null) {
@@ -651,10 +661,12 @@
         callBack.onContactInfoComplete(callId, entry);
       }
     }
+    Trace.endSection();
   }
 
   @MainThread
   private void sendImageNotifications(String callId, ContactCacheEntry entry) {
+    Trace.beginSection("ContactInfoCache.sendImageNotifications");
     Assert.isMainThread();
     final Set<ContactInfoCacheCallback> callBacks = mCallBacks.get(callId);
     if (callBacks != null && entry.photo != null) {
@@ -662,6 +674,7 @@
         callBack.onImageLoadComplete(callId, entry);
       }
     }
+    Trace.endSection();
   }
 
   private void clearCallbacks(String callId) {
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index 9b1f674..3f87a59 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -769,15 +769,19 @@
         "InCallPresenter.onIncomingCall", "Phone switching state: " + oldState + " -> " + newState);
     mInCallState = newState;
 
+    Trace.beginSection("listener.onIncomingCall");
     for (IncomingCallListener listener : mIncomingCallListeners) {
       listener.onIncomingCall(oldState, mInCallState, call);
     }
+    Trace.endSection();
 
+    Trace.beginSection("onPrimaryCallStateChanged");
     if (mInCallActivity != null) {
       // Re-evaluate which fragment is being shown.
       mInCallActivity.onPrimaryCallStateChanged();
     }
     Trace.endSection();
+    Trace.endSection();
   }
 
   @Override
@@ -1278,6 +1282,7 @@
    * UI needs to be started or finished depending on the new state and does it.
    */
   private InCallState startOrFinishUi(InCallState newState) {
+    Trace.beginSection("InCallPresenter.startOrFinishUi");
     LogUtil.d(
         "InCallPresenter.startOrFinishUi", "startOrFinishUi: " + mInCallState + " -> " + newState);
 
@@ -1286,6 +1291,7 @@
     // If the state isn't changing we have already done any starting/stopping of activities in
     // a previous pass...so lets cut out early
     if (newState == mInCallState) {
+      Trace.endSection();
       return newState;
     }
 
@@ -1364,6 +1370,7 @@
       LogUtil.i(
           "InCallPresenter.startOrFinishUi",
           "Undo the state change: " + newState + " -> " + mInCallState);
+      Trace.endSection();
       return mInCallState;
     }
 
@@ -1390,6 +1397,7 @@
       attemptCleanup();
     }
 
+    Trace.endSection();
     return newState;
   }
 
diff --git a/java/com/android/incallui/ReturnToCallController.java b/java/com/android/incallui/ReturnToCallController.java
index e5c7618..e54102c 100644
--- a/java/com/android/incallui/ReturnToCallController.java
+++ b/java/com/android/incallui/ReturnToCallController.java
@@ -94,7 +94,7 @@
     if (showing) {
       hide();
     } else {
-      if (TelecomUtil.isInCall(context)) {
+      if (TelecomUtil.isInManagedCall(context)) {
         show();
       }
     }
@@ -175,7 +175,7 @@
     }
     if (bubble != null
         && bubble.isVisible()
-        && (!TelecomUtil.isInCall(context)
+        && (!TelecomUtil.isInManagedCall(context)
             || CallList.getInstance().getActiveOrBackgroundCall() != null)) {
       bubble.showText(context.getText(R.string.incall_call_ended));
     }
diff --git a/java/com/android/incallui/StatusBarNotifier.java b/java/com/android/incallui/StatusBarNotifier.java
index e6969c1..92ffae3 100644
--- a/java/com/android/incallui/StatusBarNotifier.java
+++ b/java/com/android/incallui/StatusBarNotifier.java
@@ -40,6 +40,7 @@
 import android.net.Uri;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
+import android.os.Trace;
 import android.support.annotation.ColorRes;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -236,6 +237,7 @@
 
   @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
   private void showNotification(final CallList callList, final DialerCall call) {
+    Trace.beginSection("StatusBarNotifier.showNotification");
     final boolean isIncoming =
         (call.getState() == DialerCall.State.INCOMING
             || call.getState() == DialerCall.State.CALL_WAITING);
@@ -269,20 +271,24 @@
             }
           }
         });
+    Trace.endSection();
   }
 
   /** Sets up the main Ui for the notification */
   @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
   private void buildAndSendNotification(
       CallList callList, DialerCall originalCall, ContactCacheEntry contactInfo) {
+    Trace.beginSection("StatusBarNotifier.buildAndSendNotification");
     // This can get called to update an existing notification after contact information has come
     // back. However, it can happen much later. Before we continue, we need to make sure that
     // the call being passed in is still the one we want to show in the notification.
     final DialerCall call = getCallToShow(callList);
     if (call == null || !call.getId().equals(originalCall.getId())) {
+      Trace.endSection();
       return;
     }
 
+    Trace.beginSection("prepare work");
     final int callState = call.getState();
 
     // Check if data has changed; if nothing is different, don't issue another notification.
@@ -314,6 +320,7 @@
     } else {
       notificationType = NOTIFICATION_IN_CALL;
     }
+    Trace.endSection(); // prepare work
 
     if (!checkForChangeAndSaveData(
         iconResId,
@@ -323,6 +330,7 @@
         callState,
         notificationType,
         contactInfo.contactRingtoneUri)) {
+      Trace.endSection();
       return;
     }
 
@@ -409,6 +417,7 @@
 
     addPersonReference(builder, contactInfo, call);
 
+    Trace.beginSection("fire notification");
     // Fire off the notification
     Notification notification = builder.build();
 
@@ -448,8 +457,10 @@
               memoryInfo.availMem),
           e);
     }
+    Trace.endSection();
     call.getLatencyReport().onNotificationShown();
     mCurrentNotification = notificationType;
+    Trace.endSection();
   }
 
   @Nullable
diff --git a/java/com/android/incallui/answer/impl/AnswerFragment.java b/java/com/android/incallui/answer/impl/AnswerFragment.java
index db6d43d..18de72e 100644
--- a/java/com/android/incallui/answer/impl/AnswerFragment.java
+++ b/java/com/android/incallui/answer/impl/AnswerFragment.java
@@ -29,6 +29,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Trace;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.FloatRange;
 import android.support.annotation.NonNull;
@@ -657,6 +658,7 @@
   @Override
   public View onCreateView(
       LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+    Trace.beginSection("AnswerFragment.onCreateView");
     Bundle arguments = getArguments();
     Assert.checkState(arguments.containsKey(ARG_CALL_ID));
     Assert.checkState(arguments.containsKey(ARG_IS_VIDEO_CALL));
@@ -729,6 +731,7 @@
       }
     }
 
+    Trace.endSection();
     return view;
   }
 
diff --git a/java/com/android/incallui/contactgrid/ContactGridManager.java b/java/com/android/incallui/contactgrid/ContactGridManager.java
index ddf16e3..18bab6a 100644
--- a/java/com/android/incallui/contactgrid/ContactGridManager.java
+++ b/java/com/android/incallui/contactgrid/ContactGridManager.java
@@ -315,6 +315,7 @@
         info.isAssistedDialedVisisble ? View.VISIBLE : View.GONE);
     if (hdIconImageView.getVisibility() == View.GONE) {
       if (info.isHdAttemptingIconVisible) {
+        hdIconImageView.setImageResource(R.drawable.asd_hd_icon);
         hdIconImageView.setVisibility(View.VISIBLE);
         hdIconImageView.setActivated(false);
         Drawable drawableCurrent = hdIconImageView.getDrawable().getCurrent();
@@ -322,6 +323,7 @@
           ((Animatable) drawableCurrent).start();
         }
       } else if (info.isHdIconVisible) {
+        hdIconImageView.setImageResource(R.drawable.asd_hd_icon);
         hdIconImageView.setVisibility(View.VISIBLE);
         hdIconImageView.setActivated(true);
       }
diff --git a/java/com/android/incallui/contactgrid/res/layout/incall_contactgrid_bottom_row.xml b/java/com/android/incallui/contactgrid/res/layout/incall_contactgrid_bottom_row.xml
index 8850dd8..c545c25 100644
--- a/java/com/android/incallui/contactgrid/res/layout/incall_contactgrid_bottom_row.xml
+++ b/java/com/android/incallui/contactgrid/res/layout/incall_contactgrid_bottom_row.xml
@@ -29,7 +29,6 @@
   <ImageView
       android:id="@+id/contactgrid_hdIcon"
       style="@style/BottomRowIcon"
-      android:src="@drawable/asd_hd_icon"
       android:visibility="gone"/>
   <ImageView
       android:id="@+id/contactgrid_assistedDialingIcon"
diff --git a/java/com/android/voicemail/impl/ActivationTask.java b/java/com/android/voicemail/impl/ActivationTask.java
index 320ea2a..d7a122c 100644
--- a/java/com/android/voicemail/impl/ActivationTask.java
+++ b/java/com/android/voicemail/impl/ActivationTask.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.provider.Settings;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.annotation.WorkerThread;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.ServiceState;
@@ -64,6 +65,8 @@
 
   private final RetryPolicy mRetryPolicy;
 
+  @Nullable private OmtpVvmCarrierConfigHelper configForTest;
+
   private Bundle mMessageData;
 
   public ActivationTask() {
@@ -132,19 +135,27 @@
 
     PreOMigrationHandler.migrate(getContext(), phoneAccountHandle);
 
-    if (!VisualVoicemailSettingsUtil.isEnabled(getContext(), phoneAccountHandle)) {
-      VvmLog.i(TAG, "VVM is disabled");
-      return;
+    OmtpVvmCarrierConfigHelper helper;
+    if (configForTest != null) {
+      helper = configForTest;
+    } else {
+      helper = new OmtpVvmCarrierConfigHelper(getContext(), phoneAccountHandle);
     }
-
-    OmtpVvmCarrierConfigHelper helper =
-        new OmtpVvmCarrierConfigHelper(getContext(), phoneAccountHandle);
     if (!helper.isValid()) {
       VvmLog.i(TAG, "VVM not supported on phoneAccountHandle " + phoneAccountHandle);
       VvmAccountManager.removeAccount(getContext(), phoneAccountHandle);
       return;
     }
 
+    if (!VisualVoicemailSettingsUtil.isEnabled(getContext(), phoneAccountHandle)) {
+      if (helper.isLegacyModeEnabled()) {
+        VvmLog.i(TAG, "Setting up filter for legacy mode");
+        helper.activateSmsFilter();
+      }
+      VvmLog.i(TAG, "VVM is disabled");
+      return;
+    }
+
     // OmtpVvmCarrierConfigHelper can start the activation process; it will pass in a vvm
     // content provider URI which we will use.  On some occasions, setting that URI will
     // fail, so we will perform a few attempts to ensure that the vvm content provider has
@@ -278,4 +289,9 @@
             .createForPhoneAccountHandle(phoneAccountHandle);
     return telephonyManager.getServiceState().getState() == ServiceState.STATE_IN_SERVICE;
   }
+
+  @VisibleForTesting
+  void setConfigForTest(OmtpVvmCarrierConfigHelper config) {
+    configForTest = config;
+  }
 }
diff --git a/java/com/android/voicemail/impl/scheduling/BaseTask.java b/java/com/android/voicemail/impl/scheduling/BaseTask.java
index bbdca8c..773d026 100644
--- a/java/com/android/voicemail/impl/scheduling/BaseTask.java
+++ b/java/com/android/voicemail/impl/scheduling/BaseTask.java
@@ -23,6 +23,7 @@
 import android.support.annotation.CallSuper;
 import android.support.annotation.MainThread;
 import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
 import android.support.annotation.WorkerThread;
 import android.telecom.PhoneAccountHandle;
 import com.android.dialer.proguard.UsedByReflection;
@@ -38,7 +39,8 @@
 @UsedByReflection(value = "Tasks.java")
 public abstract class BaseTask implements Task {
 
-  private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
+  @VisibleForTesting
+  public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
 
   private static final String EXTRA_EXECUTION_TIME = "extra_execution_time";