Loading java/com/android/dialer/speeddial/ContextMenu.java +53 −12 Original line number Diff line number Diff line Loading @@ -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); } Loading @@ -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) Loading @@ -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); Loading @@ -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; } Loading @@ -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. * * <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); Loading java/com/android/dialer/speeddial/SpeedDialFragment.java +53 −12 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; /** Loading Loading @@ -78,8 +81,6 @@ public class SpeedDialFragment extends Fragment { */ private boolean updateSpeedDialItemsOnResume = true; private FavoriteContactsListener favoritesListener; public static SpeedDialFragment newInstance() { return new SpeedDialFragment(); } Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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())))); } } } java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java +58 −0 Original line number Diff line number Diff line Loading @@ -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) Loading java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml 0 → 100644 +30 −0 Original line number Diff line number Diff line <?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 java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xmldeleted 100644 → 0 +0 −21 Original line number Diff line number Diff line <?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 Loading
java/com/android/dialer/speeddial/ContextMenu.java +53 −12 Original line number Diff line number Diff line Loading @@ -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); } Loading @@ -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) Loading @@ -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); Loading @@ -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; } Loading @@ -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. * * <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); Loading
java/com/android/dialer/speeddial/SpeedDialFragment.java +53 −12 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; /** Loading Loading @@ -78,8 +81,6 @@ public class SpeedDialFragment extends Fragment { */ private boolean updateSpeedDialItemsOnResume = true; private FavoriteContactsListener favoritesListener; public static SpeedDialFragment newInstance() { return new SpeedDialFragment(); } Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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())))); } } }
java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java +58 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
java/com/android/dialer/speeddial/res/drawable/context_menu_contact_icon.xml 0 → 100644 +30 −0 Original line number Diff line number Diff line <?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
java/com/android/dialer/speeddial/res/layout/add_favorite_activity.xmldeleted 100644 → 0 +0 −21 Original line number Diff line number Diff line <?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