Loading java/com/android/dialer/main/impl/res/layout/main_activity.xml +9 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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" Loading java/com/android/dialer/speeddial/FavoritesViewHolder.java +15 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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( Loading Loading @@ -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 { Loading @@ -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); } } java/com/android/dialer/speeddial/RemoveViewHolder.java 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * 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 } } java/com/android/dialer/speeddial/SpeedDialAdapter.java +116 −12 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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, Loading Loading @@ -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); } Loading @@ -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); Loading @@ -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()) { Loading @@ -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 Loading @@ -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) { Loading java/com/android/dialer/speeddial/SpeedDialFragment.java +71 −67 Original line number Diff line number Diff line Loading @@ -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()); Loading Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 { Loading Loading @@ -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 { Loading Loading @@ -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); Loading Loading
java/com/android/dialer/main/impl/res/layout/main_activity.xml +9 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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" Loading
java/com/android/dialer/speeddial/FavoritesViewHolder.java +15 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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( Loading Loading @@ -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 { Loading @@ -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); } }
java/com/android/dialer/speeddial/RemoveViewHolder.java 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * 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 } }
java/com/android/dialer/speeddial/SpeedDialAdapter.java +116 −12 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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, Loading Loading @@ -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); } Loading @@ -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); Loading @@ -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()) { Loading @@ -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 Loading @@ -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) { Loading
java/com/android/dialer/speeddial/SpeedDialFragment.java +71 −67 Original line number Diff line number Diff line Loading @@ -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()); Loading Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 { Loading Loading @@ -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 { Loading Loading @@ -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); Loading