Merge "Implemented context menu actions."
diff --git a/java/com/android/dialer/speeddial/ContextMenu.java b/java/com/android/dialer/speeddial/ContextMenu.java
index b6ac988..126373c 100644
--- a/java/com/android/dialer/speeddial/ContextMenu.java
+++ b/java/com/android/dialer/speeddial/ContextMenu.java
@@ -21,14 +21,23 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
 import com.android.dialer.speeddial.loader.SpeedDialUiItem;
 
 /** Floating menu which presents contact options available to the contact. */
 public class ContextMenu extends LinearLayout {
 
-  private SpeedDialUiItem speedDialUiItem;
   private ContextMenuItemListener listener;
 
+  private TextView videoView;
+  private TextView smsView;
+
+  private SpeedDialUiItem speedDialUiItem;
+  private Channel voiceChannel;
+  private Channel videoChannel;
+  private Channel smsChannel;
+
   public ContextMenu(Context context, @Nullable AttributeSet attrs) {
     super(context, attrs);
   }
@@ -36,12 +45,14 @@
   @Override
   protected void onFinishInflate() {
     super.onFinishInflate();
-    findViewById(R.id.voice_call_container)
-        .setOnClickListener(v -> listener.placeVoiceCall(speedDialUiItem));
-    findViewById(R.id.video_call_container)
-        .setOnClickListener(v -> listener.placeVideoCall(speedDialUiItem));
-    findViewById(R.id.send_message_container)
-        .setOnClickListener(v -> listener.openSmsConversation(speedDialUiItem));
+
+    videoView = findViewById(R.id.video_call_container);
+    videoView.setOnClickListener(v -> placeVideoCall());
+
+    smsView = findViewById(R.id.send_message_container);
+    smsView.setOnClickListener(v -> listener.openSmsConversation(smsChannel.number()));
+
+    findViewById(R.id.voice_call_container).setOnClickListener(v -> placeVoiceCall());
     findViewById(R.id.remove_container)
         .setOnClickListener(v -> listener.removeFavoriteContact(speedDialUiItem));
     findViewById(R.id.contact_info_container)
@@ -65,6 +76,15 @@
     setX((float) (childLocation[0] + .5 * childLayout.getWidth() - .5 * getWidth()));
     setY(childLocation[1] - parentLocation[1] + childLayout.getHeight());
 
+    voiceChannel = speedDialUiItem.getDeterministicVoiceChannel();
+    videoChannel = speedDialUiItem.getDeterministicVideoChannel();
+    videoView.setVisibility(
+        videoChannel == null && !speedDialUiItem.hasVideoChannels() ? View.GONE : View.VISIBLE);
+
+    // TODO(calderwoodra): disambig dialog for texts?
+    smsChannel = voiceChannel;
+    smsView.setVisibility(smsChannel == null ? View.GONE : View.VISIBLE);
+
     // TODO(calderwoodra): a11y
     // TODO(calderwoodra): animate this similar to the bubble menu
     setVisibility(View.VISIBLE);
@@ -81,6 +101,22 @@
     }
   }
 
+  private void placeVoiceCall() {
+    if (voiceChannel == null) {
+      listener.disambiguateCall(speedDialUiItem);
+    } else {
+      listener.placeCall(voiceChannel);
+    }
+  }
+
+  private void placeVideoCall() {
+    if (videoChannel == null) {
+      listener.disambiguateCall(speedDialUiItem);
+    } else {
+      listener.placeCall(videoChannel);
+    }
+  }
+
   public boolean isVisible() {
     return getVisibility() == View.VISIBLE;
   }
@@ -88,14 +124,19 @@
   /** Listener to report user clicks on menu items. */
   public interface ContextMenuItemListener {
 
-    /** Called when the user selects "voice call" option from the context menu. */
-    void placeVoiceCall(SpeedDialUiItem speedDialUiItem);
+    /** Called when the user selects "voice call" or "video call" option from the context menu. */
+    void placeCall(Channel channel);
 
-    /** Called when the user selects "video call" option from the context menu. */
-    void placeVideoCall(SpeedDialUiItem speedDialUiItem);
+    /**
+     * Called when the user selects "voice call" or "video call" option from the context menu, but
+     * it's not clear which channel they want to call.
+     *
+     * <p>TODO(calderwoodra): discuss with product how we want to handle these cases
+     */
+    void disambiguateCall(SpeedDialUiItem speedDialUiItem);
 
     /** Called when the user selects "send message" from the context menu. */
-    void openSmsConversation(SpeedDialUiItem speedDialUiItem);
+    void openSmsConversation(String number);
 
     /** Called when the user selects "remove" from the context menu. */
     void removeFavoriteContact(SpeedDialUiItem speedDialUiItem);
diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java
index 793169a..3654c81 100644
--- a/java/com/android/dialer/speeddial/SpeedDialFragment.java
+++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java
@@ -17,8 +17,10 @@
 package com.android.dialer.speeddial;
 
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentActivity;
@@ -49,6 +51,7 @@
 import com.android.dialer.speeddial.draghelper.SpeedDialLayoutManager;
 import com.android.dialer.speeddial.loader.SpeedDialUiItem;
 import com.android.dialer.speeddial.loader.UiItemLoaderComponent;
+import com.android.dialer.util.IntentUtil;
 import com.google.common.collect.ImmutableList;
 
 /**
@@ -78,8 +81,6 @@
    */
   private boolean updateSpeedDialItemsOnResume = true;
 
-  private FavoriteContactsListener favoritesListener;
-
   public static SpeedDialFragment newInstance() {
     return new SpeedDialFragment();
   }
@@ -103,14 +104,14 @@
     // Setup our RecyclerView
     SpeedDialLayoutManager layoutManager =
         new SpeedDialLayoutManager(getContext(), 3 /* spanCount */);
-    favoritesListener =
+    FavoriteContactsListener favoritesListener =
         new SpeedDialFavoritesListener(
             getActivity(),
             getChildFragmentManager(),
             rootLayout,
             contextMenu,
             contextMenuBackground,
-            new SpeedDialContextMenuItemListener(),
+            new SpeedDialContextMenuItemListener(getActivity(), getChildFragmentManager()),
             layoutManager);
     adapter =
         new SpeedDialAdapter(getContext(), favoritesListener, suggestedListener, headerListener);
@@ -181,6 +182,22 @@
     }
   }
 
+  @Override
+  public void onPause() {
+    super.onPause();
+    contextMenu.hideMenu();
+    contextMenuBackground.setVisibility(View.GONE);
+  }
+
+  @Override
+  public void onHiddenChanged(boolean hidden) {
+    super.onHiddenChanged(hidden);
+    if (hidden) {
+      contextMenu.hideMenu();
+      contextMenuBackground.setVisibility(View.GONE);
+    }
+  }
+
   private class SpeedDialFragmentHeaderListener implements SpeedDialHeaderListener {
 
     @Override
@@ -294,29 +311,53 @@
 
   private static final class SpeedDialContextMenuItemListener implements ContextMenuItemListener {
 
-    @Override
-    public void placeVoiceCall(SpeedDialUiItem speedDialUiItem) {
-      // TODO(calderwoodra)
+    private final FragmentActivity activity;
+    private final FragmentManager childFragmentManager;
+
+    SpeedDialContextMenuItemListener(
+        FragmentActivity activity, FragmentManager childFragmentManager) {
+      this.activity = activity;
+      this.childFragmentManager = childFragmentManager;
     }
 
     @Override
-    public void placeVideoCall(SpeedDialUiItem speedDialUiItem) {
-      // TODO(calderwoodra)
+    public void disambiguateCall(SpeedDialUiItem speedDialUiItem) {
+      // TODO(calderwoodra): show only video or voice channels in the disambig dialog
+      DisambigDialog.show(speedDialUiItem, childFragmentManager);
     }
 
     @Override
-    public void openSmsConversation(SpeedDialUiItem speedDialUiItem) {
-      // TODO(calderwoodra)
+    public void placeCall(Channel channel) {
+      if (channel.technology() == Channel.DUO) {
+        Logger.get(activity)
+            .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_FAVORITE_CONTACT);
+        Intent intent = DuoComponent.get(activity).getDuo().getIntent(activity, channel.number());
+        activity.startActivityForResult(intent, ActivityRequestCodes.DIALTACTS_DUO);
+        return;
+      }
+      PreCall.start(
+          activity,
+          new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL)
+              .setIsVideoCall(channel.isVideoTechnology()));
+    }
+
+    @Override
+    public void openSmsConversation(String number) {
+      activity.startActivity(IntentUtil.getSendSmsIntent(number));
     }
 
     @Override
     public void removeFavoriteContact(SpeedDialUiItem speedDialUiItem) {
-      // TODO(calderwoodra)
+      // TODO(calderwoodra): implement remove
     }
 
     @Override
     public void openContactInfo(SpeedDialUiItem speedDialUiItem) {
-      // TODO(calderwoodra)
+      activity.startActivity(
+          new Intent(
+              Intent.ACTION_VIEW,
+              Uri.withAppendedPath(
+                  Contacts.CONTENT_URI, String.valueOf(speedDialUiItem.contactId()))));
     }
   }
 }
diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
index 65aa297..5b7906f 100644
--- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
+++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
@@ -119,6 +119,64 @@
   }
 
   /**
+   * Returns a video channel if there is exactly one video channel or the default channel is a video
+   * channel.
+   */
+  @Nullable
+  public Channel getDeterministicVideoChannel() {
+    if (defaultChannel() != null && defaultChannel().isVideoTechnology()) {
+      return defaultChannel();
+    }
+
+    Channel videoChannel = null;
+    for (Channel channel : channels()) {
+      if (channel.isVideoTechnology()) {
+        if (videoChannel != null) {
+          // We found two video channels, so we can't determine which one is correct..
+          return null;
+        }
+        videoChannel = channel;
+      }
+    }
+    // Only found one channel, so return it
+    return videoChannel;
+  }
+
+  /** Returns true if any channels are video channels. */
+  public boolean hasVideoChannels() {
+    for (Channel channel : channels()) {
+      if (channel.isVideoTechnology()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Returns a voice channel if there is exactly one voice channel or the default channel is a voice
+   * channel.
+   */
+  @Nullable
+  public Channel getDeterministicVoiceChannel() {
+    if (defaultChannel() != null && !defaultChannel().isVideoTechnology()) {
+      return defaultChannel();
+    }
+
+    Channel voiceChannel = null;
+    for (Channel channel : channels()) {
+      if (!channel.isVideoTechnology()) {
+        if (voiceChannel != null) {
+          // We found two voice channels, so we can't determine which one is correct..
+          return null;
+        }
+        voiceChannel = channel;
+      }
+    }
+    // Only found one channel, so return it
+    return voiceChannel;
+  }
+
+  /**
    * The id of the corresponding SpeedDialEntry. Null if the UI item does not have an entry, for
    * example suggested contacts (isStarred() will also be false)
    *
diff --git a/java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml b/java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml
new file mode 100644
index 0000000..73260b1
--- /dev/null
+++ b/java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml
@@ -0,0 +1,30 @@
+<?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
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+  <item>
+    <shape android:shape="oval">
+      <solid android:color="@color/secondary_text_color"/>
+      <size android:width="24dp" android:height="24dp"/>
+    </shape>
+  </item>
+  <item
+      android:width="24dp"
+      android:height="24dp"
+      android:gravity="center"
+      android:drawable="@drawable/product_logo_avatar_anonymous_white_color_120"/>
+</layer-list>
\ No newline at end of file
diff --git a/java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xml b/java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xml
deleted file mode 100644
index 4df2f29..0000000
--- a/java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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
- -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/add_favorite_container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/java/com/android/dialer/speeddial/res/layout/context_menu_layout.xml b/java/com/android/dialer/speeddial/res/layout/context_menu_layout.xml
index 4fb12ff..a59fa07 100644
--- a/java/com/android/dialer/speeddial/res/layout/context_menu_layout.xml
+++ b/java/com/android/dialer/speeddial/res/layout/context_menu_layout.xml
@@ -20,7 +20,6 @@
     android:orientation="vertical"
     android:layout_width="160dp"
     android:layout_height="wrap_content"
-    android:elevation="8dp"
     android:clipChildren="true"
     android:clipToPadding="false">
 
@@ -83,13 +82,12 @@
         android:drawableStart="@drawable/quantum_ic_close_vd_theme_24"
         style="@style/SpeedDialContextMenuItem"/>
 
-    <!-- TODO(calderwoodra): Update this icon to be the contact icon. -->
     <TextView
         android:id="@+id/contact_info_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:drawableStart="@drawable/context_menu_contact_icon"
         android:text="@string/contact_menu_contact_info"
-        android:drawableStart="@drawable/quantum_ic_call_vd_theme_24"
-        style="@style/SpeedDialContextMenuItem"/>
+        style="@style/SpeedDialContextMenuItem.NoDrawableTint"/>
   </LinearLayout>
 </com.android.dialer.speeddial.ContextMenu>
\ No newline at end of file
diff --git a/java/com/android/dialer/speeddial/res/values/styles.xml b/java/com/android/dialer/speeddial/res/values/styles.xml
index 83bbd09..46dbc35 100644
--- a/java/com/android/dialer/speeddial/res/values/styles.xml
+++ b/java/com/android/dialer/speeddial/res/values/styles.xml
@@ -15,11 +15,14 @@
   ~ limitations under the License
   -->
 <resources>
-  <style name="SpeedDialContextMenuItem" parent="SecondaryText">
+  <style name="SpeedDialContextMenuItem" parent="SpeedDialContextMenuItem.NoDrawableTint">
+    <item name="android:drawableTint">@color/secondary_text_color</item>
+  </style>
+
+  <style name="SpeedDialContextMenuItem.NoDrawableTint" parent="SecondaryText">
     <item name="android:paddingStart">12dp</item>
     <item name="android:minHeight">48dp</item>
     <item name="android:gravity">center_vertical</item>
-    <item name="android:drawableTint">@color/secondary_text_color</item>
     <item name="android:drawablePadding">12dp</item>
     <item name="android:clickable">true</item>
     <item name="android:background">?android:attr/selectableItemBackground</item>