blob: 898a4a23a6e37f327980eeee018d07e4fcd805d5 [file] [log] [blame]
Steve McKay84d66782016-07-29 09:39:52 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui.dirlist;
18
19import android.content.Context;
20import android.graphics.Point;
21import android.view.DragEvent;
22import android.view.View;
23import android.view.View.OnDragListener;
24
25import com.android.documentsui.ItemDragListener;
26import com.android.documentsui.ItemDragListener.DragHost;
27import com.android.documentsui.dirlist.ViewAutoScroller.ScrollActionDelegate;
28import com.android.documentsui.dirlist.ViewAutoScroller.ScrollDistanceDelegate;
29import com.android.documentsui.R;
30
31import java.util.function.BooleanSupplier;
32import java.util.function.IntSupplier;
33
34import javax.annotation.Nullable;
35
36/**
37 * This class acts as a middle-man handler for potential auto-scrolling before passing the dragEvent
38 * onto {@link DirectoryDragListener}.
39 */
40class DragScrollListener implements OnDragListener {
41
42 private final ItemDragListener<? extends DragHost> mDragHandler;
43 private final IntSupplier mHeight;
44 private final BooleanSupplier mCanScrollUp;
45 private final BooleanSupplier mCanScrollDown;
46 private final int mAutoScrollEdgeHeight;
47 private final Runnable mDragScroller;
48
49 private boolean mDragHappening;
50 private @Nullable Point mCurrentPosition;
51
52 private DragScrollListener(
53 Context context,
54 ItemDragListener<? extends DragHost> dragHandler,
55 IntSupplier heightSupplier,
56 BooleanSupplier scrollUpSupplier,
57 BooleanSupplier scrollDownSupplier,
58 ViewAutoScroller.ScrollActionDelegate actionDelegate) {
59 mDragHandler = dragHandler;
60 mAutoScrollEdgeHeight = (int) context.getResources()
61 .getDimension(R.dimen.autoscroll_edge_height);
62 mHeight = heightSupplier;
63 mCanScrollUp = scrollUpSupplier;
64 mCanScrollDown = scrollDownSupplier;
65
66 ScrollDistanceDelegate distanceDelegate = new ScrollDistanceDelegate() {
67 @Override
68 public Point getCurrentPosition() {
69 return mCurrentPosition;
70 }
71
72 @Override
73 public int getViewHeight() {
74 return mHeight.getAsInt();
75 }
76
77 @Override
78 public boolean isActive() {
79 return mDragHappening;
80 }
81 };
82
83 mDragScroller = new ViewAutoScroller(
84 mAutoScrollEdgeHeight, distanceDelegate, actionDelegate);
85 }
86
87 static DragScrollListener create(
88 Context context, ItemDragListener<? extends DragHost> dragHandler, View scrollView) {
89 ScrollActionDelegate actionDelegate = new ScrollActionDelegate() {
90 @Override
91 public void scrollBy(int dy) {
92 scrollView.scrollBy(0, dy);
93 }
94
95 @Override
96 public void runAtNextFrame(Runnable r) {
97 scrollView.postOnAnimation(r);
98
99 }
100
101 @Override
102 public void removeCallback(Runnable r) {
103 scrollView.removeCallbacks(r);
104 }
105 };
106 DragScrollListener listener = new DragScrollListener(
107 context,
108 dragHandler,
109 scrollView::getHeight,
110 () -> {
111 return scrollView.canScrollVertically(-1);
112 },
113 () -> {
114 return scrollView.canScrollVertically(1);
115 },
116 actionDelegate);
117 return listener;
118 }
119
120 @Override
121 public boolean onDrag(View v, DragEvent event) {
122 boolean handled = false;
123 switch (event.getAction()) {
124 case DragEvent.ACTION_DRAG_STARTED:
125 mDragHappening = true;
126 break;
127 case DragEvent.ACTION_DRAG_ENDED:
128 mDragHappening = false;
129 break;
130 case DragEvent.ACTION_DRAG_ENTERED:
131 handled = insideDragZone();
132 break;
133 case DragEvent.ACTION_DRAG_LOCATION:
134 handled = handleLocationEvent(v, event.getX(), event.getY());
135 break;
136 default:
137 break;
138 }
139
140 if (!handled) {
141 handled = mDragHandler.onDrag(v, event);
142 }
143
144 return handled;
145 }
146
147 private boolean handleLocationEvent(View v, float x, float y) {
148 mCurrentPosition = new Point(Math.round(v.getX() + x), Math.round(v.getY() + y));
149 if (insideDragZone()) {
150 mDragScroller.run();
151 return true;
152 }
153 return false;
154 }
155
156 private boolean insideDragZone() {
157 if (mCurrentPosition == null) {
158 return false;
159 }
160
161 boolean shouldScrollUp = mCurrentPosition.y < mAutoScrollEdgeHeight
162 && mCanScrollUp.getAsBoolean();
163 boolean shouldScrollDown = mCurrentPosition.y > mHeight.getAsInt() - mAutoScrollEdgeHeight
164 && mCanScrollDown.getAsBoolean();
165 return shouldScrollUp || shouldScrollDown;
166 }
167}