From 406de13ab4326bbedae0262709a004da2211d04c Mon Sep 17 00:00:00 2001 From: yueg Date: Tue, 19 Jun 2018 16:54:38 -0700 Subject: Drag favorite to remove Test: RemoveViewHolderTest, SpeedDialAdapterTest PiperOrigin-RevId: 201266033 Change-Id: Ie7ed9bac8ad9c7bbc35c351409b629e3fbad3de8 --- .../dialer/main/impl/res/layout/main_activity.xml | 12 +- .../dialer/speeddial/FavoritesViewHolder.java | 15 +++ .../android/dialer/speeddial/RemoveViewHolder.java | 49 ++++++++ .../android/dialer/speeddial/SpeedDialAdapter.java | 128 +++++++++++++++++-- .../dialer/speeddial/SpeedDialFragment.java | 138 +++++++++++---------- .../SpeedDialItemTouchHelperCallback.java | 62 +++++++++ .../res/layout/favorite_remove_view_layout.xml | 49 ++++++++ .../speeddial/res/layout/fragment_speed_dial.xml | 7 +- .../android/dialer/speeddial/res/values/dimens.xml | 2 + .../dialer/speeddial/res/values/strings.xml | 3 + 10 files changed, 381 insertions(+), 84 deletions(-) create mode 100644 java/com/android/dialer/speeddial/RemoveViewHolder.java create mode 100644 java/com/android/dialer/speeddial/res/layout/favorite_remove_view_layout.xml (limited to 'java') diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml index b47806ece..5cb457ec9 100644 --- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml +++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml @@ -19,7 +19,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/root_layout" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:clipChildren="false" + android:clipToPadding="false"> + android:layout_above="@+id/bottom_nav_bar" + android:clipChildren="false" + android:clipToPadding="false"> + android:layout_height="match_parent" + android:clipChildren="false" + android:clipToPadding="false"/> implements ItemTouchHelperAdapter { + private static final int NON_CONTACT_ITEM_NUMBER_BEFORE_FAVORITES = 2; + private static final int NON_CONTACT_ITEM_NUMBER_BEFORE_SUGGESTION = 3; + + private static final float IN_REMOVE_VIEW_SCALE = 0.5f; + private static final float IN_REMOVE_VIEW_ALPHA = 0.5f; + @Retention(RetentionPolicy.SOURCE) @IntDef({RowType.STARRED_HEADER, RowType.SUGGESTION_HEADER, RowType.STARRED, RowType.SUGGESTION}) @interface RowType { - int STARRED_HEADER = 0; - int SUGGESTION_HEADER = 1; - int STARRED = 2; - int SUGGESTION = 3; + int REMOVE_VIEW = 0; + int STARRED_HEADER = 1; + int SUGGESTION_HEADER = 2; + int STARRED = 3; + int SUGGESTION = 4; } private final Context context; @@ -78,6 +88,9 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter> speedDialLoaderListener; + + private final SpeedDialContextMenuItemListener speedDialContextMenuItemListener = + new SpeedDialContextMenuItemListener(); private ContextMenu contextMenu; SpeedDialFavoritesListener( FragmentActivity activity, FragmentManager childFragmentManager, - ContextMenuItemListener contextMenuListener, - SpeedDialLayoutManager layoutManager) { + SpeedDialLayoutManager layoutManager, + UpdateSpeedDialAdapterListener updateAdapterListener, + SupportUiListener> speedDialLoaderListener) { this.activity = activity; this.childFragmentManager = childFragmentManager; - this.contextMenuListener = contextMenuListener; this.layoutManager = layoutManager; + this.updateAdapterListener = updateAdapterListener; + this.speedDialLoaderListener = speedDialLoaderListener; } @Override @@ -384,7 +390,8 @@ public class SpeedDialFragment extends Fragment { @Override public void showContextMenu(View view, SpeedDialUiItem speedDialUiItem) { layoutManager.setScrollEnabled(false); - contextMenu = ContextMenu.show(activity, view, contextMenuListener, speedDialUiItem); + contextMenu = + ContextMenu.show(activity, view, speedDialContextMenuItemListener, speedDialUiItem); } @Override @@ -397,12 +404,66 @@ public class SpeedDialFragment extends Fragment { } } - public void hideMenu() { + @Override + public void onRequestRemove(SpeedDialUiItem speedDialUiItem) { + speedDialContextMenuItemListener.removeFavoriteContact(speedDialUiItem); + } + + void hideMenu() { if (contextMenu != null) { contextMenu.hide(); contextMenu = null; } } + + public SpeedDialContextMenuItemListener getSpeedDialContextMenuItemListener() { + return speedDialContextMenuItemListener; + } + + class SpeedDialContextMenuItemListener implements ContextMenuItemListener { + + @Override + public void placeCall(Channel channel) { + if (channel.technology() == Channel.DUO) { + Logger.get(activity) + .logImpression( + DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_FAVORITE_CONTACT); + } + PreCall.start( + activity, + new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) + .setAllowAssistedDial(true) + .setIsVideoCall(channel.isVideoTechnology()) + .setIsDuoCall(channel.technology() == Channel.DUO)); + } + + @Override + public void openSmsConversation(String number) { + activity.startActivity(IntentUtil.getSendSmsIntent(number)); + } + + @Override + public void removeFavoriteContact(SpeedDialUiItem speedDialUiItem) { + speedDialLoaderListener.listen( + activity, + UiItemLoaderComponent.get(activity) + .speedDialUiItemMutator() + .removeSpeedDialUiItem(speedDialUiItem), + updateAdapterListener::updateAdapter, + throwable -> { + throw new RuntimeException(throwable); + }); + } + + @Override + public void openContactInfo(SpeedDialUiItem speedDialUiItem) { + activity.startActivity( + new Intent( + Intent.ACTION_VIEW, + Uri.withAppendedPath( + Contacts.CONTENT_URI, String.valueOf(speedDialUiItem.contactId())))); + } + } } private final class SpeedDialSuggestedListener implements SuggestedContactsListener { @@ -530,63 +591,6 @@ public class SpeedDialFragment extends Fragment { } } - private static final class SpeedDialContextMenuItemListener implements ContextMenuItemListener { - - private final FragmentActivity activity; - private final SupportUiListener> speedDialLoaderListener; - private final UpdateSpeedDialAdapterListener updateAdapterListener; - - SpeedDialContextMenuItemListener( - FragmentActivity activity, - UpdateSpeedDialAdapterListener updateAdapterListener, - SupportUiListener> speedDialLoaderListener) { - this.activity = activity; - this.updateAdapterListener = updateAdapterListener; - this.speedDialLoaderListener = speedDialLoaderListener; - } - - @Override - public void placeCall(Channel channel) { - if (channel.technology() == Channel.DUO) { - Logger.get(activity) - .logImpression(DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FOR_FAVORITE_CONTACT); - } - PreCall.start( - activity, - new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL) - .setAllowAssistedDial(true) - .setIsVideoCall(channel.isVideoTechnology()) - .setIsDuoCall(channel.technology() == Channel.DUO)); - } - - @Override - public void openSmsConversation(String number) { - activity.startActivity(IntentUtil.getSendSmsIntent(number)); - } - - @Override - public void removeFavoriteContact(SpeedDialUiItem speedDialUiItem) { - speedDialLoaderListener.listen( - activity, - UiItemLoaderComponent.get(activity) - .speedDialUiItemMutator() - .removeSpeedDialUiItem(speedDialUiItem), - updateAdapterListener::updateAdapter, - throwable -> { - throw new RuntimeException(throwable); - }); - } - - @Override - public void openContactInfo(SpeedDialUiItem speedDialUiItem) { - activity.startActivity( - new Intent( - Intent.ACTION_VIEW, - Uri.withAppendedPath( - Contacts.CONTENT_URI, String.valueOf(speedDialUiItem.contactId())))); - } - } - private static final class SpeedDialContactPermissionEmptyViewListener implements OnEmptyViewActionButtonClickedListener { @@ -628,7 +632,7 @@ public class SpeedDialFragment extends Fragment { } /** Listener for when a SpeedDialUiItem is updated. */ - private class UpdateSpeedDialAdapterListener { + class UpdateSpeedDialAdapterListener { void updateAdapter(ImmutableList speedDialUiItems) { onSpeedDialUiItemListLoaded(speedDialUiItems); diff --git a/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java b/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java index d1d9f478b..fc963a1a3 100644 --- a/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java +++ b/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java @@ -16,7 +16,9 @@ package com.android.dialer.speeddial.draghelper; +import android.graphics.Canvas; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.helper.ItemTouchHelper; @@ -26,6 +28,12 @@ public class SpeedDialItemTouchHelperCallback extends ItemTouchHelper.Callback { private final ItemTouchHelperAdapter adapter; + // When dragged item is in removeView, onMove() and onChildDraw() are called in turn. This + // behavior changes when dragged item entering/leaving removeView. The boolean field + // movedOverRemoveView is for onMove() and onChildDraw() to flip. + private boolean movedOverRemoveView; + private boolean inRemoveView; + public SpeedDialItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { this.adapter = adapter; } @@ -64,10 +72,56 @@ public class SpeedDialItemTouchHelperCallback extends ItemTouchHelper.Callback { @NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder, @NonNull ViewHolder target) { + if (target.getItemViewType() == 0) { // 0 for RowType.REMOVE_VIEW + movedOverRemoveView = true; + if (!inRemoveView) { + // onMove() first called + adapter.enterRemoveView(); + inRemoveView = true; + } + return false; + } else if (inRemoveView) { + // Move out of removeView fast + inRemoveView = false; + movedOverRemoveView = false; + adapter.leaveRemoveView(); + } adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; } + @Override + public void onChildDraw( + @NonNull Canvas canvas, + @NonNull RecyclerView recyclerView, + @NonNull ViewHolder viewHolder, + float dx, + float dy, + int i, + boolean isCurrentlyActive) { + if (inRemoveView) { + if (!isCurrentlyActive) { + // View animating back to its original state, which means drop in this case + inRemoveView = false; + adapter.dropOnRemoveView(viewHolder); + } + if (!movedOverRemoveView) { + // when the view is over a droppable target, onMove() will be called before onChildDraw() + // thus if onMove() is not called, it is not over a droppable target. + inRemoveView = false; + adapter.leaveRemoveView(); + } + } + movedOverRemoveView = false; + super.onChildDraw(canvas, recyclerView, viewHolder, dx, dy, i, isCurrentlyActive); + } + + @Override + public void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState) { + super.onSelectedChanged(viewHolder, actionState); + adapter.onSelectedChanged(viewHolder, actionState); + } + @Override public void onSwiped(@NonNull ViewHolder viewHolder, int direction) { // No-op since we don't support swiping @@ -79,5 +133,13 @@ public class SpeedDialItemTouchHelperCallback extends ItemTouchHelper.Callback { void onItemMove(int fromPosition, int toPosition); boolean canDropOver(ViewHolder target); + + void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState); + + void enterRemoveView(); + + void leaveRemoveView(); + + void dropOnRemoveView(ViewHolder fromViewHolder); } } diff --git a/java/com/android/dialer/speeddial/res/layout/favorite_remove_view_layout.xml b/java/com/android/dialer/speeddial/res/layout/favorite_remove_view_layout.xml new file mode 100644 index 000000000..825658c37 --- /dev/null +++ b/java/com/android/dialer/speeddial/res/layout/favorite_remove_view_layout.xml @@ -0,0 +1,49 @@ + + + + + + + + + + \ 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 e289bb794..472f9e951 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 @@ -17,14 +17,17 @@ + android:layout_height="match_parent" + android:clipChildren="false" + android:clipToPadding="false"> -24dp 16dp 280dp + 64dp + -64dp \ 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 7f8fed51f..397ec8f5e 100644 --- a/java/com/android/dialer/speeddial/res/values/strings.xml +++ b/java/com/android/dialer/speeddial/res/values/strings.xml @@ -71,4 +71,7 @@ Add favorite + + + Remove from favorites \ No newline at end of file -- cgit v1.2.3