1/*
2 * Copyright (C) 2015 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.launcher3.dragndrop;
18
19import android.content.Context;
20import android.view.DragEvent;
21import android.view.MotionEvent;
22import com.android.launcher3.DropTarget.DragObject;
23import com.android.launcher3.Utilities;
24
25/**
26 * Base class for driving a drag/drop operation.
27 */
28public abstract class DragDriver {
29    protected final EventListener mEventListener;
30
31    public interface EventListener {
32        void onDriverDragMove(float x, float y);
33        void onDriverDragExitWindow();
34        void onDriverDragEnd(float x, float y);
35        void onDriverDragCancel();
36    }
37
38    public DragDriver(EventListener eventListener) {
39        mEventListener = eventListener;
40    }
41
42    /**
43     * Handles ending of the DragView animation.
44     */
45    public void onDragViewAnimationEnd() { }
46
47    public boolean onTouchEvent(MotionEvent ev) {
48        final int action = ev.getAction();
49
50        switch (action) {
51            case MotionEvent.ACTION_MOVE:
52                mEventListener.onDriverDragMove(ev.getX(), ev.getY());
53                break;
54            case MotionEvent.ACTION_UP:
55                mEventListener.onDriverDragMove(ev.getX(), ev.getY());
56                mEventListener.onDriverDragEnd(ev.getX(), ev.getY());
57                break;
58            case MotionEvent.ACTION_CANCEL:
59                mEventListener.onDriverDragCancel();
60                break;
61        }
62
63        return true;
64    }
65
66    public abstract boolean onDragEvent (DragEvent event);
67
68
69    public boolean onInterceptTouchEvent(MotionEvent ev) {
70        final int action = ev.getAction();
71
72        switch (action) {
73            case MotionEvent.ACTION_UP:
74                mEventListener.onDriverDragEnd(ev.getX(), ev.getY());
75                break;
76            case MotionEvent.ACTION_CANCEL:
77                mEventListener.onDriverDragCancel();
78                break;
79        }
80
81        return true;
82    }
83
84    public static DragDriver create(Context context, DragController dragController,
85            DragObject dragObject, DragOptions options) {
86        if (Utilities.ATLEAST_NOUGAT && options.systemDndStartPoint != null) {
87            return new SystemDragDriver(dragController, context, dragObject);
88        } else {
89            return new InternalDragDriver(dragController);
90        }
91    }
92}
93
94/**
95 * Class for driving a system (i.e. framework) drag/drop operation.
96 */
97class SystemDragDriver extends DragDriver {
98
99    float mLastX = 0;
100    float mLastY = 0;
101
102    SystemDragDriver(DragController dragController, Context context, DragObject dragObject) {
103        super(dragController);
104    }
105
106    @Override
107    public boolean onTouchEvent(MotionEvent ev) {
108        return false;
109    }
110
111    @Override
112    public boolean onInterceptTouchEvent(MotionEvent ev) {
113        return false;
114    }
115
116    @Override
117    public boolean onDragEvent (DragEvent event) {
118        final int action = event.getAction();
119
120        switch (action) {
121            case DragEvent.ACTION_DRAG_STARTED:
122                mLastX = event.getX();
123                mLastY = event.getY();
124                return true;
125
126            case DragEvent.ACTION_DRAG_ENTERED:
127                return true;
128
129            case DragEvent.ACTION_DRAG_LOCATION:
130                mLastX = event.getX();
131                mLastY = event.getY();
132                mEventListener.onDriverDragMove(event.getX(), event.getY());
133                return true;
134
135            case DragEvent.ACTION_DROP:
136                mLastX = event.getX();
137                mLastY = event.getY();
138                mEventListener.onDriverDragMove(event.getX(), event.getY());
139                mEventListener.onDriverDragEnd(mLastX, mLastY);
140                return true;
141            case DragEvent.ACTION_DRAG_EXITED:
142                mEventListener.onDriverDragExitWindow();
143                return true;
144
145            case DragEvent.ACTION_DRAG_ENDED:
146                mEventListener.onDriverDragCancel();
147                return true;
148
149            default:
150                return false;
151        }
152    }
153}
154
155/**
156 * Class for driving an internal (i.e. not using framework) drag/drop operation.
157 */
158class InternalDragDriver extends DragDriver {
159    InternalDragDriver(DragController dragController) {
160        super(dragController);
161    }
162
163    @Override
164    public boolean onDragEvent (DragEvent event) { return false; }
165}
166