summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryueg <yueg@google.com>2018-06-19 16:54:38 -0700
committerCopybara-Service <copybara-piper@google.com>2018-06-19 16:55:54 -0700
commit406de13ab4326bbedae0262709a004da2211d04c (patch)
tree5e9f525d8dc782b1ba778b191184d0960617bcc9
parentacfab4ed674bb7b0154373c626ce494f37629509 (diff)
Drag favorite to remove
Test: RemoveViewHolderTest, SpeedDialAdapterTest PiperOrigin-RevId: 201266033 Change-Id: Ie7ed9bac8ad9c7bbc35c351409b629e3fbad3de8
-rw-r--r--java/com/android/dialer/main/impl/res/layout/main_activity.xml12
-rw-r--r--java/com/android/dialer/speeddial/FavoritesViewHolder.java15
-rw-r--r--java/com/android/dialer/speeddial/RemoveViewHolder.java49
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialAdapter.java128
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialFragment.java138
-rw-r--r--java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java62
-rw-r--r--java/com/android/dialer/speeddial/res/layout/favorite_remove_view_layout.xml49
-rw-r--r--java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml7
-rw-r--r--java/com/android/dialer/speeddial/res/values/dimens.xml2
-rw-r--r--java/com/android/dialer/speeddial/res/values/strings.xml3
10 files changed, 381 insertions, 84 deletions
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">
<!-- MainToolbar -->
<include
@@ -33,13 +35,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar"
- android:layout_above="@+id/bottom_nav_bar">
+ android:layout_above="@+id/bottom_nav_bar"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<!-- Holds SpeedDial, Call Log, Contacts, Voicemail and Search fragments -->
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"/>
<FrameLayout
android:id="@+id/search_fragment_container"
diff --git a/java/com/android/dialer/speeddial/FavoritesViewHolder.java b/java/com/android/dialer/speeddial/FavoritesViewHolder.java
index f06672d8d..600c8c734 100644
--- a/java/com/android/dialer/speeddial/FavoritesViewHolder.java
+++ b/java/com/android/dialer/speeddial/FavoritesViewHolder.java
@@ -46,6 +46,8 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder
private final TextView phoneType;
private final FrameLayout videoCallIcon;
+ private final FrameLayout avatarContainer;
+
private SpeedDialUiItem speedDialUiItem;
public FavoritesViewHolder(View view, ItemTouchHelper helper, FavoriteContactsListener listener) {
@@ -54,6 +56,7 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder
nameView = view.findViewById(R.id.name);
phoneType = view.findViewById(R.id.phone_type);
videoCallIcon = view.findViewById(R.id.video_call_container);
+ avatarContainer = view.findViewById(R.id.avatar_container);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
view.setOnTouchListener(
@@ -117,6 +120,15 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder
listener.onTouchFinished(closeContextMenu);
}
+ FrameLayout getAvatarContainer() {
+ return avatarContainer;
+ }
+
+ void onSelectedChanged(boolean selected) {
+ nameView.setVisibility(selected ? View.GONE : View.VISIBLE);
+ phoneType.setVisibility(selected ? View.GONE : View.VISIBLE);
+ }
+
/** Listener/callback for {@link FavoritesViewHolder} actions. */
public interface FavoriteContactsListener {
@@ -131,5 +143,8 @@ public class FavoritesViewHolder extends RecyclerView.ViewHolder
/** Called when the user is no longer touching the favorite contact. */
void onTouchFinished(boolean closeContextMenu);
+
+ /** Called when the user drag the favorite to remove. */
+ void onRequestRemove(SpeedDialUiItem speedDialUiItem);
}
}
diff --git a/java/com/android/dialer/speeddial/RemoveViewHolder.java b/java/com/android/dialer/speeddial/RemoveViewHolder.java
new file mode 100644
index 000000000..998e1ae2f
--- /dev/null
+++ b/java/com/android/dialer/speeddial/RemoveViewHolder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+/** ViewHolder for headers in {@link SpeedDialFragment}. */
+public class RemoveViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
+
+ private final View removeViewContent;
+
+ RemoveViewHolder(View view) {
+ super(view);
+ removeViewContent = view;
+ }
+
+ void show() {
+ removeViewContent.setVisibility(View.VISIBLE);
+ removeViewContent.setAlpha(0);
+ removeViewContent.animate().alpha(1).start();
+ }
+
+ void hide() {
+ removeViewContent.setVisibility(View.INVISIBLE);
+ removeViewContent.setAlpha(1);
+ removeViewContent.animate().alpha(0).start();
+ }
+
+ @Override
+ public void onClick(View v) {
+ // Not clickable
+ }
+}
diff --git a/java/com/android/dialer/speeddial/SpeedDialAdapter.java b/java/com/android/dialer/speeddial/SpeedDialAdapter.java
index a382b1a6b..ff52a0745 100644
--- a/java/com/android/dialer/speeddial/SpeedDialAdapter.java
+++ b/java/com/android/dialer/speeddial/SpeedDialAdapter.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.os.Build.VERSION_CODES;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -28,6 +29,8 @@ import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.ViewGroup;
+import android.view.animation.AnticipateInterpolator;
+import android.widget.FrameLayout;
import com.android.dialer.common.Assert;
import com.android.dialer.speeddial.FavoritesViewHolder.FavoriteContactsListener;
import com.android.dialer.speeddial.HeaderViewHolder.SpeedDialHeaderListener;
@@ -58,13 +61,20 @@ import java.util.Map;
public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
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<RecyclerView.Vi
// Needed for FavoriteViewHolder
private ItemTouchHelper itemTouchHelper;
+ private RemoveViewHolder removeViewHolder;
+ private FavoritesViewHolder draggingFavoritesViewHolder;
+
public SpeedDialAdapter(
Context context,
FavoriteContactsListener favoritesListener,
@@ -111,6 +124,11 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
case RowType.SUGGESTION_HEADER:
return new HeaderViewHolder(
inflater.inflate(R.layout.speed_dial_header_layout, parent, false), headerListener);
+ case RowType.REMOVE_VIEW:
+ removeViewHolder =
+ new RemoveViewHolder(
+ inflater.inflate(R.layout.favorite_remove_view_layout, parent, false));
+ return removeViewHolder;
default:
throw Assert.createIllegalStateFailException("Invalid viewType: " + viewType);
}
@@ -128,10 +146,17 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
((HeaderViewHolder) holder).showAddButton(false);
return;
case RowType.STARRED:
- ((FavoritesViewHolder) holder).bind(context, speedDialUiItems.get(position - 1));
+ ((FavoritesViewHolder) holder).bind(context, speedDialUiItems.get(position - 2));
+ // Removed item might come back
+ FrameLayout avatarContainer = ((FavoritesViewHolder) holder).getAvatarContainer();
+ avatarContainer.setScaleX(1);
+ avatarContainer.setScaleY(1);
+ avatarContainer.setAlpha(1);
break;
case RowType.SUGGESTION:
- ((SuggestionViewHolder) holder).bind(context, speedDialUiItems.get(position - 2));
+ ((SuggestionViewHolder) holder).bind(context, speedDialUiItems.get(position - 3));
+ break;
+ case RowType.REMOVE_VIEW:
break;
default:
throw Assert.createIllegalStateFailException("Invalid view holder: " + holder);
@@ -153,20 +178,25 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
}
return Boolean.compare(o2.isStarred(), o1.isStarred());
});
+ updatePositionToRowTypeMap();
+ }
+
+ private void updatePositionToRowTypeMap() {
positionToRowTypeMap.clear();
if (speedDialUiItems.isEmpty()) {
return;
}
+ positionToRowTypeMap.put(0, RowType.REMOVE_VIEW);
// Show the add favorites even if there are no favorite contacts
- positionToRowTypeMap.put(0, RowType.STARRED_HEADER);
- int positionOfSuggestionHeader = 1;
+ positionToRowTypeMap.put(1, RowType.STARRED_HEADER);
+ int positionOfSuggestionHeader = NON_CONTACT_ITEM_NUMBER_BEFORE_FAVORITES;
for (int i = 0; i < speedDialUiItems.size(); i++) {
if (speedDialUiItems.get(i).isStarred()) {
- positionToRowTypeMap.put(i + 1, RowType.STARRED); // +1 for the header
+ positionToRowTypeMap.put(i + NON_CONTACT_ITEM_NUMBER_BEFORE_FAVORITES, RowType.STARRED);
positionOfSuggestionHeader++;
} else {
- positionToRowTypeMap.put(i + 2, RowType.SUGGESTION); // +2 for both headers
+ positionToRowTypeMap.put(i + NON_CONTACT_ITEM_NUMBER_BEFORE_SUGGESTION, RowType.SUGGESTION);
}
}
if (!speedDialUiItems.get(speedDialUiItems.size() - 1).isStarred()) {
@@ -189,6 +219,7 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
case RowType.SUGGESTION:
case RowType.STARRED_HEADER:
case RowType.SUGGESTION_HEADER:
+ case RowType.REMOVE_VIEW:
return 3; // span the whole screen
case RowType.STARRED:
return 1; // span 1/3 of the screen
@@ -202,15 +233,88 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
@Override
public void onItemMove(int fromPosition, int toPosition) {
+ if (toPosition == 0) {
+ // drop to removeView
+ return;
+ }
// fromPosition/toPosition correspond to adapter position, which is off by 1 from the list
// position b/c of the favorites header. So subtract 1 here.
- speedDialUiItems.add(toPosition - 1, speedDialUiItems.remove(fromPosition - 1));
+ speedDialUiItems.add(toPosition - 2, speedDialUiItems.remove(fromPosition - 2));
notifyItemMoved(fromPosition, toPosition);
}
@Override
public boolean canDropOver(ViewHolder target) {
- return target instanceof FavoritesViewHolder;
+ return target instanceof FavoritesViewHolder || target instanceof RemoveViewHolder;
+ }
+
+ @Override
+ public void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState) {
+ switch (actionState) {
+ case ItemTouchHelper.ACTION_STATE_DRAG:
+ if (viewHolder != null) {
+ draggingFavoritesViewHolder = (FavoritesViewHolder) viewHolder;
+ draggingFavoritesViewHolder.onSelectedChanged(true);
+ removeViewHolder.show();
+ }
+ break;
+ case ItemTouchHelper.ACTION_STATE_IDLE:
+ // viewHolder is null in this case
+ if (draggingFavoritesViewHolder != null) {
+ draggingFavoritesViewHolder.onSelectedChanged(false);
+ draggingFavoritesViewHolder = null;
+ removeViewHolder.hide();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void enterRemoveView() {
+ if (draggingFavoritesViewHolder != null) {
+ draggingFavoritesViewHolder
+ .getAvatarContainer()
+ .animate()
+ .scaleX(IN_REMOVE_VIEW_SCALE)
+ .scaleY(IN_REMOVE_VIEW_SCALE)
+ .alpha(IN_REMOVE_VIEW_ALPHA)
+ .start();
+ }
+ }
+
+ @Override
+ public void leaveRemoveView() {
+ if (draggingFavoritesViewHolder != null) {
+ draggingFavoritesViewHolder
+ .getAvatarContainer()
+ .animate()
+ .scaleX(1)
+ .scaleY(1)
+ .alpha(1)
+ .start();
+ }
+ }
+
+ @Override
+ public void dropOnRemoveView(ViewHolder fromViewHolder) {
+ if (!(fromViewHolder instanceof FavoritesViewHolder)) {
+ return;
+ }
+ int fromPosition = fromViewHolder.getAdapterPosition();
+
+ SpeedDialUiItem removedItem = speedDialUiItems.remove(fromPosition - 2);
+ favoritesListener.onRequestRemove(removedItem);
+ ((FavoritesViewHolder) fromViewHolder)
+ .getAvatarContainer()
+ .animate()
+ .scaleX(0)
+ .scaleY(0)
+ .alpha(0)
+ .setInterpolator(new AnticipateInterpolator())
+ .start();
+ updatePositionToRowTypeMap();
}
public void setItemTouchHelper(ItemTouchHelper itemTouchHelper) {
diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java
index c48eb8d68..aabf28bcb 100644
--- a/java/com/android/dialer/speeddial/SpeedDialFragment.java
+++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java
@@ -151,9 +151,9 @@ public class SpeedDialFragment extends Fragment {
new SpeedDialFavoritesListener(
getActivity(),
getChildFragmentManager(),
- new SpeedDialContextMenuItemListener(
- getActivity(), new UpdateSpeedDialAdapterListener(), speedDialLoaderListener),
- layoutManager);
+ layoutManager,
+ new UpdateSpeedDialAdapterListener(),
+ speedDialLoaderListener);
adapter =
new SpeedDialAdapter(getContext(), favoritesListener, suggestedListener, headerListener);
layoutManager.setSpanSizeLookup(adapter.getSpanSizeLookup());
@@ -339,20 +339,26 @@ public class SpeedDialFragment extends Fragment {
private final FragmentActivity activity;
private final FragmentManager childFragmentManager;
- private final ContextMenuItemListener contextMenuListener;
private final SpeedDialLayoutManager layoutManager;
+ private final UpdateSpeedDialAdapterListener updateAdapterListener;
+ private final SupportUiListener<ImmutableList<SpeedDialUiItem>> speedDialLoaderListener;
+
+ private final SpeedDialContextMenuItemListener speedDialContextMenuItemListener =
+ new SpeedDialContextMenuItemListener();
private ContextMenu contextMenu;
SpeedDialFavoritesListener(
FragmentActivity activity,
FragmentManager childFragmentManager,
- ContextMenuItemListener contextMenuListener,
- SpeedDialLayoutManager layoutManager) {
+ SpeedDialLayoutManager layoutManager,
+ UpdateSpeedDialAdapterListener updateAdapterListener,
+ SupportUiListener<ImmutableList<SpeedDialUiItem>> 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<ImmutableList<SpeedDialUiItem>> speedDialLoaderListener;
- private final UpdateSpeedDialAdapterListener updateAdapterListener;
-
- SpeedDialContextMenuItemListener(
- FragmentActivity activity,
- UpdateSpeedDialAdapterListener updateAdapterListener,
- SupportUiListener<ImmutableList<SpeedDialUiItem>> 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<SpeedDialUiItem> 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,11 +72,57 @@ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<!-- Sets android:importantForAccessibility="no" to avoid being announced when navigating with
+ talkback enabled. It will still be announced when user drag or drop contact onto it.
+ This is required since drag and drop event is only sent to views are visible when drag
+ starts. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/favorite_remove_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/expanded_search_bar_height"
+ android:background="?android:attr/colorPrimary"
+ android:gravity="center"
+ android:orientation="horizontal"
+ android:visibility="invisible"
+ android:contentDescription="@string/speed_dial_remove_favorites"
+ android:importantForAccessibility="no">
+
+ <ImageView
+ android:id="@+id/remove_view_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:src="@drawable/quantum_ic_close_vd_theme_24"
+ android:tint="?colorIconOnUnthemedDarkBackground"/>
+
+ <TextView
+ android:id="@+id/remove_view_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/speed_dial_remove_favorites"
+ android:textColor="?colorTextOnUnthemedDarkBackground"
+ android:textSize="16sp"/>
+</LinearLayout> \ 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 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/speed_dial_root"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<android.support.v7.widget.RecyclerView
android:id="@+id/speed_dial_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/expanded_search_bar_height_minus"
android:clipToPadding="false"
- android:background="?android:attr/colorBackground"
+ android:background="@android:color/transparent"
android:paddingBottom="@dimen/floating_action_button_list_bottom_padding"/>
<com.android.dialer.widget.EmptyContentView
diff --git a/java/com/android/dialer/speeddial/res/values/dimens.xml b/java/com/android/dialer/speeddial/res/values/dimens.xml
index a4cf16c17..624c60dd3 100644
--- a/java/com/android/dialer/speeddial/res/values/dimens.xml
+++ b/java/com/android/dialer/speeddial/res/values/dimens.xml
@@ -32,4 +32,6 @@
<dimen name="speed_dial_context_menu_x_offset">-24dp</dimen>
<dimen name="speed_dial_context_menu_corner_radius">16dp</dimen>
<dimen name="disambig_dialog_width">280dp</dimen>
+ <dimen name="expanded_search_bar_height">64dp</dimen>
+ <dimen name="expanded_search_bar_height_minus">-64dp</dimen>
</resources> \ 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 @@
<!-- [CHAR LIMIT=NONE] Shown as an action when the all contacts list is empty -->
<string name="speed_dial_no_contacts_action_text">Add favorite</string>
+
+ <!-- Text shown on a dragging target that removes the contact from favorites -->
+ <string name="speed_dial_remove_favorites">Remove from favorites</string>
</resources> \ No newline at end of file