From 6c2357ae634cd3413c699d71c542fd5fced48002 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Mon, 23 Apr 2018 15:22:26 -0700 Subject: Implemented context menu actions. Actions implemented in this CL: - placing a voice call - placing a video call - opening an sms conversation - opening a contact card Remove action will be implemented in a follow up CL. Made a few adjustments to the context menu UI. Bug: 77761023 Test: ContextMenuTest PiperOrigin-RevId: 193994428 Change-Id: I85b328f5820175ff91514c0057267b85649b0755 --- java/com/android/dialer/speeddial/ContextMenu.java | 65 ++++++++++++++++++---- .../dialer/speeddial/SpeedDialFragment.java | 65 ++++++++++++++++++---- .../dialer/speeddial/loader/SpeedDialUiItem.java | 58 +++++++++++++++++++ .../res/drawable/context_menu_contact_icon.xml | 30 ++++++++++ .../speeddial/res/layout/add_favorite_activity.xml | 21 ------- .../speeddial/res/layout/context_menu_layout.xml | 6 +- .../android/dialer/speeddial/res/values/styles.xml | 7 ++- 7 files changed, 201 insertions(+), 51 deletions(-) create mode 100644 java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml delete mode 100644 java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xml (limited to 'java/com/android/dialer') diff --git a/java/com/android/dialer/speeddial/ContextMenu.java b/java/com/android/dialer/speeddial/ContextMenu.java index b6ac98862..126373c12 100644 --- a/java/com/android/dialer/speeddial/ContextMenu.java +++ b/java/com/android/dialer/speeddial/ContextMenu.java @@ -21,14 +21,23 @@ import android.support.annotation.Nullable; 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 @@ public class ContextMenu extends LinearLayout { @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 @@ public class ContextMenu extends LinearLayout { 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 @@ public class ContextMenu extends LinearLayout { } } + 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 @@ public class ContextMenu extends LinearLayout { /** 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. + * + *

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 793169a81..3654c816b 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.SpeedDialItemTouchHelperCallback; 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 @@ public class SpeedDialFragment extends Fragment { */ private boolean updateSpeedDialItemsOnResume = true; - private FavoriteContactsListener favoritesListener; - public static SpeedDialFragment newInstance() { return new SpeedDialFragment(); } @@ -103,14 +104,14 @@ public class SpeedDialFragment extends Fragment { // 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 @@ public class SpeedDialFragment extends Fragment { } } + @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 @@ public class SpeedDialFragment extends Fragment { private static final class SpeedDialContextMenuItemListener implements ContextMenuItemListener { + private final FragmentActivity activity; + private final FragmentManager childFragmentManager; + + SpeedDialContextMenuItemListener( + FragmentActivity activity, FragmentManager childFragmentManager) { + this.activity = activity; + this.childFragmentManager = childFragmentManager; + } + @Override - public void placeVoiceCall(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 placeVideoCall(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(SpeedDialUiItem speedDialUiItem) { - // TODO(calderwoodra) + 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 65aa297f0..5b7906fdb 100644 --- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java +++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java @@ -118,6 +118,64 @@ public abstract class SpeedDialUiItem { return builder.build(); } + /** + * 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 000000000..73260b156 --- /dev/null +++ b/java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + \ 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 4df2f29b4..000000000 --- a/java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - \ 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 4fb12ffe9..a59fa07c7 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"/> - + style="@style/SpeedDialContextMenuItem.NoDrawableTint"/> \ 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 83bbd09e5..46dbc359a 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 --> - + +