From 7be061ae13582b0c64251d99a206589a6901bf20 Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Wed, 11 Apr 2018 21:43:49 -0700 Subject: Added context menu for favorite contacts in new speed dial. Bug: 36841782,77761023 Test: WIP PiperOrigin-RevId: 192556602 Change-Id: I50c0baef7ef6c8ae533545567ec797283a9a870f --- java/com/android/dialer/speeddial/ContextMenu.java | 102 +++++++++++++++++++++ .../dialer/speeddial/FavoritesViewHolder.java | 34 +++---- .../dialer/speeddial/SpeedDialFragment.java | 66 +++++++++++-- .../speeddial/loader/SpeedDialUiItemLoader.java | 4 +- .../res/drawable/context_menu_background.xml | 26 ++++++ .../speeddial/res/layout/context_menu_layout.xml | 95 +++++++++++++++++++ .../speeddial/res/layout/fragment_speed_dial.xml | 32 +++++-- .../android/dialer/speeddial/res/values/dimens.xml | 15 +++ .../dialer/speeddial/res/values/strings.xml | 15 +++ .../android/dialer/speeddial/res/values/styles.xml | 27 ++++++ 10 files changed, 377 insertions(+), 39 deletions(-) create mode 100644 java/com/android/dialer/speeddial/ContextMenu.java create mode 100644 java/com/android/dialer/speeddial/res/drawable/context_menu_background.xml create mode 100644 java/com/android/dialer/speeddial/res/layout/context_menu_layout.xml create mode 100644 java/com/android/dialer/speeddial/res/values/styles.xml (limited to 'java/com/android/dialer/speeddial') diff --git a/java/com/android/dialer/speeddial/ContextMenu.java b/java/com/android/dialer/speeddial/ContextMenu.java new file mode 100644 index 000000000..a7fa65556 --- /dev/null +++ b/java/com/android/dialer/speeddial/ContextMenu.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 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.speeddial; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +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; + + public ContextMenu(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @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)); + findViewById(R.id.remove_container) + .setOnClickListener(v -> listener.removeFavoriteContact(speedDialUiItem)); + findViewById(R.id.contact_info_container) + .setOnClickListener(v -> listener.openContactInfo(speedDialUiItem)); + } + + /** Shows the menu and updates the menu's position w.r.t. the view it's related to. */ + public void showMenu( + View parentLayout, + View childLayout, + SpeedDialUiItem speedDialUiItem, + ContextMenuItemListener listener) { + this.speedDialUiItem = speedDialUiItem; + this.listener = listener; + + int[] childLocation = new int[2]; + int[] parentLocation = new int[2]; + childLayout.getLocationOnScreen(childLocation); + parentLayout.getLocationOnScreen(parentLocation); + + setX((float) (childLocation[0] + .5 * childLayout.getWidth() - .5 * getWidth())); + setY(childLocation[1] - parentLocation[1] + childLayout.getHeight()); + + // TODO(calderwoodra): a11y + // TODO(calderwoodra): animate this similar to the bubble menu + setVisibility(View.VISIBLE); + } + + /** Returns true if the view was hidden. */ + public void hideMenu() { + this.speedDialUiItem = null; + this.listener = null; + if (getVisibility() == View.VISIBLE) { + // TODO(calderwoodra): a11y + // TODO(calderwoodra): animate this similar to the bubble menu + setVisibility(View.INVISIBLE); + } + } + + /** 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 "video call" option from the context menu. */ + void placeVideoCall(SpeedDialUiItem speedDialUiItem); + + /** Called when the user selects "send message" from the context menu. */ + void openSmsConversation(SpeedDialUiItem speedDialUiItem); + + /** Called when the user selects "remove" from the context menu. */ + void removeFavoriteContact(SpeedDialUiItem speedDialUiItem); + + /** Called when the user selects "contact info" from the context menu. */ + void openContactInfo(SpeedDialUiItem speedDialUiItem); + } +} diff --git a/java/com/android/dialer/speeddial/FavoritesViewHolder.java b/java/com/android/dialer/speeddial/FavoritesViewHolder.java index 92ffb0a46..4f0cf65a0 100644 --- a/java/com/android/dialer/speeddial/FavoritesViewHolder.java +++ b/java/com/android/dialer/speeddial/FavoritesViewHolder.java @@ -30,7 +30,6 @@ import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent; import com.android.dialer.glidephotomanager.PhotoInfo; import com.android.dialer.speeddial.database.SpeedDialEntry.Channel; import com.android.dialer.speeddial.loader.SpeedDialUiItem; -import java.util.ArrayList; import java.util.List; /** ViewHolder for starred/favorite contacts in {@link SpeedDialFragment}. */ @@ -44,10 +43,7 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder private final TextView phoneType; private final FrameLayout videoCallIcon; - private boolean hasDefaultNumber; - private boolean isVideoCall; - private String number; - private List channels; + private SpeedDialUiItem speedDialUiItem; public FavoritesViewHolder(View view, FavoriteContactsListener listener) { super(view); @@ -62,20 +58,15 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder } public void bind(Context context, SpeedDialUiItem speedDialUiItem) { + this.speedDialUiItem = Assert.isNotNull(speedDialUiItem); Assert.checkArgument(speedDialUiItem.isStarred()); nameView.setText(speedDialUiItem.name()); - hasDefaultNumber = speedDialUiItem.defaultChannel() != null; - if (hasDefaultNumber) { - channels = new ArrayList<>(); - isVideoCall = speedDialUiItem.defaultChannel().isVideoTechnology(); - number = speedDialUiItem.defaultChannel().number(); + if (speedDialUiItem.defaultChannel() != null) { phoneType.setText(speedDialUiItem.defaultChannel().label()); - videoCallIcon.setVisibility(isVideoCall ? View.VISIBLE : View.GONE); + videoCallIcon.setVisibility( + speedDialUiItem.defaultChannel().isVideoTechnology() ? View.VISIBLE : View.GONE); } else { - channels = speedDialUiItem.channels(); - isVideoCall = false; - number = null; phoneType.setText(""); videoCallIcon.setVisibility(View.GONE); } @@ -96,17 +87,18 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder @Override public void onClick(View v) { - if (hasDefaultNumber) { - listener.onClick(number, isVideoCall); + if (speedDialUiItem.defaultChannel() != null) { + listener.onClick(speedDialUiItem.defaultChannel()); } else { - listener.onAmbiguousContactClicked(channels); + listener.onAmbiguousContactClicked(speedDialUiItem.channels()); } } @Override - public boolean onLongClick(View v) { + public boolean onLongClick(View view) { // TODO(calderwoodra): implement drag and drop logic - listener.onLongClick(number); + // TODO(calderwoodra): add bounce/sin wave scale animation + listener.onLongClick(photoView, speedDialUiItem); return true; } @@ -117,9 +109,9 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder void onAmbiguousContactClicked(List channels); /** Called when the user clicks on a favorite contact. */ - void onClick(String number, boolean isVideoCall); + void onClick(Channel channel); /** Called when the user long clicks on a favorite contact. */ - void onLongClick(String number); + void onLongClick(View view, SpeedDialUiItem speedDialUiItem); } } diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java index aca4886a4..d323b1bb4 100644 --- a/java/com/android/dialer/speeddial/SpeedDialFragment.java +++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java @@ -24,11 +24,14 @@ import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.concurrent.SupportUiListener; import com.android.dialer.precall.PreCall; +import com.android.dialer.speeddial.ContextMenu.ContextMenuItemListener; import com.android.dialer.speeddial.FavoritesViewHolder.FavoriteContactsListener; import com.android.dialer.speeddial.HeaderViewHolder.SpeedDialHeaderListener; import com.android.dialer.speeddial.SuggestionViewHolder.SuggestedContactsListener; @@ -54,7 +57,11 @@ public class SpeedDialFragment extends Fragment { private final FavoriteContactsListener favoritesListener = new SpeedDialFavoritesListener(); private final SuggestedContactsListener suggestedListener = new SpeedDialSuggestedListener(); + private View rootLayout; + private ContextMenu contextMenu; + private FrameLayout contextMenuBackground; private SpeedDialAdapter adapter; + private ContextMenuItemListener contextMenuItemListener; private SupportUiListener> speedDialLoaderListener; public static SpeedDialFragment newInstance() { @@ -65,18 +72,28 @@ public class SpeedDialFragment extends Fragment { @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_speed_dial, container, false); - RecyclerView recyclerView = view.findViewById(R.id.speed_dial_recycler_view); + LogUtil.enterBlock("SpeedDialFragment.onCreateView"); + rootLayout = inflater.inflate(R.layout.fragment_speed_dial, container, false); + RecyclerView recyclerView = rootLayout.findViewById(R.id.speed_dial_recycler_view); adapter = new SpeedDialAdapter(getContext(), favoritesListener, suggestedListener, headerListener); recyclerView.setLayoutManager(adapter.getLayoutManager(getContext())); recyclerView.setAdapter(adapter); + contextMenu = rootLayout.findViewById(R.id.favorite_contact_context_menu); + contextMenuBackground = rootLayout.findViewById(R.id.context_menu_background); + contextMenuBackground.setOnClickListener( + v -> { + contextMenu.hideMenu(); + contextMenuBackground.setVisibility(View.GONE); + }); + contextMenuItemListener = new SpeedDialContextMenuItemListener(); + speedDialLoaderListener = DialerExecutorComponent.get(getContext()) .createUiListener(getChildFragmentManager(), "speed_dial_loader_listener"); - return view; + return rootLayout; } public boolean hasFrequents() { @@ -107,7 +124,7 @@ public class SpeedDialFragment extends Fragment { } } - private class SpeedDialFavoritesListener implements FavoriteContactsListener { + private final class SpeedDialFavoritesListener implements FavoriteContactsListener { @Override public void onAmbiguousContactClicked(List channels) { @@ -115,21 +132,22 @@ public class SpeedDialFragment extends Fragment { } @Override - public void onClick(String number, boolean isVideoCall) { + public void onClick(Channel channel) { // TODO(calderwoodra): add logic for duo video calls PreCall.start( getContext(), - new CallIntentBuilder(number, CallInitiationType.Type.SPEED_DIAL) - .setIsVideoCall(isVideoCall)); + new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) + .setIsVideoCall(channel.isVideoTechnology())); } @Override - public void onLongClick(String number) { - // TODO(calderwoodra): show favorite contact floating context menu + public void onLongClick(View view, SpeedDialUiItem speedDialUiItem) { + contextMenuBackground.setVisibility(View.VISIBLE); + contextMenu.showMenu(rootLayout, view, speedDialUiItem, contextMenuItemListener); } } - private class SpeedDialSuggestedListener implements SuggestedContactsListener { + private final class SpeedDialSuggestedListener implements SuggestedContactsListener { @Override public void onOverFlowMenuClicked(String number) { @@ -142,4 +160,32 @@ public class SpeedDialFragment extends Fragment { getContext(), new CallIntentBuilder(number, CallInitiationType.Type.SPEED_DIAL)); } } + + private static final class SpeedDialContextMenuItemListener implements ContextMenuItemListener { + + @Override + public void placeVoiceCall(SpeedDialUiItem speedDialUiItem) { + // TODO(calderwoodra) + } + + @Override + public void placeVideoCall(SpeedDialUiItem speedDialUiItem) { + // TODO(calderwoodra) + } + + @Override + public void openSmsConversation(SpeedDialUiItem speedDialUiItem) { + // TODO(calderwoodra) + } + + @Override + public void removeFavoriteContact(SpeedDialUiItem speedDialUiItem) { + // TODO(calderwoodra) + } + + @Override + public void openContactInfo(SpeedDialUiItem speedDialUiItem) { + // TODO(calderwoodra) + } + } } diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java index c23b67d45..c80a06245 100644 --- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java +++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java @@ -135,7 +135,9 @@ public final class SpeedDialUiItemLoader implements UiItemLoader { for (SpeedDialUiItem contact : strequentContacts) { if (!contact.isStarred()) { // Add this contact as a suggestion - speedDialUiItems.add(contact); + // TODO(77754534): improve suggestions beyond just first channel + speedDialUiItems.add( + contact.toBuilder().setDefaultChannel(contact.channels().get(0)).build()); } else if (speedDialUiItems.stream().noneMatch(c -> c.contactId() == contact.contactId())) { entriesToInsert.add( diff --git a/java/com/android/dialer/speeddial/res/drawable/context_menu_background.xml b/java/com/android/dialer/speeddial/res/drawable/context_menu_background.xml new file mode 100644 index 000000000..c828860b2 --- /dev/null +++ b/java/com/android/dialer/speeddial/res/drawable/context_menu_background.xml @@ -0,0 +1,26 @@ + + + + + + + + \ 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 new file mode 100644 index 000000000..4fb12ffe9 --- /dev/null +++ b/java/com/android/dialer/speeddial/res/layout/context_menu_layout.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml b/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml index 67ef877ca..080fba5d3 100644 --- a/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml +++ b/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml @@ -14,11 +14,29 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - + android:layout_height="match_parent"> + + + + + + + + + diff --git a/java/com/android/dialer/speeddial/res/values/dimens.xml b/java/com/android/dialer/speeddial/res/values/dimens.xml index 74b509b73..ce2de9dcc 100644 --- a/java/com/android/dialer/speeddial/res/values/dimens.xml +++ b/java/com/android/dialer/speeddial/res/values/dimens.xml @@ -16,4 +16,19 @@ --> 280dp + 200dp + 4dp + 16dp + + + 28dp + + -24dp + 16dp \ No newline at end of file diff --git a/java/com/android/dialer/speeddial/res/values/strings.xml b/java/com/android/dialer/speeddial/res/values/strings.xml index 677f772c5..59a0ab5d6 100644 --- a/java/com/android/dialer/speeddial/res/values/strings.xml +++ b/java/com/android/dialer/speeddial/res/values/strings.xml @@ -40,4 +40,19 @@ Add Favorite + + + Voice Call + + + Video Call + + + Message + + + Remove + + + Contact info \ 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 new file mode 100644 index 000000000..83bbd09e5 --- /dev/null +++ b/java/com/android/dialer/speeddial/res/values/styles.xml @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file -- cgit v1.2.3