• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.biometrics.udfps
18 
19 import android.graphics.Point
20 import android.graphics.Rect
21 import androidx.annotation.VisibleForTesting
22 import com.android.systemui.dagger.SysUISingleton
23 import kotlin.math.cos
24 import kotlin.math.pow
25 import kotlin.math.sin
26 
27 /**
28  * Approximates the touch as an ellipse and determines whether the ellipse has a sufficient overlap
29  * with the sensor.
30  */
31 @SysUISingleton
32 class EllipseOverlapDetector(private val neededPoints: Int = 2) : OverlapDetector {
33 
isGoodOverlapnull34     override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
35         val points = calculateSensorPoints(nativeSensorBounds)
36         return points.count { checkPoint(it, touchData) } >= neededPoints
37     }
38 
checkPointnull39     private fun checkPoint(point: Point, touchData: NormalizedTouchData): Boolean {
40         // Calculate if sensor point is within ellipse
41         // Formula: ((cos(o)(xE - xS) + sin(o)(yE - yS))^2 / a^2) + ((sin(o)(xE - xS) + cos(o)(yE -
42         // yS))^2 / b^2) <= 1
43         val a: Float = cos(touchData.orientation) * (point.x - touchData.x)
44         val b: Float = sin(touchData.orientation) * (point.y - touchData.y)
45         val c: Float = sin(touchData.orientation) * (point.x - touchData.x)
46         val d: Float = cos(touchData.orientation) * (point.y - touchData.y)
47         val result =
48             (a + b).pow(2) / (touchData.minor / 2).pow(2) +
49                 (c - d).pow(2) / (touchData.major / 2).pow(2)
50 
51         return result <= 1
52     }
53 
54     @VisibleForTesting
calculateSensorPointsnull55     fun calculateSensorPoints(sensorBounds: Rect): List<Point> {
56         val sensorX = sensorBounds.centerX()
57         val sensorY = sensorBounds.centerY()
58         val cornerOffset: Int = sensorBounds.width() / 4
59         val sideOffset: Int = sensorBounds.width() / 3
60 
61         return listOf(
62             Point(sensorX - cornerOffset, sensorY - cornerOffset),
63             Point(sensorX, sensorY - sideOffset),
64             Point(sensorX + cornerOffset, sensorY - cornerOffset),
65             Point(sensorX - sideOffset, sensorY),
66             Point(sensorX, sensorY),
67             Point(sensorX + sideOffset, sensorY),
68             Point(sensorX - cornerOffset, sensorY + cornerOffset),
69             Point(sensorX, sensorY + sideOffset),
70             Point(sensorX + cornerOffset, sensorY + cornerOffset)
71         )
72     }
73 }
74