1 /*
2  * Copyright (C) 2024 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.systemui.screenshot.ui
18 
19 import android.view.MotionEvent
20 import android.view.VelocityTracker
21 import android.view.View
22 import com.android.systemui.screenshot.FloatingWindowUtil
23 import kotlin.math.abs
24 
25 class SwipeGestureListener(
26     private val view: View,
27     private val onDismiss: (Float?) -> Unit,
28     private val onCancel: () -> Unit
29 ) {
30     private val velocityTracker = VelocityTracker.obtain()
31     private val displayMetrics = view.resources.displayMetrics
32 
33     private var startX = 0f
34 
onMotionEventnull35     fun onMotionEvent(ev: MotionEvent): Boolean {
36         ev.offsetLocation(view.translationX, 0f)
37         when (ev.actionMasked) {
38             MotionEvent.ACTION_DOWN -> {
39                 velocityTracker.addMovement(ev)
40                 startX = ev.rawX
41             }
42             MotionEvent.ACTION_UP -> {
43                 velocityTracker.computeCurrentVelocity(1)
44                 val xVelocity = velocityTracker.xVelocity
45                 if (
46                     abs(xVelocity) > FloatingWindowUtil.dpToPx(displayMetrics, FLING_THRESHOLD_DP)
47                 ) {
48                     onDismiss.invoke(xVelocity)
49                     return true
50                 } else if (
51                     abs(view.translationX) >
52                         FloatingWindowUtil.dpToPx(displayMetrics, DISMISS_THRESHOLD_DP)
53                 ) {
54                     onDismiss.invoke(xVelocity)
55                     return true
56                 } else {
57                     velocityTracker.clear()
58                     onCancel.invoke()
59                 }
60             }
61             MotionEvent.ACTION_MOVE -> {
62                 velocityTracker.addMovement(ev)
63                 view.translationX = ev.rawX - startX
64             }
65         }
66         return false
67     }
68 
69     companion object {
70         private const val DISMISS_THRESHOLD_DP = 80f
71         private const val FLING_THRESHOLD_DP = .8f // dp per ms
72     }
73 }
74