Loading src/com/android/launcher3/ButtonDropTarget.java +2 −1 Original line number Diff line number Diff line Loading @@ -259,7 +259,8 @@ public abstract class ButtonDropTarget extends TextView } }; dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f, DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2), mLauncher.getDragController().isExternalDrag() ? 1 : DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2), new LinearInterpolator(), onAnimationEndRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null); } Loading src/com/android/launcher3/ShortcutInfo.java +1 −1 Original line number Diff line number Diff line Loading @@ -158,7 +158,7 @@ public class ShortcutInfo extends ItemInfo { */ Intent promisedIntent; ShortcutInfo() { public ShortcutInfo() { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; } Loading src/com/android/launcher3/dragndrop/AnotherWindowDragSource.java 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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.launcher3.dragndrop; import android.content.Context; import android.view.View; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; /** * DragSource used when the drag started at another window. */ public class AnotherWindowDragSource implements DragSource { private final Context mContext; AnotherWindowDragSource(Context context) { mContext = context; } @Override public boolean supportsFlingToDelete() { return false; } @Override public boolean supportsAppInfoDropTarget() { return false; } @Override public boolean supportsDeleteDropTarget() { return false; } @Override public float getIntrinsicIconScaleFactor() { return 1; } @Override public void onFlingToDeleteCompleted() { } @Override public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success) { if (!success) { Launcher.getLauncher(mContext).exitSpringLoadedDragModeDelayed(false, 0, null); } } @Override public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) { // TODO: Probably log something } } src/com/android/launcher3/dragndrop/DragController.java +11 −3 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.view.DragEvent; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; Loading Loading @@ -213,6 +212,12 @@ public class DragController implements DragDriver.EventListener, TouchController } mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0); mOptions = options; if (mOptions.systemDndStartPoint != null) { mMotionDownX = mOptions.systemDndStartPoint.x; mMotionDownY = mOptions.systemDndStartPoint.y; } final int registrationX = mMotionDownX - dragLayerX; final int registrationY = mMotionDownY - dragLayerY; Loading @@ -221,7 +226,6 @@ public class DragController implements DragDriver.EventListener, TouchController mLastDropTarget = null; mOptions = options; mDragObject = new DropTarget.DragObject(); final Resources res = mLauncher.getResources(); Loading @@ -241,7 +245,7 @@ public class DragController implements DragDriver.EventListener, TouchController mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop); mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); mDragDriver = DragDriver.create(this, dragInfo, dragView); mDragDriver = DragDriver.create(mLauncher, this, mDragObject, mOptions); } mDragObject.dragSource = source; Loading Loading @@ -293,6 +297,10 @@ public class DragController implements DragDriver.EventListener, TouchController return mDragDriver != null || (mOptions != null && mOptions.isAccessibleDrag); } public boolean isExternalDrag() { return (mOptions != null && mOptions.systemDndStartPoint != null); } /** * Stop dragging without dropping. */ Loading src/com/android/launcher3/dragndrop/DragDriver.java +69 −96 Original line number Diff line number Diff line Loading @@ -17,18 +17,19 @@ package com.android.launcher3.dragndrop; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Point; import android.view.DragEvent; import android.view.MotionEvent; import android.view.View; import com.android.launcher3.AnotherWindowDropTarget; import com.android.launcher3.DropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import java.util.ArrayList; /** * Base class for driving a drag/drop operation. Loading @@ -50,7 +51,7 @@ public abstract class DragDriver { /** * Handles ending of the DragView animation. */ public abstract void onDragViewAnimationEnd(); public void onDragViewAnimationEnd() { } public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); Loading Loading @@ -89,100 +90,46 @@ public abstract class DragDriver { return true; } public static DragDriver create( DragController dragController, ItemInfo dragInfo, DragView dragView) { if (FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER && Utilities.isNycOrAbove()) { return new SystemDragDriver(dragController, dragInfo.getIntent(), dragView); public static DragDriver create(Context context, DragController dragController, DragObject dragObject, DragOptions options) { if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) { return new SystemDragDriver(dragController, context, dragObject); } else { return new InternalDragDriver(dragController); } } }; } /** * Class for driving a system (i.e. framework) drag/drop operation. */ class SystemDragDriver extends DragDriver { /** Intent associated with the drag operation, or null is there no associated intent. */ private final Intent mDragIntent; private final DragView mDragView; boolean mIsFrameworkDragActive = false; private final DragObject mDragObject; private final Context mContext; boolean mReceivedDropEvent = false; float mLastX = 0; float mLastY = 0; public SystemDragDriver(DragController dragController, Intent dragIntent, DragView dragView) { public SystemDragDriver(DragController dragController, Context context, DragObject dragObject) { super(dragController); mDragIntent = dragIntent; mDragView = dragView; } private static class ShadowBuilder extends View.DragShadowBuilder { final DragView mDragView; public ShadowBuilder(DragView dragView) { mDragView = dragView; } @Override public void onProvideShadowMetrics (Point size, Point touch) { mDragView.provideDragShadowMetrics(size, touch); } @Override public void onDrawShadow(Canvas canvas) { mDragView.drawDragShadow(canvas); } }; @Override public void onDragViewAnimationEnd() { // Clip data for the drag operation. If there is an intent, create an intent-based ClipData, // which will be passed to a global DND. // If there is no intent, craft a fake ClipData and start a local DND operation; this // ClipData will be ignored. final ClipData dragData = mDragIntent != null ? ClipData.newIntent("", mDragIntent) : ClipData.newPlainText("", ""); View.DragShadowBuilder shadowBuilder = new ShadowBuilder(mDragView); // TODO: DND flags are in flux, once settled, use the appropriate constant. final int flagGlobal = 1 << 0; final int flagOpaque = 1 << 9; final int flags = (mDragIntent != null ? flagGlobal : 0) | flagOpaque; mIsFrameworkDragActive = true; if (!mDragView.startDrag(dragData, shadowBuilder, null, flags)) { mIsFrameworkDragActive = false; mEventListener.onDriverDragCancel(); return; } // Starting from this point, the driver takes over showing the drag shadow, so hiding the // drag view. mDragView.setVisibility(View.INVISIBLE); mDragObject = dragObject; mContext = context; } @Override public boolean onTouchEvent(MotionEvent ev) { return !mIsFrameworkDragActive && super.onTouchEvent(ev); return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return !mIsFrameworkDragActive && super.onInterceptTouchEvent(ev); return false; } @Override public boolean onDragEvent (DragEvent event) { if (!mIsFrameworkDragActive) { // We are interested only in drag events started by this driver. return false; } final int action = event.getAction(); switch (action) { Loading @@ -192,8 +139,6 @@ class SystemDragDriver extends DragDriver { return true; case DragEvent.ACTION_DRAG_ENTERED: mLastX = event.getX(); mLastY = event.getY(); return true; case DragEvent.ACTION_DRAG_LOCATION: Loading @@ -205,35 +150,66 @@ class SystemDragDriver extends DragDriver { case DragEvent.ACTION_DROP: mLastX = event.getX(); mLastY = event.getY(); mReceivedDropEvent = true; return true; mReceivedDropEvent = updateInfoFromClipData(event.getClipData(), event.getClipDescription()); return mReceivedDropEvent; case DragEvent.ACTION_DRAG_EXITED: mLastX = event.getX(); mLastY = event.getY(); mEventListener.onDriverDragExitWindow(); return true; case DragEvent.ACTION_DRAG_ENDED: final boolean dragAccepted = event.getResult(); final boolean acceptedByAnotherWindow = dragAccepted && !mReceivedDropEvent; if (mReceivedDropEvent) { mEventListener.onDriverDragEnd(mLastX, mLastY, null); } else { mEventListener.onDriverDragCancel(); } return true; // When the system drag ends, its drag shadow disappears. Resume showing the drag // view for the possible final animation. mDragView.setVisibility(View.VISIBLE); default: return false; } } private boolean updateInfoFromClipData(ClipData data, ClipDescription desc) { if (data == null) { return false; } ArrayList<Intent> intents = new ArrayList<>(); int itemCount = data.getItemCount(); for (int i = 0; i < itemCount; i++) { Intent intent = data.getItemAt(i).getIntent(); if (intent == null) { continue; } final DropTarget dropTargetOverride = acceptedByAnotherWindow ? new AnotherWindowDropTarget(mDragView.getContext()) : null; // Give preference to shortcut intents. if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) { intents.add(intent); continue; } ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, intent); if (info != null) { mDragObject.dragInfo = info; return true; } return true; } mEventListener.onDriverDragEnd(mLastX, mLastY, dropTargetOverride); mIsFrameworkDragActive = false; // Try creating shortcuts just using the intent and label Intent fullIntent = new Intent().putExtra(Intent.EXTRA_SHORTCUT_NAME, desc.getLabel()); for (Intent intent : intents) { fullIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, fullIntent); if (info != null) { mDragObject.dragInfo = info; return true; } } default: return false; } } }; /** * Class for driving an internal (i.e. not using framework) drag/drop operation. Loading @@ -243,9 +219,6 @@ class InternalDragDriver extends DragDriver { super(dragController); } @Override public void onDragViewAnimationEnd() {} @Override public boolean onDragEvent (DragEvent event) { return false; } }; Loading
src/com/android/launcher3/ButtonDropTarget.java +2 −1 Original line number Diff line number Diff line Loading @@ -259,7 +259,8 @@ public abstract class ButtonDropTarget extends TextView } }; dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f, DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2), mLauncher.getDragController().isExternalDrag() ? 1 : DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2), new LinearInterpolator(), onAnimationEndRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null); } Loading
src/com/android/launcher3/ShortcutInfo.java +1 −1 Original line number Diff line number Diff line Loading @@ -158,7 +158,7 @@ public class ShortcutInfo extends ItemInfo { */ Intent promisedIntent; ShortcutInfo() { public ShortcutInfo() { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; } Loading
src/com/android/launcher3/dragndrop/AnotherWindowDragSource.java 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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.launcher3.dragndrop; import android.content.Context; import android.view.View; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; /** * DragSource used when the drag started at another window. */ public class AnotherWindowDragSource implements DragSource { private final Context mContext; AnotherWindowDragSource(Context context) { mContext = context; } @Override public boolean supportsFlingToDelete() { return false; } @Override public boolean supportsAppInfoDropTarget() { return false; } @Override public boolean supportsDeleteDropTarget() { return false; } @Override public float getIntrinsicIconScaleFactor() { return 1; } @Override public void onFlingToDeleteCompleted() { } @Override public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success) { if (!success) { Launcher.getLauncher(mContext).exitSpringLoadedDragModeDelayed(false, 0, null); } } @Override public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) { // TODO: Probably log something } }
src/com/android/launcher3/dragndrop/DragController.java +11 −3 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.view.DragEvent; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; Loading Loading @@ -213,6 +212,12 @@ public class DragController implements DragDriver.EventListener, TouchController } mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0); mOptions = options; if (mOptions.systemDndStartPoint != null) { mMotionDownX = mOptions.systemDndStartPoint.x; mMotionDownY = mOptions.systemDndStartPoint.y; } final int registrationX = mMotionDownX - dragLayerX; final int registrationY = mMotionDownY - dragLayerY; Loading @@ -221,7 +226,6 @@ public class DragController implements DragDriver.EventListener, TouchController mLastDropTarget = null; mOptions = options; mDragObject = new DropTarget.DragObject(); final Resources res = mLauncher.getResources(); Loading @@ -241,7 +245,7 @@ public class DragController implements DragDriver.EventListener, TouchController mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop); mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); mDragDriver = DragDriver.create(this, dragInfo, dragView); mDragDriver = DragDriver.create(mLauncher, this, mDragObject, mOptions); } mDragObject.dragSource = source; Loading Loading @@ -293,6 +297,10 @@ public class DragController implements DragDriver.EventListener, TouchController return mDragDriver != null || (mOptions != null && mOptions.isAccessibleDrag); } public boolean isExternalDrag() { return (mOptions != null && mOptions.systemDndStartPoint != null); } /** * Stop dragging without dropping. */ Loading
src/com/android/launcher3/dragndrop/DragDriver.java +69 −96 Original line number Diff line number Diff line Loading @@ -17,18 +17,19 @@ package com.android.launcher3.dragndrop; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Point; import android.view.DragEvent; import android.view.MotionEvent; import android.view.View; import com.android.launcher3.AnotherWindowDropTarget; import com.android.launcher3.DropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import java.util.ArrayList; /** * Base class for driving a drag/drop operation. Loading @@ -50,7 +51,7 @@ public abstract class DragDriver { /** * Handles ending of the DragView animation. */ public abstract void onDragViewAnimationEnd(); public void onDragViewAnimationEnd() { } public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); Loading Loading @@ -89,100 +90,46 @@ public abstract class DragDriver { return true; } public static DragDriver create( DragController dragController, ItemInfo dragInfo, DragView dragView) { if (FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER && Utilities.isNycOrAbove()) { return new SystemDragDriver(dragController, dragInfo.getIntent(), dragView); public static DragDriver create(Context context, DragController dragController, DragObject dragObject, DragOptions options) { if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) { return new SystemDragDriver(dragController, context, dragObject); } else { return new InternalDragDriver(dragController); } } }; } /** * Class for driving a system (i.e. framework) drag/drop operation. */ class SystemDragDriver extends DragDriver { /** Intent associated with the drag operation, or null is there no associated intent. */ private final Intent mDragIntent; private final DragView mDragView; boolean mIsFrameworkDragActive = false; private final DragObject mDragObject; private final Context mContext; boolean mReceivedDropEvent = false; float mLastX = 0; float mLastY = 0; public SystemDragDriver(DragController dragController, Intent dragIntent, DragView dragView) { public SystemDragDriver(DragController dragController, Context context, DragObject dragObject) { super(dragController); mDragIntent = dragIntent; mDragView = dragView; } private static class ShadowBuilder extends View.DragShadowBuilder { final DragView mDragView; public ShadowBuilder(DragView dragView) { mDragView = dragView; } @Override public void onProvideShadowMetrics (Point size, Point touch) { mDragView.provideDragShadowMetrics(size, touch); } @Override public void onDrawShadow(Canvas canvas) { mDragView.drawDragShadow(canvas); } }; @Override public void onDragViewAnimationEnd() { // Clip data for the drag operation. If there is an intent, create an intent-based ClipData, // which will be passed to a global DND. // If there is no intent, craft a fake ClipData and start a local DND operation; this // ClipData will be ignored. final ClipData dragData = mDragIntent != null ? ClipData.newIntent("", mDragIntent) : ClipData.newPlainText("", ""); View.DragShadowBuilder shadowBuilder = new ShadowBuilder(mDragView); // TODO: DND flags are in flux, once settled, use the appropriate constant. final int flagGlobal = 1 << 0; final int flagOpaque = 1 << 9; final int flags = (mDragIntent != null ? flagGlobal : 0) | flagOpaque; mIsFrameworkDragActive = true; if (!mDragView.startDrag(dragData, shadowBuilder, null, flags)) { mIsFrameworkDragActive = false; mEventListener.onDriverDragCancel(); return; } // Starting from this point, the driver takes over showing the drag shadow, so hiding the // drag view. mDragView.setVisibility(View.INVISIBLE); mDragObject = dragObject; mContext = context; } @Override public boolean onTouchEvent(MotionEvent ev) { return !mIsFrameworkDragActive && super.onTouchEvent(ev); return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return !mIsFrameworkDragActive && super.onInterceptTouchEvent(ev); return false; } @Override public boolean onDragEvent (DragEvent event) { if (!mIsFrameworkDragActive) { // We are interested only in drag events started by this driver. return false; } final int action = event.getAction(); switch (action) { Loading @@ -192,8 +139,6 @@ class SystemDragDriver extends DragDriver { return true; case DragEvent.ACTION_DRAG_ENTERED: mLastX = event.getX(); mLastY = event.getY(); return true; case DragEvent.ACTION_DRAG_LOCATION: Loading @@ -205,35 +150,66 @@ class SystemDragDriver extends DragDriver { case DragEvent.ACTION_DROP: mLastX = event.getX(); mLastY = event.getY(); mReceivedDropEvent = true; return true; mReceivedDropEvent = updateInfoFromClipData(event.getClipData(), event.getClipDescription()); return mReceivedDropEvent; case DragEvent.ACTION_DRAG_EXITED: mLastX = event.getX(); mLastY = event.getY(); mEventListener.onDriverDragExitWindow(); return true; case DragEvent.ACTION_DRAG_ENDED: final boolean dragAccepted = event.getResult(); final boolean acceptedByAnotherWindow = dragAccepted && !mReceivedDropEvent; if (mReceivedDropEvent) { mEventListener.onDriverDragEnd(mLastX, mLastY, null); } else { mEventListener.onDriverDragCancel(); } return true; // When the system drag ends, its drag shadow disappears. Resume showing the drag // view for the possible final animation. mDragView.setVisibility(View.VISIBLE); default: return false; } } private boolean updateInfoFromClipData(ClipData data, ClipDescription desc) { if (data == null) { return false; } ArrayList<Intent> intents = new ArrayList<>(); int itemCount = data.getItemCount(); for (int i = 0; i < itemCount; i++) { Intent intent = data.getItemAt(i).getIntent(); if (intent == null) { continue; } final DropTarget dropTargetOverride = acceptedByAnotherWindow ? new AnotherWindowDropTarget(mDragView.getContext()) : null; // Give preference to shortcut intents. if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) { intents.add(intent); continue; } ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, intent); if (info != null) { mDragObject.dragInfo = info; return true; } return true; } mEventListener.onDriverDragEnd(mLastX, mLastY, dropTargetOverride); mIsFrameworkDragActive = false; // Try creating shortcuts just using the intent and label Intent fullIntent = new Intent().putExtra(Intent.EXTRA_SHORTCUT_NAME, desc.getLabel()); for (Intent intent : intents) { fullIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, fullIntent); if (info != null) { mDragObject.dragInfo = info; return true; } } default: return false; } } }; /** * Class for driving an internal (i.e. not using framework) drag/drop operation. Loading @@ -243,9 +219,6 @@ class InternalDragDriver extends DragDriver { super(dragController); } @Override public void onDragViewAnimationEnd() {} @Override public boolean onDragEvent (DragEvent event) { return false; } };