1 /* 2 * Copyright (C) 2020 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.classifier; 18 19 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE; 20 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE; 21 import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE; 22 import static com.android.systemui.classifier.Classifier.LOCK_ICON; 23 import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE; 24 25 import android.provider.DeviceConfig; 26 27 import com.android.systemui.util.DeviceConfigProxy; 28 29 import java.util.Locale; 30 31 import javax.inject.Inject; 32 33 /** 34 * False on swipes that are too close to 45 degrees. 35 * 36 * Horizontal swipes may have a different threshold than vertical. 37 * 38 * This falser should not run on "affordance" swipes, as they will always be close to 45. 39 */ 40 class DiagonalClassifier extends FalsingClassifier { 41 42 private static final float HORIZONTAL_ANGLE_RANGE = (float) (5f / 360f * Math.PI * 2f); 43 private static final float VERTICAL_ANGLE_RANGE = (float) (5f / 360f * Math.PI * 2f); 44 private static final float DIAGONAL = (float) (Math.PI / 4); // 45 deg 45 private static final float NINETY_DEG = (float) (Math.PI / 2); 46 private static final float ONE_HUNDRED_EIGHTY_DEG = (float) (Math.PI); 47 private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI); 48 49 private final float mHorizontalAngleRange; 50 private final float mVerticalAngleRange; 51 52 @Inject DiagonalClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy)53 DiagonalClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) { 54 super(dataProvider); 55 56 mHorizontalAngleRange = deviceConfigProxy.getFloat( 57 DeviceConfig.NAMESPACE_SYSTEMUI, 58 BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE, 59 HORIZONTAL_ANGLE_RANGE); 60 mVerticalAngleRange = deviceConfigProxy.getFloat( 61 DeviceConfig.NAMESPACE_SYSTEMUI, 62 BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE, 63 VERTICAL_ANGLE_RANGE); 64 } 65 calculateFalsingResult( @lassifier.InteractionType int interactionType, double historyBelief, double historyConfidence)66 Result calculateFalsingResult( 67 @Classifier.InteractionType int interactionType, 68 double historyBelief, double historyConfidence) { 69 float angle = getAngle(); 70 71 if (angle == Float.MAX_VALUE) { // Unknown angle 72 return Result.passed(0); 73 } 74 75 if (interactionType == LEFT_AFFORDANCE 76 || interactionType == RIGHT_AFFORDANCE 77 || interactionType == LOCK_ICON) { 78 return Result.passed(0); 79 } 80 81 float minAngle = DIAGONAL - mHorizontalAngleRange; 82 float maxAngle = DIAGONAL + mHorizontalAngleRange; 83 if (isVertical()) { 84 minAngle = DIAGONAL - mVerticalAngleRange; 85 maxAngle = DIAGONAL + mVerticalAngleRange; 86 } 87 88 boolean falsed = angleBetween(angle, minAngle, maxAngle) 89 || angleBetween(angle, minAngle + NINETY_DEG, maxAngle + NINETY_DEG) 90 || angleBetween(angle, minAngle - NINETY_DEG, maxAngle - NINETY_DEG) 91 || angleBetween(angle, minAngle + ONE_HUNDRED_EIGHTY_DEG, 92 maxAngle + ONE_HUNDRED_EIGHTY_DEG); 93 return falsed ? falsed(0.5f, getReason()) : Result.passed(0.5); 94 } 95 getReason()96 private String getReason() { 97 return String.format( 98 (Locale) null, 99 "{angle=%f, vertical=%s}", 100 getAngle(), 101 isVertical()); 102 } 103 angleBetween(float angle, float min, float max)104 private boolean angleBetween(float angle, float min, float max) { 105 // No need to normalize angle as it is guaranteed to be between 0 and 2*PI. 106 min = normalizeAngle(min); 107 max = normalizeAngle(max); 108 109 if (min > max) { // Can happen when angle is close to 0. 110 return angle >= min || angle <= max; 111 } 112 113 return angle >= min && angle <= max; 114 } 115 normalizeAngle(float angle)116 private float normalizeAngle(float angle) { 117 if (angle < 0) { 118 return THREE_HUNDRED_SIXTY_DEG + (angle % THREE_HUNDRED_SIXTY_DEG); 119 } else if (angle > THREE_HUNDRED_SIXTY_DEG) { 120 return angle % THREE_HUNDRED_SIXTY_DEG; 121 } 122 return angle; 123 } 124 } 125