diff options
Diffstat (limited to 'java/com/android/dialer/speeddial/draghelper')
3 files changed, 230 insertions, 0 deletions
diff --git a/java/com/android/dialer/speeddial/draghelper/SpeedDialFavoritesViewHolderOnTouchListener.java b/java/com/android/dialer/speeddial/draghelper/SpeedDialFavoritesViewHolderOnTouchListener.java new file mode 100644 index 000000000..00fecd788 --- /dev/null +++ b/java/com/android/dialer/speeddial/draghelper/SpeedDialFavoritesViewHolderOnTouchListener.java @@ -0,0 +1,107 @@ +/* + * 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.draghelper; + +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewConfiguration; +import com.android.dialer.common.Assert; + +/** OnTouchListener for the {@link com.android.dialer.speeddial.FavoritesViewHolder}. */ +public class SpeedDialFavoritesViewHolderOnTouchListener implements OnTouchListener { + + private final ViewConfiguration configuration; + private final ItemTouchHelper itemTouchHelper; + private final ViewHolder viewHolder; + private final OnTouchFinishCallback onTouchFinishCallback; + + private boolean hasPerformedLongClick; + private float startX; + private float startY; + + public SpeedDialFavoritesViewHolderOnTouchListener( + ViewConfiguration configuration, + ItemTouchHelper itemTouchHelper, + ViewHolder viewHolder, + OnTouchFinishCallback onTouchFinishCallback) { + this.configuration = configuration; + this.itemTouchHelper = itemTouchHelper; + this.viewHolder = viewHolder; + this.onTouchFinishCallback = onTouchFinishCallback; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + startX = event.getX(); + startY = event.getY(); + return true; + case MotionEvent.ACTION_MOVE: + // If the user has long clicked the view + if (event.getEventTime() - event.getDownTime() > ViewConfiguration.getLongPressTimeout()) { + // Perform long click if we haven't already + if (!hasPerformedLongClick) { + v.performLongClick(); + v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + hasPerformedLongClick = true; + } else if (moveEventExceedsTouchSlop(event)) { + itemTouchHelper.startDrag(viewHolder); + onTouchFinishCallback.onTouchFinished(true); + } + } + return true; + case MotionEvent.ACTION_UP: + if (event.getEventTime() - event.getDownTime() < ViewConfiguration.getLongPressTimeout()) { + v.performClick(); + } + // fallthrough + case MotionEvent.ACTION_CANCEL: + hasPerformedLongClick = false; + onTouchFinishCallback.onTouchFinished(false); + return true; + default: + return false; + } + } + + private boolean moveEventExceedsTouchSlop(MotionEvent event) { + Assert.checkArgument(event.getAction() == MotionEvent.ACTION_MOVE); + if (event.getHistorySize() <= 0) { + return false; + } + + return Math.abs(startX - event.getX()) > configuration.getScaledTouchSlop() + || Math.abs(startY - event.getY()) > configuration.getScaledTouchSlop(); + } + + /** Callback to listen for on touch events ending. */ + public interface OnTouchFinishCallback { + + /** + * Called when the user stops touching the view. + * + * @see MotionEvent#ACTION_UP + * @see MotionEvent#ACTION_CANCEL + */ + void onTouchFinished(boolean closeContextMenu); + } +} diff --git a/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java b/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java new file mode 100644 index 000000000..d1d9f478b --- /dev/null +++ b/java/com/android/dialer/speeddial/draghelper/SpeedDialItemTouchHelperCallback.java @@ -0,0 +1,83 @@ +/* + * 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.draghelper; + +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.helper.ItemTouchHelper; + +/** {@link ItemTouchHelper} for Speed Dial favorite contacts. */ +public class SpeedDialItemTouchHelperCallback extends ItemTouchHelper.Callback { + + private final ItemTouchHelperAdapter adapter; + + public SpeedDialItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { + this.adapter = adapter; + } + + @Override + public boolean isLongPressDragEnabled() { + // We'll manually call ItemTouchHelper#startDrag + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + // We don't want to enable swiping + return false; + } + + @Override + public boolean canDropOver( + @NonNull RecyclerView recyclerView, @NonNull ViewHolder current, @NonNull ViewHolder target) { + return adapter.canDropOver(target); + } + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) { + if (!adapter.canDropOver(viewHolder)) { + return makeMovementFlags(0, 0); + } + + int dragFlags = + ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END; + return makeMovementFlags(dragFlags, /* swipeFlags */ 0); + } + + @Override + public boolean onMove( + @NonNull RecyclerView recyclerView, + @NonNull ViewHolder viewHolder, + @NonNull ViewHolder target) { + adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(@NonNull ViewHolder viewHolder, int direction) { + // No-op since we don't support swiping + } + + /** RecyclerView adapters interested in drag and drop should implement this interface. */ + public interface ItemTouchHelperAdapter { + + void onItemMove(int fromPosition, int toPosition); + + boolean canDropOver(ViewHolder target); + } +} diff --git a/java/com/android/dialer/speeddial/draghelper/SpeedDialLayoutManager.java b/java/com/android/dialer/speeddial/draghelper/SpeedDialLayoutManager.java new file mode 100644 index 000000000..fcc925186 --- /dev/null +++ b/java/com/android/dialer/speeddial/draghelper/SpeedDialLayoutManager.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package com.android.dialer.speeddial.draghelper; + +import android.content.Context; +import android.support.v7.widget.GridLayoutManager; + +/** {@link GridLayoutManager} that allows disabling scrolling. */ +public class SpeedDialLayoutManager extends GridLayoutManager { + + private boolean isScrollEnabled = true; + + public SpeedDialLayoutManager(Context context, int spanCount) { + super(context, spanCount); + } + + public void setScrollEnabled(boolean flag) { + this.isScrollEnabled = flag; + } + + @Override + public boolean canScrollVertically() { + // Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll + return isScrollEnabled && super.canScrollVertically(); + } +} |