Created FakeInCallActivity for making EC w/ images.

video (slow/3g): https://drive.google.com/open?id=0B2Hce9qilHmvMnZZbE90TTlNSTQ
video (average): https://drive.google.com/open?id=0B2Hce9qilHmvazZNeVJjbU5Db0k
video (cancelling): https://drive.google.com/open?id=0B2Hce9qilHmvRi1JUXQ3OHZOYXM

Future CLs or updates to this CL will include activity transition improvements
and testing.

Bug: 38189742
Test: CallComposerActivityIntegrationTest
PiperOrigin-RevId: 166137133
Change-Id: Iada3e96c83495fd9a1554b4556be968670513163
diff --git a/java/com/android/dialer/callcomposer/CallComposerActivity.java b/java/com/android/dialer/callcomposer/CallComposerActivity.java
index e6e5513..d470ad2 100644
--- a/java/com/android/dialer/callcomposer/CallComposerActivity.java
+++ b/java/com/android/dialer/callcomposer/CallComposerActivity.java
@@ -75,9 +75,11 @@
 import com.android.dialer.protos.ProtoParsers;
 import com.android.dialer.telecom.TelecomUtil;
 import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.UriUtils;
 import com.android.dialer.util.ViewUtil;
 import com.android.dialer.widget.DialerToolbar;
 import com.android.dialer.widget.LockableViewPager;
+import com.android.incallui.callpending.CallPendingActivity;
 import com.google.protobuf.InvalidProtocolBufferException;
 import java.io.File;
 
@@ -119,6 +121,14 @@
         LogUtil.i("CallComposerActivity.sessionStartedTimedOutRunnable", "session never started");
         setFailedResultAndFinish();
       };
+  private final Runnable placeTelecomCallRunnable =
+      () -> {
+        LogUtil.i("CallComposerActivity.placeTelecomCallRunnable", "upload timed out.");
+        placeTelecomCall();
+      };
+  // Counter for the number of message sent updates received from EnrichedCallManager
+  private int messageSentCounter;
+  private boolean pendingCallStarted;
 
   private DialerContact contact;
   private Long sessionId = Session.NO_SESSION_ID;
@@ -239,7 +249,13 @@
   protected void onResume() {
     super.onResume();
     getEnrichedCallManager().registerStateChangedListener(this);
-    if (sessionId == Session.NO_SESSION_ID) {
+    if (pendingCallStarted) {
+      // User went into incall ui and pressed disconnect before the image was done uploading.
+      // Kill the activity and cancel the telecom call.
+      timeoutHandler.removeCallbacks(placeTelecomCallRunnable);
+      setResult(RESULT_OK);
+      finish();
+    } else if (sessionId == Session.NO_SESSION_ID) {
       LogUtil.i("CallComposerActivity.onResume", "creating new session");
       sessionId = getEnrichedCallManager().startCallComposerSession(contact.getNumber());
     } else if (getEnrichedCallManager().getSession(sessionId) == null) {
@@ -257,12 +273,16 @@
   }
 
   @Override
-  protected void onPause() {
-    super.onPause();
+  protected void onDestroy() {
+    super.onDestroy();
     getEnrichedCallManager().unregisterStateChangedListener(this);
-    timeoutHandler.removeCallbacks(sessionStartedTimedOut);
+    timeoutHandler.removeCallbacksAndMessages(null);
   }
 
+  /**
+   * This listener is registered in onResume and removed in onDestroy, meaning that calls to this
+   * method can come after onStop and updates to UI could cause crashes.
+   */
   @Override
   public void onEnrichedCallStateChanged() {
     refreshUiForCallComposerState();
@@ -297,8 +317,18 @@
       case Session.STATE_CLOSED:
         setFailedResultAndFinish();
         break;
-      case Session.STATE_MESSAGE_FAILED:
       case Session.STATE_MESSAGE_SENT:
+        if (++messageSentCounter == 3) {
+          // When we compose EC with images, there are 3 steps:
+          //  1. Message sent with no data
+          //  2. Image uploaded
+          //  3. url sent
+          // Once we receive 3 message sent updates, we know that we can proceed with the call.
+          timeoutHandler.removeCallbacks(placeTelecomCallRunnable);
+          placeTelecomCall();
+        }
+        break;
+      case Session.STATE_MESSAGE_FAILED:
       case Session.STATE_NONE:
       default:
         break;
@@ -394,18 +424,36 @@
     return session != null && session.getState() == Session.STATE_STARTED;
   }
 
-  private void placeRCSCall(MultimediaData.Builder builder) {
+  @VisibleForTesting
+  public void placeRCSCall(MultimediaData.Builder builder) {
     MultimediaData data = builder.build();
     LogUtil.i("CallComposerActivity.placeRCSCall", "placing enriched call, data: " + data);
     Logger.get(this).logImpression(DialerImpression.Type.CALL_COMPOSER_ACTIVITY_PLACE_RCS_CALL);
+
     getEnrichedCallManager().sendCallComposerData(sessionId, data);
-    TelecomUtil.placeCall(
-        this,
-        new CallIntentBuilder(contact.getNumber(), CallInitiationType.Type.CALL_COMPOSER).build());
-    setResult(RESULT_OK);
+    maybeShowPrivacyToast(data);
+    if (data.hasImageData()
+        && ConfigProviderBindings.get(this).getBoolean("enable_delayed_ec_images", true)
+        && !TelecomUtil.isInCall(this)) {
+      timeoutHandler.postDelayed(placeTelecomCallRunnable, getRCSTimeoutMillis());
+      startActivity(
+          CallPendingActivity.getIntent(
+              this,
+              contact.getNameOrNumber(),
+              contact.getNumber(),
+              contact.getNumberLabel(),
+              UriUtils.getLookupKeyFromUri(Uri.parse(contact.getContactUri())),
+              Uri.parse(contact.getPhotoUri()),
+              sessionId));
+      pendingCallStarted = true;
+    } else {
+      placeTelecomCall();
+    }
+  }
+
+  private void maybeShowPrivacyToast(MultimediaData data) {
     SharedPreferences preferences =
         DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(this);
-
     // Show a toast for privacy purposes if this is the first time a user uses call composer.
     if (preferences.getBoolean(KEY_IS_FIRST_CALL_COMPOSE, true)) {
       int privacyMessage =
@@ -416,6 +464,18 @@
       toast.show();
       preferences.edit().putBoolean(KEY_IS_FIRST_CALL_COMPOSE, false).apply();
     }
+  }
+
+  @VisibleForTesting
+  public long getRCSTimeoutMillis() {
+    return ConfigProviderBindings.get(this).getLong("ec_image_upload_timeout", 15_000);
+  }
+
+  private void placeTelecomCall() {
+    TelecomUtil.placeCall(
+        this,
+        new CallIntentBuilder(contact.getNumber(), CallInitiationType.Type.CALL_COMPOSER).build());
+    setResult(RESULT_OK);
     finish();
   }
 
diff --git a/java/com/android/dialer/postcall/AndroidManifest.xml b/java/com/android/dialer/postcall/AndroidManifest.xml
index 7e69d33..a097505 100644
--- a/java/com/android/dialer/postcall/AndroidManifest.xml
+++ b/java/com/android/dialer/postcall/AndroidManifest.xml
@@ -15,7 +15,7 @@
  -->
 <manifest
   xmlns:android="http://schemas.android.com/apk/res/android"
-  package="com.android.dialer.callcomposer">
+  package="com.android.dialer.postcall">
 
   <application android:theme="@style/Theme.AppCompat">
     <activity
diff --git a/java/com/android/incallui/CallCardPresenter.java b/java/com/android/incallui/CallCardPresenter.java
index 389b7c1..5f9f879 100644
--- a/java/com/android/incallui/CallCardPresenter.java
+++ b/java/com/android/incallui/CallCardPresenter.java
@@ -713,6 +713,7 @@
               shouldShowLocation(),
               null /* contactInfoLookupKey */,
               null /* enrichedCallMultimediaData */,
+              true /* showInCallButtonGrid */,
               mPrimary.getNumberPresentation()));
     } else if (mPrimaryContactInfo != null) {
       LogUtil.v(
@@ -760,6 +761,7 @@
               shouldShowLocation(),
               mPrimaryContactInfo.lookupKey,
               multimediaData,
+              true /* showInCallButtonGrid */,
               mPrimary.getNumberPresentation()));
     } else {
       // Clear the primary display info.
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 90f532a..178a404 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -49,6 +49,7 @@
 import com.android.incallui.call.CallList;
 import com.android.incallui.call.DialerCall;
 import com.android.incallui.call.DialerCall.State;
+import com.android.incallui.callpending.CallPendingActivity;
 import com.android.incallui.disconnectdialog.DisconnectMessage;
 import com.android.incallui.incall.bindings.InCallBindings;
 import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
@@ -141,6 +142,7 @@
             View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
 
     pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
+    sendBroadcast(CallPendingActivity.getFinishBroadcast());
     Trace.endSection();
   }
 
diff --git a/java/com/android/incallui/callpending/AndroidManifest.xml b/java/com/android/incallui/callpending/AndroidManifest.xml
new file mode 100644
index 0000000..231553e
--- /dev/null
+++ b/java/com/android/incallui/callpending/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<!--
+ ~ Copyright (C) 2017 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
+ -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.incallui.callpending">
+  <application android:theme="@style/Theme.AppCompat">
+    <!-- Identical to .InCallActivity except orientation is locked to portrait -->
+    <activity
+        android:directBootAware="true"
+        android:excludeFromRecents="true"
+        android:exported="false"
+        android:label="@string/phoneAppLabel"
+        android:name="com.android.incallui.callpending.CallPendingActivity"
+        android:resizeableActivity="true"
+        android:screenOrientation="portrait"
+        android:taskAffinity="com.android.incallui"
+        android:theme="@style/Theme.InCallScreen"/>
+  </application>
+</manifest>
diff --git a/java/com/android/incallui/callpending/CallPendingActivity.java b/java/com/android/incallui/callpending/CallPendingActivity.java
new file mode 100644
index 0000000..554d021
--- /dev/null
+++ b/java/com/android/incallui/callpending/CallPendingActivity.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2017 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.incallui.callpending;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.telecom.CallAudioState;
+import android.telecom.TelecomManager;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.enrichedcall.EnrichedCallComponent;
+import com.android.dialer.multimedia.MultimediaData;
+import com.android.incallui.audiomode.AudioModeProvider;
+import com.android.incallui.call.DialerCall.State;
+import com.android.incallui.incall.bindings.InCallBindings;
+import com.android.incallui.incall.protocol.ContactPhotoType;
+import com.android.incallui.incall.protocol.InCallButtonIds;
+import com.android.incallui.incall.protocol.InCallButtonUi;
+import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
+import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
+import com.android.incallui.incall.protocol.InCallScreen;
+import com.android.incallui.incall.protocol.InCallScreenDelegate;
+import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
+import com.android.incallui.incall.protocol.PrimaryCallState;
+import com.android.incallui.incall.protocol.PrimaryInfo;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+/**
+ * Activity useful for showing the incall ui without an actual call being placed.
+ *
+ * <p>The UI currently displays the following:
+ *
+ * <ul>
+ *   <li>Contact info
+ *   <li>"Dialing..." call state
+ *   <li>Enriched calling data
+ * </ul>
+ *
+ * If the user presses the back or disconnect buttons, {@link #finish()} is called.
+ */
+public class CallPendingActivity extends FragmentActivity
+    implements InCallButtonUiDelegateFactory, InCallScreenDelegateFactory {
+
+  private static final String TAG_IN_CALL_SCREEN = "tag_in_call_screen";
+  private static final String ACTION_FINISH_BROADCAST =
+      "dialer.intent.action.CALL_PENDING_ACTIVITY_FINISH";
+
+  private static final String EXTRA_SESSION_ID = "extra_session_id";
+  private static final String EXTRA_NUMBER = "extra_number";
+  private static final String EXTRA_NAME = "extra_name";
+  private static final String EXTRA_LABEL = "extra_LABEL";
+  private static final String EXTRA_LOOKUP_KEY = "extra_LOOKUP_KEY";
+  private static final String EXTRA_PHOTO_URI = "extra_photo_uri";
+
+  private final BroadcastReceiver finishReceiver =
+      new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context arg0, Intent intent) {
+          LogUtil.i("CallPendingActivity.onReceive", "finish broadcast received");
+          String action = intent.getAction();
+          if (action.equals(ACTION_FINISH_BROADCAST)) {
+            finish();
+          }
+        }
+      };
+
+  private InCallButtonUiDelegate inCallButtonUiDelegate;
+  private InCallScreenDelegate inCallScreenDelegate;
+
+  public static Intent getIntent(
+      Context context,
+      String name,
+      String number,
+      String label,
+      String lookupKey,
+      Uri photoUri,
+      long sessionId) {
+    Intent intent = new Intent(context, CallPendingActivity.class);
+    intent.putExtra(EXTRA_NAME, name);
+    intent.putExtra(EXTRA_NUMBER, number);
+    intent.putExtra(EXTRA_LABEL, label);
+    intent.putExtra(EXTRA_LOOKUP_KEY, lookupKey);
+    intent.putExtra(EXTRA_PHOTO_URI, photoUri);
+    intent.putExtra(EXTRA_SESSION_ID, sessionId);
+    return intent;
+  }
+
+  public static Intent getFinishBroadcast() {
+    return new Intent(ACTION_FINISH_BROADCAST);
+  }
+
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.pending_incall_screen);
+    registerReceiver(finishReceiver, new IntentFilter(ACTION_FINISH_BROADCAST));
+  }
+
+  @Override
+  protected void onStart() {
+    super.onStart();
+    InCallScreen inCallScreen = InCallBindings.createInCallScreen();
+    getSupportFragmentManager()
+        .beginTransaction()
+        .add(R.id.main, inCallScreen.getInCallScreenFragment(), TAG_IN_CALL_SCREEN)
+        .commit();
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+    setupInCallScreen();
+  }
+
+  @Override
+  protected void onDestroy() {
+    super.onDestroy();
+    unregisterReceiver(finishReceiver);
+  }
+
+  private void setupInCallScreen() {
+    InCallScreen inCallScreen =
+        (InCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_IN_CALL_SCREEN);
+    inCallScreen.setPrimary(createPrimaryInfo());
+    inCallScreen.setCallState(PrimaryCallState.createEmptyPrimaryCallStateWithState(State.DIALING));
+    inCallScreen.setEndCallButtonEnabled(true, true);
+  }
+
+  private PrimaryInfo createPrimaryInfo() {
+    MultimediaData multimediaData =
+        EnrichedCallComponent.get(this)
+            .getEnrichedCallManager()
+            .getSession(getSessionId())
+            .getMultimediaData();
+
+    Drawable photo = null;
+    try {
+      // TODO(calderwoodra) move to background thread
+      Uri photoUri = getPhotoUri();
+      InputStream is = getContentResolver().openInputStream(photoUri);
+      photo = Drawable.createFromStream(is, photoUri.toString());
+    } catch (FileNotFoundException e) {
+      LogUtil.e("CallPendingActivity.createPrimaryInfo", "Contact photo not found", e);
+    }
+
+    String name = getName();
+    String number = getNumber();
+
+    // DialerCall with caller that is a work contact.
+    return new PrimaryInfo(
+        number,
+        name,
+        name != null && name.equals(number),
+        null /* location */,
+        getPhoneLabel(),
+        photo,
+        ContactPhotoType.CONTACT,
+        false /* isSipCall */,
+        true /* isContactPhotoShown */,
+        false /* isWorkCall */,
+        false /* isSpam */,
+        false /* answeringDisconnectsOngoingCall */,
+        false /* shouldShowLocation */,
+        getLookupKey(),
+        multimediaData,
+        false /*showInCallButtonGrid */,
+        TelecomManager.PRESENTATION_ALLOWED);
+  }
+
+  @Override
+  public InCallButtonUiDelegate newInCallButtonUiDelegate() {
+    if (inCallButtonUiDelegate != null) {
+      return inCallButtonUiDelegate;
+    }
+    return inCallButtonUiDelegate =
+        new InCallButtonUiDelegate() {
+
+          @Override
+          public void onInCallButtonUiReady(InCallButtonUi inCallButtonUi) {
+            inCallButtonUi.showButton(InCallButtonIds.BUTTON_DIALPAD, true);
+            inCallButtonUi.showButton(InCallButtonIds.BUTTON_MUTE, true);
+            inCallButtonUi.showButton(InCallButtonIds.BUTTON_AUDIO, true);
+            inCallButtonUi.showButton(InCallButtonIds.BUTTON_ADD_CALL, true);
+
+            inCallButtonUi.enableButton(InCallButtonIds.BUTTON_DIALPAD, false);
+            inCallButtonUi.enableButton(InCallButtonIds.BUTTON_MUTE, false);
+            inCallButtonUi.enableButton(InCallButtonIds.BUTTON_AUDIO, false);
+            inCallButtonUi.enableButton(InCallButtonIds.BUTTON_ADD_CALL, false);
+          }
+
+          @Override
+          public void onInCallButtonUiUnready() {}
+
+          @Override
+          public void onSaveInstanceState(Bundle outState) {}
+
+          @Override
+          public void onRestoreInstanceState(Bundle savedInstanceState) {}
+
+          @Override
+          public void refreshMuteState() {}
+
+          @Override
+          public void addCallClicked() {}
+
+          @Override
+          public void muteClicked(boolean checked, boolean clickedByUser) {}
+
+          @Override
+          public void mergeClicked() {}
+
+          @Override
+          public void holdClicked(boolean checked) {}
+
+          @Override
+          public void swapClicked() {}
+
+          @Override
+          public void showDialpadClicked(boolean checked) {}
+
+          @Override
+          public void changeToVideoClicked() {}
+
+          @Override
+          public void switchCameraClicked(boolean useFrontFacingCamera) {}
+
+          @Override
+          public void toggleCameraClicked() {}
+
+          @Override
+          public void pauseVideoClicked(boolean pause) {}
+
+          @Override
+          public void toggleSpeakerphone() {}
+
+          @Override
+          public CallAudioState getCurrentAudioState() {
+            return AudioModeProvider.getInstance().getAudioState();
+          }
+
+          @Override
+          public void setAudioRoute(int route) {}
+
+          @Override
+          public void onEndCallClicked() {}
+
+          @Override
+          public void showAudioRouteSelector() {}
+
+          @Override
+          public Context getContext() {
+            return CallPendingActivity.this;
+          }
+        };
+  }
+
+  @Override
+  public InCallScreenDelegate newInCallScreenDelegate() {
+    if (inCallScreenDelegate != null) {
+      return inCallScreenDelegate;
+    }
+    return inCallScreenDelegate =
+        new InCallScreenDelegate() {
+
+          @Override
+          public void onInCallScreenDelegateInit(InCallScreen inCallScreen) {}
+
+          @Override
+          public void onInCallScreenReady() {}
+
+          @Override
+          public void onInCallScreenUnready() {}
+
+          @Override
+          public void onEndCallClicked() {
+            finish();
+          }
+
+          @Override
+          public void onSecondaryInfoClicked() {}
+
+          @Override
+          public void onCallStateButtonClicked() {}
+
+          @Override
+          public void onManageConferenceClicked() {}
+
+          @Override
+          public void onShrinkAnimationComplete() {}
+
+          @Override
+          public void onInCallScreenResumed() {}
+
+          @Override
+          public void onInCallScreenPaused() {}
+        };
+  }
+
+  private long getSessionId() {
+    return getIntent().getLongExtra(EXTRA_SESSION_ID, -1);
+  }
+
+  private String getNumber() {
+    return getIntent().getStringExtra(EXTRA_NUMBER);
+  }
+
+  private String getName() {
+    return getIntent().getStringExtra(EXTRA_NAME);
+  }
+
+  private String getPhoneLabel() {
+    return getIntent().getStringExtra(EXTRA_LABEL);
+  }
+
+  private String getLookupKey() {
+    return getIntent().getStringExtra(EXTRA_LOOKUP_KEY);
+  }
+
+  private Uri getPhotoUri() {
+    return getIntent().getParcelableExtra(EXTRA_PHOTO_URI);
+  }
+}
diff --git a/java/com/android/incallui/callpending/res/layout/pending_incall_screen.xml b/java/com/android/incallui/callpending/res/layout/pending_incall_screen.xml
new file mode 100644
index 0000000..398042b
--- /dev/null
+++ b/java/com/android/incallui/callpending/res/layout/pending_incall_screen.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- In-call Phone UI; see CallPendingActivity.java. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java
index 7e39ceb..f9abf20 100644
--- a/java/com/android/incallui/incall/impl/InCallFragment.java
+++ b/java/com/android/incallui/incall/impl/InCallFragment.java
@@ -241,7 +241,7 @@
   @Override
   public void setPrimary(@NonNull PrimaryInfo primaryInfo) {
     LogUtil.i("InCallFragment.setPrimary", primaryInfo.toString());
-    setAdapterMedia(primaryInfo.multimediaData);
+    setAdapterMedia(primaryInfo.multimediaData, primaryInfo.showInCallButtonGrid);
     contactGridManager.setPrimary(primaryInfo);
 
     if (primaryInfo.shouldShowLocation) {
@@ -267,9 +267,10 @@
     }
   }
 
-  private void setAdapterMedia(MultimediaData multimediaData) {
+  private void setAdapterMedia(MultimediaData multimediaData, boolean showInCallButtonGrid) {
     if (adapter == null) {
-      adapter = new InCallPagerAdapter(getChildFragmentManager(), multimediaData);
+      adapter =
+          new InCallPagerAdapter(getChildFragmentManager(), multimediaData, showInCallButtonGrid);
       pager.setAdapter(adapter);
     } else {
       adapter.setAttachments(multimediaData);
diff --git a/java/com/android/incallui/incall/impl/InCallPagerAdapter.java b/java/com/android/incallui/incall/impl/InCallPagerAdapter.java
index d4b04fe..ead3534 100644
--- a/java/com/android/incallui/incall/impl/InCallPagerAdapter.java
+++ b/java/com/android/incallui/incall/impl/InCallPagerAdapter.java
@@ -21,6 +21,7 @@
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.support.v4.view.PagerAdapter;
+import com.android.dialer.common.Assert;
 import com.android.dialer.multimedia.MultimediaData;
 import com.android.incallui.sessiondata.MultimediaFragment;
 
@@ -28,28 +29,44 @@
 public class InCallPagerAdapter extends FragmentStatePagerAdapter {
 
   @Nullable private MultimediaData attachments;
+  private final boolean showInCallButtonGrid;
 
-  public InCallPagerAdapter(FragmentManager fragmentManager, @Nullable MultimediaData attachments) {
+  public InCallPagerAdapter(
+      FragmentManager fragmentManager,
+      @Nullable MultimediaData attachments,
+      boolean showInCallButtonGrid) {
     super(fragmentManager);
     this.attachments = attachments;
+    this.showInCallButtonGrid = showInCallButtonGrid;
   }
 
   @Override
   public Fragment getItem(int position) {
-    if (position == getButtonGridPosition()) {
-      return InCallButtonGridFragment.newInstance();
-    } else {
+    if (!showInCallButtonGrid) {
       // TODO(calderwoodra): handle fragment invalidation for when the data changes.
-      return MultimediaFragment.newInstance(attachments, true, false, false);
+      return MultimediaFragment.newInstance(
+          attachments, true /* isInteractive */, false /* showAvatar */, false /* isSpam */);
+
+    } else if (position == getButtonGridPosition()) {
+      return InCallButtonGridFragment.newInstance();
+
+    } else {
+      return MultimediaFragment.newInstance(
+          attachments, true /* isInteractive */, false /* showAvatar */, false /* isSpam */);
     }
   }
 
   @Override
   public int getCount() {
-    if (attachments != null && attachments.hasData()) {
-      return 2;
+    int count = 0;
+    if (showInCallButtonGrid) {
+      count++;
     }
-    return 1;
+    if (attachments != null && attachments.hasData()) {
+      count++;
+    }
+    Assert.checkArgument(count > 0, "InCallPager adapter doesn't have any pages.");
+    return count;
   }
 
   public void setAttachments(@Nullable MultimediaData attachments) {
diff --git a/java/com/android/incallui/incall/protocol/PrimaryCallState.java b/java/com/android/incallui/incall/protocol/PrimaryCallState.java
index 791f22e..1afa66a 100644
--- a/java/com/android/incallui/incall/protocol/PrimaryCallState.java
+++ b/java/com/android/incallui/incall/protocol/PrimaryCallState.java
@@ -66,8 +66,12 @@
 
   // TODO: Convert to autovalue. b/34502119
   public static PrimaryCallState createEmptyPrimaryCallState() {
+    return createEmptyPrimaryCallStateWithState(DialerCall.State.IDLE);
+  }
+
+  public static PrimaryCallState createEmptyPrimaryCallStateWithState(int state) {
     return new PrimaryCallState(
-        DialerCall.State.IDLE,
+        state,
         false, /* isVideoCall */
         SessionModificationState.NO_REQUEST,
         new DisconnectCause(DisconnectCause.UNKNOWN),
diff --git a/java/com/android/incallui/incall/protocol/PrimaryInfo.java b/java/com/android/incallui/incall/protocol/PrimaryInfo.java
index 761dd9a..7fe0a0f 100644
--- a/java/com/android/incallui/incall/protocol/PrimaryInfo.java
+++ b/java/com/android/incallui/incall/protocol/PrimaryInfo.java
@@ -41,6 +41,7 @@
   // Used for consistent LetterTile coloring.
   @Nullable public final String contactInfoLookupKey;
   @Nullable public final MultimediaData multimediaData;
+  public final boolean showInCallButtonGrid;
   public final int numberPresentation;
 
   // TODO: Convert to autovalue. b/34502119
@@ -61,6 +62,7 @@
         false,
         null,
         null,
+        true,
         -1);
   }
 
@@ -80,6 +82,7 @@
       boolean shouldShowLocation,
       @Nullable String contactInfoLookupKey,
       @Nullable MultimediaData multimediaData,
+      boolean showInCallButtonGrid,
       int numberPresentation) {
     this.number = number;
     this.name = name;
@@ -96,6 +99,7 @@
     this.shouldShowLocation = shouldShowLocation;
     this.contactInfoLookupKey = contactInfoLookupKey;
     this.multimediaData = multimediaData;
+    this.showInCallButtonGrid = showInCallButtonGrid;
     this.numberPresentation = numberPresentation;
   }