• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.statusbar.gesture
18 
19 import android.content.Context
20 import android.view.InputEvent
21 import android.view.MotionEvent
22 import android.view.MotionEvent.ACTION_CANCEL
23 import android.view.MotionEvent.ACTION_DOWN
24 import android.view.MotionEvent.ACTION_MOVE
25 import android.view.MotionEvent.ACTION_UP
26 import com.android.systemui.dagger.SysUISingleton
27 import com.android.systemui.settings.DisplayTracker
28 
29 /**
30  * A class to detect a generic "swipe up" gesture. To be notified when the swipe up gesture is
31  * detected, add a callback via [addOnGestureDetectedCallback].
32  */
33 @SysUISingleton
34 abstract class SwipeUpGestureHandler(
35     context: Context,
36     displayTracker: DisplayTracker,
37     private val logger: SwipeUpGestureLogger,
38     private val loggerTag: String
39 ) : GenericGestureDetector(SwipeUpGestureHandler::class.simpleName!!, displayTracker) {
40 
41     private var startY: Float = 0f
42     private var startTime: Long = 0L
43     private var monitoringCurrentTouch: Boolean = false
44 
45     private var swipeDistanceThreshold: Int = context.resources.getDimensionPixelSize(
46         com.android.internal.R.dimen.system_gestures_start_threshold
47     )
48 
onInputEventnull49     override fun onInputEvent(ev: InputEvent) {
50         if (ev !is MotionEvent) {
51             return
52         }
53 
54         when (ev.actionMasked) {
55             ACTION_DOWN -> {
56                 if (
57                     startOfGestureIsWithinBounds(ev)
58                 ) {
59                     logger.logGestureDetectionStarted(loggerTag, ev.y.toInt())
60                     startY = ev.y
61                     startTime = ev.eventTime
62                     monitoringCurrentTouch = true
63                 } else {
64                     monitoringCurrentTouch = false
65                 }
66             }
67             ACTION_MOVE -> {
68                 if (!monitoringCurrentTouch) {
69                     return
70                 }
71                 if (
72                     // Gesture is up
73                     ev.y < startY &&
74                     // Gesture went far enough
75                     (startY - ev.y) >= swipeDistanceThreshold &&
76                     // Gesture completed quickly enough
77                     (ev.eventTime - startTime) < SWIPE_TIMEOUT_MS
78                 ) {
79                     monitoringCurrentTouch = false
80                     logger.logGestureDetected(loggerTag, ev.y.toInt())
81                     onGestureDetected(ev)
82                 }
83             }
84             ACTION_CANCEL, ACTION_UP -> {
85                 if (monitoringCurrentTouch) {
86                     logger.logGestureDetectionEndedWithoutTriggering(loggerTag, ev.y.toInt())
87                 }
88                 monitoringCurrentTouch = false
89             }
90         }
91     }
92 
93     /**
94      * Returns true if the [ACTION_DOWN] event falls within bounds for this specific swipe-up
95      * gesture.
96      *
97      * Implementations must override this method to specify what part(s) of the screen are valid
98      * locations for the swipe up gesture to start at.
99      */
startOfGestureIsWithinBoundsnull100     abstract fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean
101 
102     override fun startGestureListening() {
103         super.startGestureListening()
104         logger.logInputListeningStarted(loggerTag)
105     }
106 
stopGestureListeningnull107     override fun stopGestureListening() {
108         super.stopGestureListening()
109         logger.logInputListeningStopped(loggerTag)
110     }
111 }
112 
113 private const val SWIPE_TIMEOUT_MS: Long = 500
114