1 package com.android.launcher3
2 
3 import android.content.ComponentName
4 import android.view.View
5 import com.android.launcher3.BaseDraggingActivity.EVENT_RESUMED
6 import com.android.launcher3.DropTarget.DragObject
7 import com.android.launcher3.LauncherConstants.ActivityCodes
8 import com.android.launcher3.SecondaryDropTarget.DeferredOnComplete
9 import com.android.launcher3.dragndrop.DragLayer
10 import com.android.launcher3.logging.StatsLogManager.LauncherEvent
11 import com.android.launcher3.model.data.ItemInfo
12 import com.android.launcher3.model.data.LauncherAppWidgetInfo
13 import com.android.launcher3.util.IntSet
14 import com.android.launcher3.util.PendingRequestArgs
15 import com.android.launcher3.views.Snackbar
16 
17 /**
18  * Handler class for drop target actions that require modifying or interacting with launcher.
19  *
20  * This class is created by Launcher and provided the instance of launcher when created, which
21  * allows us to decouple drop target controllers from Launcher to enable easier testing.
22  */
23 class DropTargetHandler(launcher: Launcher) {
24     val mLauncher: Launcher = launcher
25 
onDropAnimationCompletenull26     fun onDropAnimationComplete() {
27         mLauncher.stateManager.goToState(LauncherState.NORMAL)
28     }
29 
onSecondaryTargetCompleteDropnull30     fun onSecondaryTargetCompleteDrop(target: ComponentName?, d: DragObject) {
31         when (val dragSource = d.dragSource) {
32             is DeferredOnComplete -> {
33                 val deferred: DeferredOnComplete = dragSource
34                 if (d.dragSource is SecondaryDropTarget.DeferredOnComplete) {
35                     target?.let {
36                         deferred.mPackageName = it.packageName
37                         mLauncher.addEventCallback(EVENT_RESUMED) { deferred.onLauncherResume() }
38                     } ?: deferred.sendFailure()
39                 }
40             }
41         }
42     }
43 
reconfigureWidgetnull44     fun reconfigureWidget(widgetId: Int, info: ItemInfo) {
45         mLauncher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(widgetId, null, info))
46         mLauncher.appWidgetHolder.startConfigActivity(
47             mLauncher,
48             widgetId,
49             ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET,
50         )
51     }
52 
getViewUnderDragnull53     fun getViewUnderDrag(info: ItemInfo): View? {
54         return if (
55             info is LauncherAppWidgetInfo &&
56                 info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
57                 mLauncher.workspace.dragInfo != null
58         ) {
59             mLauncher.workspace.dragInfo.cell
60         } else null
61     }
62 
prepareToUndoDeletenull63     fun prepareToUndoDelete() {
64         mLauncher.modelWriter.prepareToUndoDelete()
65     }
66 
onDeleteCompletenull67     fun onDeleteComplete(item: ItemInfo) {
68         removeItemAndStripEmptyScreens(null /* view */, item)
69         var pageItem: ItemInfo = item
70         if (item.container <= 0) {
71             val v = mLauncher.workspace.getHomescreenIconByItemId(item.container)
72             v?.let { pageItem = v.tag as ItemInfo }
73         }
74         val pageIds =
75             if (pageItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP)
76                 IntSet.wrap(pageItem.screenId)
77             else mLauncher.workspace.currentPageScreenIds
78         val onUndoClicked = Runnable {
79             mLauncher.setPagesToBindSynchronously(pageIds)
80             mLauncher.modelWriter.abortDelete()
81             mLauncher.statsLogManager.logger().log(LauncherEvent.LAUNCHER_UNDO)
82         }
83 
84         Snackbar.show(
85             mLauncher,
86             R.string.item_removed,
87             R.string.undo,
88             mLauncher.modelWriter::commitDelete,
89             onUndoClicked,
90         )
91     }
92 
onAccessibilityDeletenull93     fun onAccessibilityDelete(view: View?, item: ItemInfo, announcement: CharSequence) {
94         removeItemAndStripEmptyScreens(view, item)
95         mLauncher.dragLayer.announceForAccessibility(announcement)
96     }
97 
getDragLayernull98     fun getDragLayer(): DragLayer {
99         return mLauncher.dragLayer
100     }
101 
onClicknull102     fun onClick(buttonDropTarget: ButtonDropTarget) {
103         mLauncher.accessibilityDelegate.handleAccessibleDrop(buttonDropTarget, null, null)
104     }
105 
removeItemAndStripEmptyScreensnull106     private fun removeItemAndStripEmptyScreens(view: View?, item: ItemInfo) {
107         // Remove the item from launcher and the db, we can ignore the containerInfo in this call
108         // because we already remove the drag view from the folder (if the drag originated from
109         // a folder) in Folder.beginDrag()
110         mLauncher.removeItem(view, item, true /* deleteFromDb */, "removed by accessibility drop")
111         mLauncher.workspace.stripEmptyScreens()
112     }
113 }
114