Home | History | Annotate | Download | only in dragndrop
      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 
     17 package com.android.launcher3.dragndrop;
     18 
     19 import android.content.ClipData;
     20 import android.content.ClipDescription;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.view.DragEvent;
     24 import android.view.MotionEvent;
     25 
     26 import com.android.launcher3.DropTarget;
     27 import com.android.launcher3.DropTarget.DragObject;
     28 import com.android.launcher3.InstallShortcutReceiver;
     29 import com.android.launcher3.ShortcutInfo;
     30 import com.android.launcher3.Utilities;
     31 
     32 import java.util.ArrayList;
     33 
     34 /**
     35  * Base class for driving a drag/drop operation.
     36  */
     37 public abstract class DragDriver {
     38     protected final EventListener mEventListener;
     39 
     40     public interface EventListener {
     41         void onDriverDragMove(float x, float y);
     42         void onDriverDragExitWindow();
     43         void onDriverDragEnd(float x, float y, DropTarget dropTargetOverride);
     44         void onDriverDragCancel();
     45     }
     46 
     47     public DragDriver(EventListener eventListener) {
     48         mEventListener = eventListener;
     49     }
     50 
     51     /**
     52      * Handles ending of the DragView animation.
     53      */
     54     public void onDragViewAnimationEnd() { }
     55 
     56     public boolean onTouchEvent(MotionEvent ev) {
     57         final int action = ev.getAction();
     58 
     59         switch (action) {
     60             case MotionEvent.ACTION_MOVE:
     61                 mEventListener.onDriverDragMove(ev.getX(), ev.getY());
     62                 break;
     63             case MotionEvent.ACTION_UP:
     64                 mEventListener.onDriverDragMove(ev.getX(), ev.getY());
     65                 mEventListener.onDriverDragEnd(ev.getX(), ev.getY(), null);
     66                 break;
     67             case MotionEvent.ACTION_CANCEL:
     68                 mEventListener.onDriverDragCancel();
     69                 break;
     70         }
     71 
     72         return true;
     73     }
     74 
     75     public abstract boolean onDragEvent (DragEvent event);
     76 
     77 
     78     public boolean onInterceptTouchEvent(MotionEvent ev) {
     79         final int action = ev.getAction();
     80 
     81         switch (action) {
     82             case MotionEvent.ACTION_UP:
     83                 mEventListener.onDriverDragEnd(ev.getX(), ev.getY(), null);
     84                 break;
     85             case MotionEvent.ACTION_CANCEL:
     86                 mEventListener.onDriverDragCancel();
     87                 break;
     88         }
     89 
     90         return true;
     91     }
     92 
     93     public static DragDriver create(Context context, DragController dragController,
     94             DragObject dragObject, DragOptions options) {
     95         if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) {
     96             return new SystemDragDriver(dragController, context, dragObject);
     97         } else {
     98             return new InternalDragDriver(dragController);
     99         }
    100     }
    101 }
    102 
    103 /**
    104  * Class for driving a system (i.e. framework) drag/drop operation.
    105  */
    106 class SystemDragDriver extends DragDriver {
    107 
    108     private final DragObject mDragObject;
    109     private final Context mContext;
    110 
    111     boolean mReceivedDropEvent = false;
    112     float mLastX = 0;
    113     float mLastY = 0;
    114 
    115     public SystemDragDriver(DragController dragController, Context context, DragObject dragObject) {
    116         super(dragController);
    117         mDragObject = dragObject;
    118         mContext = context;
    119     }
    120 
    121     @Override
    122     public boolean onTouchEvent(MotionEvent ev) {
    123         return false;
    124     }
    125 
    126     @Override
    127     public boolean onInterceptTouchEvent(MotionEvent ev) {
    128         return false;
    129     }
    130 
    131     @Override
    132     public boolean onDragEvent (DragEvent event) {
    133         final int action = event.getAction();
    134 
    135         switch (action) {
    136             case DragEvent.ACTION_DRAG_STARTED:
    137                 mLastX = event.getX();
    138                 mLastY = event.getY();
    139                 return true;
    140 
    141             case DragEvent.ACTION_DRAG_ENTERED:
    142                 return true;
    143 
    144             case DragEvent.ACTION_DRAG_LOCATION:
    145                 mLastX = event.getX();
    146                 mLastY = event.getY();
    147                 mEventListener.onDriverDragMove(event.getX(), event.getY());
    148                 return true;
    149 
    150             case DragEvent.ACTION_DROP:
    151                 mLastX = event.getX();
    152                 mLastY = event.getY();
    153                 mReceivedDropEvent =
    154                         updateInfoFromClipData(event.getClipData(), event.getClipDescription());
    155                 return mReceivedDropEvent;
    156 
    157             case DragEvent.ACTION_DRAG_EXITED:
    158                 mEventListener.onDriverDragExitWindow();
    159                 return true;
    160 
    161             case DragEvent.ACTION_DRAG_ENDED:
    162                 if (mReceivedDropEvent) {
    163                     mEventListener.onDriverDragEnd(mLastX, mLastY, null);
    164                 } else {
    165                     mEventListener.onDriverDragCancel();
    166                 }
    167                 return true;
    168 
    169             default:
    170                 return false;
    171         }
    172     }
    173 
    174     private boolean updateInfoFromClipData(ClipData data, ClipDescription desc) {
    175         if (data == null) {
    176             return false;
    177         }
    178         ArrayList<Intent> intents = new ArrayList<>();
    179         int itemCount = data.getItemCount();
    180         for (int i = 0; i < itemCount; i++) {
    181             Intent intent = data.getItemAt(i).getIntent();
    182             if (intent == null) {
    183                 continue;
    184             }
    185 
    186             // Give preference to shortcut intents.
    187             if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) {
    188                 intents.add(intent);
    189                 continue;
    190             }
    191             ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, intent);
    192             if (info != null) {
    193                 mDragObject.dragInfo = info;
    194                 return true;
    195             }
    196             return true;
    197         }
    198 
    199         // Try creating shortcuts just using the intent and label
    200         Intent fullIntent = new Intent().putExtra(Intent.EXTRA_SHORTCUT_NAME, desc.getLabel());
    201         for (Intent intent : intents) {
    202             fullIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
    203             ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, fullIntent);
    204             if (info != null) {
    205                 mDragObject.dragInfo = info;
    206                 return true;
    207             }
    208         }
    209 
    210         return false;
    211     }
    212 }
    213 
    214 /**
    215  * Class for driving an internal (i.e. not using framework) drag/drop operation.
    216  */
    217 class InternalDragDriver extends DragDriver {
    218     public InternalDragDriver(DragController dragController) {
    219         super(dragController);
    220     }
    221 
    222     @Override
    223     public boolean onDragEvent (DragEvent event) { return false; }
    224 };
    225