Merge changes from topic "sfps-updates" into sc-v2-dev
* changes: Update side fsp sensor position via overlay. Update side fingerprint sensor overlay assets.
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package android.hardware.biometrics;
|
||||||
|
|
||||||
|
// @hide
|
||||||
|
parcelable SensorLocationInternal;
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.hardware.biometrics;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of a sensor relative to a physical display.
|
||||||
|
*
|
||||||
|
* Note that the location may change depending on other attributes of the device, such as
|
||||||
|
* fold status, which are not yet included in this class.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class SensorLocationInternal implements Parcelable {
|
||||||
|
|
||||||
|
/** Default value to use when the sensor's location is unknown or undefined. */
|
||||||
|
public static final SensorLocationInternal DEFAULT = new SensorLocationInternal("", 0, 0, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stable display id.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public final String displayId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the center of the sensor if applicable. For example, sensors of type
|
||||||
|
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
|
||||||
|
* distance in pixels, measured from the left edge of the screen.
|
||||||
|
*/
|
||||||
|
public final int sensorLocationX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the center of the sensor if applicable. For example, sensors of type
|
||||||
|
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
|
||||||
|
* distance in pixels, measured from the top edge of the screen.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final int sensorLocationY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The radius of the sensor if applicable. For example, sensors of type
|
||||||
|
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius
|
||||||
|
* of the sensor, in pixels.
|
||||||
|
*/
|
||||||
|
public final int sensorRadius;
|
||||||
|
|
||||||
|
public SensorLocationInternal(@Nullable String displayId,
|
||||||
|
int sensorLocationX, int sensorLocationY, int sensorRadius) {
|
||||||
|
this.displayId = displayId != null ? displayId : "";
|
||||||
|
this.sensorLocationX = sensorLocationX;
|
||||||
|
this.sensorLocationY = sensorLocationY;
|
||||||
|
this.sensorRadius = sensorRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SensorLocationInternal(Parcel in) {
|
||||||
|
displayId = in.readString16NoHelper();
|
||||||
|
sensorLocationX = in.readInt();
|
||||||
|
sensorLocationY = in.readInt();
|
||||||
|
sensorRadius = in.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(displayId);
|
||||||
|
dest.writeInt(sensorLocationX);
|
||||||
|
dest.writeInt(sensorLocationY);
|
||||||
|
dest.writeInt(sensorRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<SensorLocationInternal> CREATOR =
|
||||||
|
new Creator<SensorLocationInternal>() {
|
||||||
|
@Override
|
||||||
|
public SensorLocationInternal createFromParcel(Parcel in) {
|
||||||
|
return new SensorLocationInternal(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SensorLocationInternal[] newArray(int size) {
|
||||||
|
return new SensorLocationInternal[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[id: " + displayId
|
||||||
|
+ ", x: " + sensorLocationX
|
||||||
|
+ ", y: " + sensorLocationY
|
||||||
|
+ ", r: " + sensorRadius + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,9 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP
|
|||||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
|
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.hardware.biometrics.ComponentInfoInternal;
|
import android.hardware.biometrics.ComponentInfoInternal;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.biometrics.SensorProperties;
|
import android.hardware.biometrics.SensorProperties;
|
||||||
import android.hardware.biometrics.SensorPropertiesInternal;
|
import android.hardware.biometrics.SensorPropertiesInternal;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -38,34 +40,14 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
|
|||||||
*/
|
*/
|
||||||
public final @FingerprintSensorProperties.SensorType int sensorType;
|
public final @FingerprintSensorProperties.SensorType int sensorType;
|
||||||
|
|
||||||
/**
|
private final List<SensorLocationInternal> mSensorLocations;
|
||||||
* The location of the center of the sensor if applicable. For example, sensors of type
|
|
||||||
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
|
|
||||||
* distance in pixels, measured from the left edge of the screen.
|
|
||||||
*/
|
|
||||||
public final int sensorLocationX;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The location of the center of the sensor if applicable. For example, sensors of type
|
|
||||||
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
|
|
||||||
* distance in pixels, measured from the top edge of the screen.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public final int sensorLocationY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The radius of the sensor if applicable. For example, sensors of type
|
|
||||||
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius
|
|
||||||
* of the sensor, in pixels.
|
|
||||||
*/
|
|
||||||
public final int sensorRadius;
|
|
||||||
|
|
||||||
public FingerprintSensorPropertiesInternal(int sensorId,
|
public FingerprintSensorPropertiesInternal(int sensorId,
|
||||||
@SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
|
@SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
|
||||||
@NonNull List<ComponentInfoInternal> componentInfo,
|
@NonNull List<ComponentInfoInternal> componentInfo,
|
||||||
@FingerprintSensorProperties.SensorType int sensorType,
|
@FingerprintSensorProperties.SensorType int sensorType,
|
||||||
boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
|
boolean resetLockoutRequiresHardwareAuthToken,
|
||||||
int sensorRadius) {
|
@NonNull List<SensorLocationInternal> sensorLocations) {
|
||||||
// IBiometricsFingerprint@2.1 handles lockout in the framework, so the challenge is not
|
// IBiometricsFingerprint@2.1 handles lockout in the framework, so the challenge is not
|
||||||
// required as it can only be generated/attested/verified by TEE components.
|
// required as it can only be generated/attested/verified by TEE components.
|
||||||
// IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See
|
// IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See
|
||||||
@@ -73,9 +55,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
|
|||||||
super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
|
super(sensorId, strength, maxEnrollmentsPerUser, componentInfo,
|
||||||
resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
|
resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */);
|
||||||
this.sensorType = sensorType;
|
this.sensorType = sensorType;
|
||||||
this.sensorLocationX = sensorLocationX;
|
this.mSensorLocations = List.copyOf(sensorLocations);
|
||||||
this.sensorLocationY = sensorLocationY;
|
|
||||||
this.sensorRadius = sensorRadius;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,16 +68,15 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
|
|||||||
boolean resetLockoutRequiresHardwareAuthToken) {
|
boolean resetLockoutRequiresHardwareAuthToken) {
|
||||||
// TODO(b/179175438): Value should be provided from the HAL
|
// TODO(b/179175438): Value should be provided from the HAL
|
||||||
this(sensorId, strength, maxEnrollmentsPerUser, componentInfo, sensorType,
|
this(sensorId, strength, maxEnrollmentsPerUser, componentInfo, sensorType,
|
||||||
resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
|
resetLockoutRequiresHardwareAuthToken, List.of(new SensorLocationInternal(
|
||||||
1636 /* sensorLocationY */, 130 /* sensorRadius */);
|
"" /* displayId */, 540 /* sensorLocationX */, 1636 /* sensorLocationY */,
|
||||||
|
130 /* sensorRadius */)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FingerprintSensorPropertiesInternal(Parcel in) {
|
protected FingerprintSensorPropertiesInternal(Parcel in) {
|
||||||
super(in);
|
super(in);
|
||||||
sensorType = in.readInt();
|
sensorType = in.readInt();
|
||||||
sensorLocationX = in.readInt();
|
mSensorLocations = in.createTypedArrayList(SensorLocationInternal.CREATOR);
|
||||||
sensorLocationY = in.readInt();
|
|
||||||
sensorRadius = in.readInt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<FingerprintSensorPropertiesInternal> CREATOR =
|
public static final Creator<FingerprintSensorPropertiesInternal> CREATOR =
|
||||||
@@ -122,9 +101,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
|
|||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
super.writeToParcel(dest, flags);
|
super.writeToParcel(dest, flags);
|
||||||
dest.writeInt(sensorType);
|
dest.writeInt(sensorType);
|
||||||
dest.writeInt(sensorLocationX);
|
dest.writeTypedList(mSensorLocations);
|
||||||
dest.writeInt(sensorLocationY);
|
|
||||||
dest.writeInt(sensorRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAnyUdfpsType() {
|
public boolean isAnyUdfpsType() {
|
||||||
@@ -150,6 +127,44 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default location.
|
||||||
|
*
|
||||||
|
* Use this method when the sensor's relationship to the displays on the device do not
|
||||||
|
* matter.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public SensorLocationInternal getLocation() {
|
||||||
|
final SensorLocationInternal location = getLocation("" /* displayId */);
|
||||||
|
return location != null ? location : SensorLocationInternal.DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the location of a sensor relative to a physical display layout.
|
||||||
|
*
|
||||||
|
* @param displayId stable display id
|
||||||
|
* @return location or null if none is specified
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public SensorLocationInternal getLocation(String displayId) {
|
||||||
|
for (SensorLocationInternal location : mSensorLocations) {
|
||||||
|
if (location.displayId.equals(displayId)) {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all locations relative to all supported display layouts.
|
||||||
|
* @return supported locations
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public List<SensorLocationInternal> getAllLocations() {
|
||||||
|
return mSensorLocations;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ID: " + sensorId + ", Strength: " + sensorStrength + ", Type: " + sensorType;
|
return "ID: " + sensorId + ", Strength: " + sensorStrength + ", Type: " + sensorType;
|
||||||
|
|||||||
@@ -4576,6 +4576,20 @@
|
|||||||
-->
|
-->
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
<!-- An array of arrays of side fingerprint sensor properties relative to each display.
|
||||||
|
Note: this value is temporary and is expected to be queried directly
|
||||||
|
from the HAL in the future. -->
|
||||||
|
<array name="config_sfps_sensor_props" translatable="false">
|
||||||
|
<!--
|
||||||
|
<array>
|
||||||
|
<item>displayId</item>
|
||||||
|
<item>sensorLocationX</item>
|
||||||
|
<item>sensorLocationY</item>
|
||||||
|
<item>sensorRadius</item>
|
||||||
|
<array>
|
||||||
|
-->
|
||||||
|
</array>
|
||||||
|
|
||||||
<!-- How long it takes for the HW to start illuminating after the illumination is requested. -->
|
<!-- How long it takes for the HW to start illuminating after the illumination is requested. -->
|
||||||
<integer name="config_udfps_illumination_transition_ms">50</integer>
|
<integer name="config_udfps_illumination_transition_ms">50</integer>
|
||||||
|
|
||||||
|
|||||||
@@ -2609,6 +2609,7 @@
|
|||||||
<java-symbol type="array" name="config_biometric_sensors" />
|
<java-symbol type="array" name="config_biometric_sensors" />
|
||||||
<java-symbol type="bool" name="allow_test_udfps" />
|
<java-symbol type="bool" name="allow_test_udfps" />
|
||||||
<java-symbol type="array" name="config_udfps_sensor_props" />
|
<java-symbol type="array" name="config_udfps_sensor_props" />
|
||||||
|
<java-symbol type="array" name="config_sfps_sensor_props" />
|
||||||
<java-symbol type="integer" name="config_udfps_illumination_transition_ms" />
|
<java-symbol type="integer" name="config_udfps_illumination_transition_ms" />
|
||||||
<java-symbol type="bool" name="config_is_powerbutton_fps" />
|
<java-symbol type="bool" name="config_is_powerbutton_fps" />
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,13 @@
|
|||||||
~ See the License for the specific language governing permissions and
|
~ See the License for the specific language governing permissions and
|
||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
<com.android.systemui.biometrics.SidefpsView
|
<com.airbnb.lottie.LottieAnimationView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:systemui="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/sidefps_view"
|
android:id="@+id/sidefps_animation"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/accessibility_fingerprint_label">
|
app:lottie_autoPlay="true"
|
||||||
</com.android.systemui.biometrics.SidefpsView>
|
app:lottie_loop="true"
|
||||||
|
app:lottie_rawRes="@raw/sfps_pulse"
|
||||||
|
android:contentDescription="@string/accessibility_fingerprint_label"/>
|
||||||
|
|||||||
1
packages/SystemUI/res/raw/sfps_pulse.json
Normal file
1
packages/SystemUI/res/raw/sfps_pulse.json
Normal file
File diff suppressed because one or more lines are too long
1
packages/SystemUI/res/raw/sfps_pulse_landscape.json
Normal file
1
packages/SystemUI/res/raw/sfps_pulse_landscape.json
Normal file
File diff suppressed because one or more lines are too long
@@ -27,6 +27,7 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.hardware.biometrics.BiometricSourceType;
|
import android.hardware.biometrics.BiometricSourceType;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
@@ -330,8 +331,9 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
|
|||||||
private void updateLockIconLocation() {
|
private void updateLockIconLocation() {
|
||||||
if (mUdfpsSupported) {
|
if (mUdfpsSupported) {
|
||||||
FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
|
FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
|
||||||
mView.setCenterLocation(new PointF(props.sensorLocationX, props.sensorLocationY),
|
final SensorLocationInternal location = props.getLocation();
|
||||||
props.sensorRadius);
|
mView.setCenterLocation(new PointF(location.sensorLocationX, location.sensorLocationY),
|
||||||
|
location.sensorRadius);
|
||||||
} else {
|
} else {
|
||||||
mView.setCenterLocation(
|
mView.setCenterLocation(
|
||||||
new PointF(mWidthPixels / 2,
|
new PointF(mWidthPixels / 2,
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
IBiometricSysuiReceiver mReceiver;
|
IBiometricSysuiReceiver mReceiver;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@NonNull final BiometricOrientationEventListener mOrientationListener;
|
@NonNull final BiometricDisplayListener mOrientationListener;
|
||||||
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
|
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
|
||||||
@Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
|
@Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
|
||||||
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
|
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
|
||||||
@@ -459,13 +459,15 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
|
|||||||
mSidefpsControllerFactory = sidefpsControllerFactory;
|
mSidefpsControllerFactory = sidefpsControllerFactory;
|
||||||
mWindowManager = windowManager;
|
mWindowManager = windowManager;
|
||||||
mUdfpsEnrolledForUser = new SparseBooleanArray();
|
mUdfpsEnrolledForUser = new SparseBooleanArray();
|
||||||
mOrientationListener = new BiometricOrientationEventListener(context,
|
mOrientationListener = new BiometricDisplayListener(
|
||||||
|
context,
|
||||||
|
displayManager,
|
||||||
|
handler,
|
||||||
|
BiometricDisplayListener.SensorType.Generic.INSTANCE,
|
||||||
() -> {
|
() -> {
|
||||||
onOrientationChanged();
|
onOrientationChanged();
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
},
|
});
|
||||||
displayManager,
|
|
||||||
handler);
|
|
||||||
|
|
||||||
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
|
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ class AuthRippleController @Inject constructor(
|
|||||||
private fun updateUdfpsDependentParams() {
|
private fun updateUdfpsDependentParams() {
|
||||||
authController.udfpsProps?.let {
|
authController.udfpsProps?.let {
|
||||||
if (it.size > 0) {
|
if (it.size > 0) {
|
||||||
udfpsRadius = it[0].sensorRadius.toFloat()
|
udfpsRadius = it[0].location.sensorRadius.toFloat()
|
||||||
udfpsController = udfpsControllerProvider.get()
|
udfpsController = udfpsControllerProvider.get()
|
||||||
|
|
||||||
if (mView.isAttachedToWindow) {
|
if (mView.isAttachedToWindow) {
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.biometrics
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.hardware.display.DisplayManager
|
||||||
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||||
|
import android.os.Handler
|
||||||
|
import android.view.Surface
|
||||||
|
import com.android.systemui.biometrics.BiometricDisplayListener.SensorType.Generic
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A listener for keeping overlays for biometric sensors aligned with the physical device
|
||||||
|
* device's screen. The [onChanged] will be dispatched on the [handler]
|
||||||
|
* whenever a relevant change to the device's configuration (orientation, fold, display change,
|
||||||
|
* etc.) may require the UI to change for the given [sensorType].
|
||||||
|
*/
|
||||||
|
class BiometricDisplayListener(
|
||||||
|
private val context: Context,
|
||||||
|
private val displayManager: DisplayManager,
|
||||||
|
private val handler: Handler,
|
||||||
|
private val sensorType: SensorType = SensorType.Generic,
|
||||||
|
private val onChanged: () -> Unit
|
||||||
|
) : DisplayManager.DisplayListener {
|
||||||
|
|
||||||
|
private var lastRotation = context.display?.rotation ?: Surface.ROTATION_0
|
||||||
|
|
||||||
|
override fun onDisplayAdded(displayId: Int) {}
|
||||||
|
override fun onDisplayRemoved(displayId: Int) {}
|
||||||
|
override fun onDisplayChanged(displayId: Int) {
|
||||||
|
val rotationChanged = didRotationChange()
|
||||||
|
|
||||||
|
when (sensorType) {
|
||||||
|
is SensorType.SideFingerprint -> onChanged()
|
||||||
|
else -> {
|
||||||
|
if (rotationChanged) {
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun didRotationChange(): Boolean {
|
||||||
|
val rotation = context.display?.rotation ?: return false
|
||||||
|
val last = lastRotation
|
||||||
|
lastRotation = rotation
|
||||||
|
return last != rotation
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Listen for changes. */
|
||||||
|
fun enable() {
|
||||||
|
displayManager.registerDisplayListener(this, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stop listening for changes. */
|
||||||
|
fun disable() {
|
||||||
|
displayManager.unregisterDisplayListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of sensor to determine what kind of display changes require layouts.
|
||||||
|
*
|
||||||
|
* The [Generic] type should be used in cases where the modality can vary, such as
|
||||||
|
* biometric prompt (and this object will likely change as multi-mode auth is added).
|
||||||
|
*/
|
||||||
|
sealed class SensorType {
|
||||||
|
object Generic : SensorType()
|
||||||
|
data class UnderDisplayFingerprint(
|
||||||
|
val properties: FingerprintSensorPropertiesInternal
|
||||||
|
) : SensorType()
|
||||||
|
data class SideFingerprint(
|
||||||
|
val properties: FingerprintSensorPropertiesInternal
|
||||||
|
) : SensorType()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.systemui.biometrics
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.hardware.display.DisplayManager
|
|
||||||
import android.os.Handler
|
|
||||||
import android.view.OrientationEventListener
|
|
||||||
import android.view.Surface
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An [OrientationEventListener] that invokes the [onOrientationChanged] callback whenever
|
|
||||||
* the orientation of the device has changed in order to keep overlays for biometric sensors
|
|
||||||
* aligned with the device's screen.
|
|
||||||
*/
|
|
||||||
class BiometricOrientationEventListener(
|
|
||||||
private val context: Context,
|
|
||||||
private val onOrientationChanged: () -> Unit,
|
|
||||||
private val displayManager: DisplayManager,
|
|
||||||
private val handler: Handler
|
|
||||||
) : DisplayManager.DisplayListener {
|
|
||||||
|
|
||||||
private var lastRotation = context.display?.rotation ?: Surface.ROTATION_0
|
|
||||||
|
|
||||||
override fun onDisplayAdded(displayId: Int) {}
|
|
||||||
override fun onDisplayRemoved(displayId: Int) {}
|
|
||||||
override fun onDisplayChanged(displayId: Int) {
|
|
||||||
val rotation = context.display?.rotation ?: return
|
|
||||||
if (lastRotation != rotation) {
|
|
||||||
lastRotation = rotation
|
|
||||||
|
|
||||||
onOrientationChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enable() {
|
|
||||||
displayManager.registerDisplayListener(this, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun disable() {
|
|
||||||
displayManager.unregisterDisplayListener(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.systemui.biometrics;
|
|
||||||
|
|
||||||
import static com.android.internal.util.Preconditions.checkArgument;
|
|
||||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.hardware.display.DisplayManager;
|
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
|
||||||
import android.hardware.fingerprint.ISidefpsController;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
|
||||||
import com.android.systemui.R;
|
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
|
||||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import kotlin.Unit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events.
|
|
||||||
*/
|
|
||||||
@SysUISingleton
|
|
||||||
public class SidefpsController {
|
|
||||||
private static final String TAG = "SidefpsController";
|
|
||||||
@NonNull private final Context mContext;
|
|
||||||
@NonNull private final LayoutInflater mInflater;
|
|
||||||
private final FingerprintManager mFingerprintManager;
|
|
||||||
private final WindowManager mWindowManager;
|
|
||||||
private final DelayableExecutor mFgExecutor;
|
|
||||||
@VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
|
|
||||||
|
|
||||||
// TODO: update mDisplayHeight and mDisplayWidth for multi-display devices
|
|
||||||
private final int mDisplayHeight;
|
|
||||||
private final int mDisplayWidth;
|
|
||||||
|
|
||||||
private boolean mIsVisible = false;
|
|
||||||
@Nullable private SidefpsView mView;
|
|
||||||
|
|
||||||
static final int SFPS_AFFORDANCE_WIDTH = 50; // in default portrait mode
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final ISidefpsController mSidefpsControllerImpl = new ISidefpsController.Stub() {
|
|
||||||
@Override
|
|
||||||
public void show() {
|
|
||||||
mFgExecutor.execute(() -> {
|
|
||||||
SidefpsController.this.show();
|
|
||||||
mIsVisible = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void hide() {
|
|
||||||
mFgExecutor.execute(() -> {
|
|
||||||
SidefpsController.this.hide();
|
|
||||||
mIsVisible = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
final FingerprintSensorPropertiesInternal mSensorProps;
|
|
||||||
private final WindowManager.LayoutParams mCoreLayoutParams;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public SidefpsController(@NonNull Context context,
|
|
||||||
@NonNull LayoutInflater inflater,
|
|
||||||
@Nullable FingerprintManager fingerprintManager,
|
|
||||||
@NonNull WindowManager windowManager,
|
|
||||||
@Main DelayableExecutor fgExecutor,
|
|
||||||
@NonNull DisplayManager displayManager,
|
|
||||||
@Main Handler handler) {
|
|
||||||
mContext = context;
|
|
||||||
mInflater = inflater;
|
|
||||||
mFingerprintManager = checkNotNull(fingerprintManager);
|
|
||||||
mWindowManager = windowManager;
|
|
||||||
mFgExecutor = fgExecutor;
|
|
||||||
mOrientationListener = new BiometricOrientationEventListener(
|
|
||||||
context,
|
|
||||||
() -> {
|
|
||||||
onOrientationChanged();
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
},
|
|
||||||
displayManager,
|
|
||||||
handler);
|
|
||||||
|
|
||||||
mSensorProps = findFirstSidefps();
|
|
||||||
checkArgument(mSensorProps != null);
|
|
||||||
|
|
||||||
mCoreLayoutParams = new WindowManager.LayoutParams(
|
|
||||||
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
|
|
||||||
getCoreLayoutParamFlags(),
|
|
||||||
PixelFormat.TRANSLUCENT);
|
|
||||||
mCoreLayoutParams.setTitle(TAG);
|
|
||||||
// Overrides default, avoiding status bars during layout
|
|
||||||
mCoreLayoutParams.setFitInsetsTypes(0);
|
|
||||||
mCoreLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
|
||||||
mCoreLayoutParams.layoutInDisplayCutoutMode =
|
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
|
||||||
mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
|
||||||
|
|
||||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
|
||||||
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
|
|
||||||
mDisplayHeight = displayMetrics.heightPixels;
|
|
||||||
mDisplayWidth = displayMetrics.widthPixels;
|
|
||||||
|
|
||||||
mFingerprintManager.setSidefpsController(mSidefpsControllerImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void show() {
|
|
||||||
mView = (SidefpsView) mInflater.inflate(R.layout.sidefps_view, null, false);
|
|
||||||
mView.setSensorProperties(mSensorProps);
|
|
||||||
mWindowManager.addView(mView, computeLayoutParams());
|
|
||||||
|
|
||||||
mOrientationListener.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hide() {
|
|
||||||
if (mView != null) {
|
|
||||||
mWindowManager.removeView(mView);
|
|
||||||
mView.setOnTouchListener(null);
|
|
||||||
mView.setOnHoverListener(null);
|
|
||||||
mView = null;
|
|
||||||
} else {
|
|
||||||
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
mOrientationListener.disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOrientationChanged() {
|
|
||||||
// If mView is null or if view is hidden, then return.
|
|
||||||
if (mView == null || !mIsVisible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the overlay needs to be displayed with a new configuration, destroy the current
|
|
||||||
// overlay, and re-create and show the overlay with the updated LayoutParams.
|
|
||||||
hide();
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private FingerprintSensorPropertiesInternal findFirstSidefps() {
|
|
||||||
for (FingerprintSensorPropertiesInternal props :
|
|
||||||
mFingerprintManager.getSensorPropertiesInternal()) {
|
|
||||||
if (props.isAnySidefpsType()) {
|
|
||||||
// TODO(b/188690214): L155-L173 can be removed once sensorLocationX,
|
|
||||||
// sensorLocationY, and sensorRadius are defined in sensorProps by the HAL
|
|
||||||
int sensorLocationX = 25;
|
|
||||||
int sensorLocationY = 610;
|
|
||||||
int sensorRadius = 112;
|
|
||||||
|
|
||||||
FingerprintSensorPropertiesInternal tempProps =
|
|
||||||
new FingerprintSensorPropertiesInternal(
|
|
||||||
props.sensorId,
|
|
||||||
props.sensorStrength,
|
|
||||||
props.maxEnrollmentsPerUser,
|
|
||||||
props.componentInfo,
|
|
||||||
props.sensorType,
|
|
||||||
props.resetLockoutRequiresHardwareAuthToken,
|
|
||||||
sensorLocationX,
|
|
||||||
sensorLocationY,
|
|
||||||
sensorRadius
|
|
||||||
);
|
|
||||||
props = tempProps;
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getCoreLayoutParamFlags() {
|
|
||||||
return WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
|
||||||
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
|
||||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
|
||||||
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes layout params depending on orientation & folding configuration of device
|
|
||||||
*/
|
|
||||||
private WindowManager.LayoutParams computeLayoutParams() {
|
|
||||||
mCoreLayoutParams.flags = getCoreLayoutParamFlags();
|
|
||||||
// Y value of top of affordance in portrait mode, X value of left of affordance in landscape
|
|
||||||
int sfpsLocationY = mSensorProps.sensorLocationY - mSensorProps.sensorRadius;
|
|
||||||
int sfpsAffordanceHeight = mSensorProps.sensorRadius * 2;
|
|
||||||
|
|
||||||
// Calculate coordinates of drawable area for the fps affordance, accounting for orientation
|
|
||||||
switch (mContext.getDisplay().getRotation()) {
|
|
||||||
case Surface.ROTATION_90:
|
|
||||||
mCoreLayoutParams.x = sfpsLocationY;
|
|
||||||
mCoreLayoutParams.y = 0;
|
|
||||||
mCoreLayoutParams.height = SFPS_AFFORDANCE_WIDTH;
|
|
||||||
mCoreLayoutParams.width = sfpsAffordanceHeight;
|
|
||||||
break;
|
|
||||||
case Surface.ROTATION_270:
|
|
||||||
mCoreLayoutParams.x = mDisplayHeight - sfpsLocationY - sfpsAffordanceHeight;
|
|
||||||
mCoreLayoutParams.y = mDisplayWidth - SFPS_AFFORDANCE_WIDTH;
|
|
||||||
mCoreLayoutParams.height = SFPS_AFFORDANCE_WIDTH;
|
|
||||||
mCoreLayoutParams.width = sfpsAffordanceHeight;
|
|
||||||
break;
|
|
||||||
default: // Portrait
|
|
||||||
mCoreLayoutParams.x = mDisplayWidth - SFPS_AFFORDANCE_WIDTH;
|
|
||||||
mCoreLayoutParams.y = sfpsLocationY;
|
|
||||||
mCoreLayoutParams.height = sfpsAffordanceHeight;
|
|
||||||
mCoreLayoutParams.width = SFPS_AFFORDANCE_WIDTH;
|
|
||||||
}
|
|
||||||
return mCoreLayoutParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.biometrics
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.PixelFormat
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.hardware.display.DisplayManager
|
||||||
|
import android.hardware.fingerprint.FingerprintManager
|
||||||
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||||
|
import android.hardware.fingerprint.ISidefpsController
|
||||||
|
import android.os.Handler
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.Display
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Surface
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.annotation.RawRes
|
||||||
|
import com.airbnb.lottie.LottieAnimationView
|
||||||
|
import com.android.internal.annotations.VisibleForTesting
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val TAG = "SidefpsController"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
class SidefpsController @Inject constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val layoutInflater: LayoutInflater,
|
||||||
|
fingerprintManager: FingerprintManager?,
|
||||||
|
private val windowManager: WindowManager,
|
||||||
|
@Main mainExecutor: DelayableExecutor,
|
||||||
|
displayManager: DisplayManager,
|
||||||
|
@Main handler: Handler
|
||||||
|
) {
|
||||||
|
@VisibleForTesting
|
||||||
|
val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager
|
||||||
|
?.sensorPropertiesInternal
|
||||||
|
?.firstOrNull { it.isAnySidefpsType }
|
||||||
|
?: throw IllegalStateException("no side fingerprint sensor")
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
val orientationListener = BiometricDisplayListener(
|
||||||
|
context,
|
||||||
|
displayManager,
|
||||||
|
handler,
|
||||||
|
BiometricDisplayListener.SensorType.SideFingerprint(sensorProps)
|
||||||
|
) { onOrientationChanged() }
|
||||||
|
|
||||||
|
private var overlayView: View? = null
|
||||||
|
set(value) {
|
||||||
|
field?.let { oldView ->
|
||||||
|
windowManager.removeView(oldView)
|
||||||
|
orientationListener.disable()
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
field?.let { newView ->
|
||||||
|
windowManager.addView(newView, overlayViewParams)
|
||||||
|
orientationListener.enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val overlayViewParams = WindowManager.LayoutParams(
|
||||||
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
|
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
|
||||||
|
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||||
|
or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||||
|
or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||||
|
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
|
||||||
|
PixelFormat.TRANSLUCENT
|
||||||
|
).apply {
|
||||||
|
title = TAG
|
||||||
|
fitInsetsTypes = 0 // overrides default, avoiding status bars during layout
|
||||||
|
gravity = Gravity.TOP or Gravity.LEFT
|
||||||
|
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|
||||||
|
privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
fingerprintManager?.setSidefpsController(object : ISidefpsController.Stub() {
|
||||||
|
override fun show() = mainExecutor.execute {
|
||||||
|
if (overlayView == null) {
|
||||||
|
overlayView = createOverlayForDisplay()
|
||||||
|
} else {
|
||||||
|
Log.v(TAG, "overlay already shown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun hide() = mainExecutor.execute { overlayView = null }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onOrientationChanged() {
|
||||||
|
if (overlayView != null) {
|
||||||
|
overlayView = createOverlayForDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createOverlayForDisplay(): View {
|
||||||
|
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
|
||||||
|
val display = context.display!!
|
||||||
|
|
||||||
|
val lottie = view.findViewById(R.id.sidefps_animation) as LottieAnimationView
|
||||||
|
lottie.setAnimation(display.asSideFpsAnimation())
|
||||||
|
view.rotation = display.asSideFpsAnimationRotation()
|
||||||
|
|
||||||
|
updateOverlayParams(display, lottie.composition?.bounds ?: Rect())
|
||||||
|
lottie.addLottieOnCompositionLoadedListener {
|
||||||
|
if (overlayView == view) {
|
||||||
|
updateOverlayParams(display, it.bounds)
|
||||||
|
windowManager.updateViewLayout(overlayView, overlayViewParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateOverlayParams(display: Display, bounds: Rect) {
|
||||||
|
val isPortrait = display.isPortrait()
|
||||||
|
val size = windowManager.maximumWindowMetrics.bounds
|
||||||
|
val displayWidth = if (isPortrait) size.width() else size.height()
|
||||||
|
val displayHeight = if (isPortrait) size.height() else size.width()
|
||||||
|
val offsets = sensorProps.getLocation(display.uniqueId).let { location ->
|
||||||
|
if (location == null) {
|
||||||
|
Log.w(TAG, "No location specified for display: ${display.uniqueId}")
|
||||||
|
}
|
||||||
|
location ?: sensorProps.location
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore sensorLocationX and sensorRadius since it's assumed to be on the side
|
||||||
|
// of the device and centered at sensorLocationY
|
||||||
|
val (x, y) = when (display.rotation) {
|
||||||
|
Surface.ROTATION_90 ->
|
||||||
|
Pair(offsets.sensorLocationY, 0)
|
||||||
|
Surface.ROTATION_270 ->
|
||||||
|
Pair(displayHeight - offsets.sensorLocationY - bounds.width(), displayWidth)
|
||||||
|
Surface.ROTATION_180 ->
|
||||||
|
Pair(0, displayHeight - offsets.sensorLocationY - bounds.height())
|
||||||
|
else ->
|
||||||
|
Pair(displayWidth, offsets.sensorLocationY)
|
||||||
|
}
|
||||||
|
overlayViewParams.x = x
|
||||||
|
overlayViewParams.y = y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RawRes
|
||||||
|
private fun Display.asSideFpsAnimation(): Int = when (rotation) {
|
||||||
|
Surface.ROTATION_0 -> R.raw.sfps_pulse
|
||||||
|
Surface.ROTATION_180 -> R.raw.sfps_pulse
|
||||||
|
else -> R.raw.sfps_pulse_landscape
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Display.asSideFpsAnimationRotation(): Float = when (rotation) {
|
||||||
|
Surface.ROTATION_180 -> 180f
|
||||||
|
Surface.ROTATION_270 -> 180f
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Display.isPortrait(): Boolean =
|
||||||
|
rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.systemui.biometrics;
|
|
||||||
|
|
||||||
import static com.android.systemui.biometrics.SidefpsController.SFPS_AFFORDANCE_WIDTH;
|
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A view containing a normal drawable view for sidefps events.
|
|
||||||
*/
|
|
||||||
public class SidefpsView extends FrameLayout {
|
|
||||||
private static final String TAG = "SidefpsView";
|
|
||||||
private static final int POINTER_SIZE_PX = 50;
|
|
||||||
private static final int ROUND_RADIUS = 15;
|
|
||||||
|
|
||||||
@NonNull private final RectF mSensorRect;
|
|
||||||
@NonNull private final Paint mSensorRectPaint;
|
|
||||||
@NonNull private final Paint mPointerText;
|
|
||||||
@NonNull private final Context mContext;
|
|
||||||
|
|
||||||
// Used to obtain the sensor location.
|
|
||||||
@NonNull private FingerprintSensorPropertiesInternal mSensorProps;
|
|
||||||
@Surface.Rotation private int mOrientation;
|
|
||||||
|
|
||||||
public SidefpsView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
super.setWillNotDraw(false);
|
|
||||||
mContext = context;
|
|
||||||
mPointerText = new Paint(0 /* flags */);
|
|
||||||
mPointerText.setAntiAlias(true);
|
|
||||||
mPointerText.setColor(Color.WHITE);
|
|
||||||
mPointerText.setTextSize(POINTER_SIZE_PX);
|
|
||||||
|
|
||||||
mSensorRect = new RectF();
|
|
||||||
mSensorRectPaint = new Paint(0 /* flags */);
|
|
||||||
mSensorRectPaint.setAntiAlias(true);
|
|
||||||
mSensorRectPaint.setColor(Color.BLUE); // TODO: Fix Color
|
|
||||||
mSensorRectPaint.setStyle(Paint.Style.FILL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
|
|
||||||
mSensorProps = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas) {
|
|
||||||
super.onDraw(canvas);
|
|
||||||
canvas.drawRoundRect(mSensorRect, ROUND_RADIUS, ROUND_RADIUS, mSensorRectPaint);
|
|
||||||
int x, y;
|
|
||||||
if (mOrientation == Surface.ROTATION_90 || mOrientation == Surface.ROTATION_270) {
|
|
||||||
x = mSensorProps.sensorRadius + 10;
|
|
||||||
y = SFPS_AFFORDANCE_WIDTH / 2 + 15;
|
|
||||||
} else {
|
|
||||||
x = SFPS_AFFORDANCE_WIDTH / 2 - 10;
|
|
||||||
y = mSensorProps.sensorRadius + 30;
|
|
||||||
}
|
|
||||||
canvas.drawText(
|
|
||||||
">",
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
mPointerText
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
|
||||||
mOrientation = mContext.getDisplay().getRotation();
|
|
||||||
if (mOrientation == Surface.ROTATION_90 || mOrientation == Surface.ROTATION_270) {
|
|
||||||
right = mSensorProps.sensorRadius * 2;
|
|
||||||
bottom = SFPS_AFFORDANCE_WIDTH;
|
|
||||||
} else {
|
|
||||||
right = SFPS_AFFORDANCE_WIDTH;
|
|
||||||
bottom = mSensorProps.sensorRadius * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSensorRect.set(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
right,
|
|
||||||
bottom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,6 +33,7 @@ import android.graphics.PixelFormat;
|
|||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.hardware.biometrics.BiometricOverlayConstants;
|
import android.hardware.biometrics.BiometricOverlayConstants;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.display.DisplayManager;
|
import android.hardware.display.DisplayManager;
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
@@ -129,7 +130,7 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
@NonNull private final KeyguardBypassController mKeyguardBypassController;
|
@NonNull private final KeyguardBypassController mKeyguardBypassController;
|
||||||
@NonNull private final ConfigurationController mConfigurationController;
|
@NonNull private final ConfigurationController mConfigurationController;
|
||||||
@NonNull private final SystemClock mSystemClock;
|
@NonNull private final SystemClock mSystemClock;
|
||||||
@VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
|
@VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
|
||||||
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
|
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
|
||||||
// sensors, this, in addition to a lot of the code here, will be updated.
|
// sensors, this, in addition to a lot of the code here, will be updated.
|
||||||
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
|
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
|
||||||
@@ -558,14 +559,6 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
mHbmProvider = hbmProvider.orElse(null);
|
mHbmProvider = hbmProvider.orElse(null);
|
||||||
screenLifecycle.addObserver(mScreenObserver);
|
screenLifecycle.addObserver(mScreenObserver);
|
||||||
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
|
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
|
||||||
mOrientationListener = new BiometricOrientationEventListener(
|
|
||||||
context,
|
|
||||||
() -> {
|
|
||||||
onOrientationChanged();
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
},
|
|
||||||
displayManager,
|
|
||||||
mainHandler);
|
|
||||||
mKeyguardBypassController = keyguardBypassController;
|
mKeyguardBypassController = keyguardBypassController;
|
||||||
mConfigurationController = configurationController;
|
mConfigurationController = configurationController;
|
||||||
mSystemClock = systemClock;
|
mSystemClock = systemClock;
|
||||||
@@ -573,6 +566,15 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
mSensorProps = findFirstUdfps();
|
mSensorProps = findFirstUdfps();
|
||||||
// At least one UDFPS sensor exists
|
// At least one UDFPS sensor exists
|
||||||
checkArgument(mSensorProps != null);
|
checkArgument(mSensorProps != null);
|
||||||
|
mOrientationListener = new BiometricDisplayListener(
|
||||||
|
context,
|
||||||
|
displayManager,
|
||||||
|
mainHandler,
|
||||||
|
new BiometricDisplayListener.SensorType.UnderDisplayFingerprint(mSensorProps),
|
||||||
|
() -> {
|
||||||
|
onOrientationChanged();
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
mCoreLayoutParams = new WindowManager.LayoutParams(
|
mCoreLayoutParams = new WindowManager.LayoutParams(
|
||||||
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
|
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
|
||||||
@@ -642,10 +644,11 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
// on lockscreen and for the udfps light reveal animation on keyguard.
|
// on lockscreen and for the udfps light reveal animation on keyguard.
|
||||||
// Keyguard is only shown in portrait mode for now, so this will need to
|
// Keyguard is only shown in portrait mode for now, so this will need to
|
||||||
// be updated if that ever changes.
|
// be updated if that ever changes.
|
||||||
return new RectF(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
|
final SensorLocationInternal location = mSensorProps.getLocation();
|
||||||
mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
|
return new RectF(location.sensorLocationX - location.sensorRadius,
|
||||||
mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
|
location.sensorLocationY - location.sensorRadius,
|
||||||
mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
|
location.sensorLocationX + location.sensorRadius,
|
||||||
|
location.sensorLocationY + location.sensorRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverlay() {
|
private void updateOverlay() {
|
||||||
@@ -669,10 +672,11 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Default dimensions assume portrait mode.
|
// Default dimensions assume portrait mode.
|
||||||
mCoreLayoutParams.x = mSensorProps.sensorLocationX - mSensorProps.sensorRadius - paddingX;
|
final SensorLocationInternal location = mSensorProps.getLocation();
|
||||||
mCoreLayoutParams.y = mSensorProps.sensorLocationY - mSensorProps.sensorRadius - paddingY;
|
mCoreLayoutParams.x = location.sensorLocationX - location.sensorRadius - paddingX;
|
||||||
mCoreLayoutParams.height = 2 * mSensorProps.sensorRadius + 2 * paddingX;
|
mCoreLayoutParams.y = location.sensorLocationY - location.sensorRadius - paddingY;
|
||||||
mCoreLayoutParams.width = 2 * mSensorProps.sensorRadius + 2 * paddingY;
|
mCoreLayoutParams.height = 2 * location.sensorRadius + 2 * paddingX;
|
||||||
|
mCoreLayoutParams.width = 2 * location.sensorRadius + 2 * paddingY;
|
||||||
|
|
||||||
Point p = new Point();
|
Point p = new Point();
|
||||||
// Gets the size based on the current rotation of the display.
|
// Gets the size based on the current rotation of the display.
|
||||||
@@ -685,9 +689,9 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
&& mKeyguardUpdateMonitor.isGoingToSleep()) {
|
&& mKeyguardUpdateMonitor.isGoingToSleep()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mCoreLayoutParams.x = mSensorProps.sensorLocationY - mSensorProps.sensorRadius
|
mCoreLayoutParams.x = location.sensorLocationY - location.sensorRadius
|
||||||
- paddingX;
|
- paddingX;
|
||||||
mCoreLayoutParams.y = p.y - mSensorProps.sensorLocationX - mSensorProps.sensorRadius
|
mCoreLayoutParams.y = p.y - location.sensorLocationX - location.sensorRadius
|
||||||
- paddingY;
|
- paddingY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -696,9 +700,9 @@ public class UdfpsController implements DozeReceiver {
|
|||||||
&& mKeyguardUpdateMonitor.isGoingToSleep()) {
|
&& mKeyguardUpdateMonitor.isGoingToSleep()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mCoreLayoutParams.x = p.x - mSensorProps.sensorLocationY - mSensorProps.sensorRadius
|
mCoreLayoutParams.x = p.x - location.sensorLocationY - location.sensorRadius
|
||||||
- paddingX;
|
- paddingX;
|
||||||
mCoreLayoutParams.y = mSensorProps.sensorLocationX - mSensorProps.sensorRadius
|
mCoreLayoutParams.y = location.sensorLocationX - location.sensorRadius
|
||||||
- paddingY;
|
- paddingY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
|
|||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.graphics.Insets;
|
import android.graphics.Insets;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@@ -93,7 +94,7 @@ public class UdfpsDialogMeasureAdapter {
|
|||||||
// Go through each of the children and do the custom measurement.
|
// Go through each of the children and do the custom measurement.
|
||||||
int totalHeight = 0;
|
int totalHeight = 0;
|
||||||
final int numChildren = mView.getChildCount();
|
final int numChildren = mView.getChildCount();
|
||||||
final int sensorDiameter = mSensorProps.sensorRadius * 2;
|
final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
|
||||||
for (int i = 0; i < numChildren; i++) {
|
for (int i = 0; i < numChildren; i++) {
|
||||||
final View child = mView.getChildAt(i);
|
final View child = mView.getChildAt(i);
|
||||||
if (child.getId() == R.id.biometric_icon_frame) {
|
if (child.getId() == R.id.biometric_icon_frame) {
|
||||||
@@ -160,7 +161,7 @@ public class UdfpsDialogMeasureAdapter {
|
|||||||
final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape(
|
final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape(
|
||||||
mSensorProps, displayWidth, dialogMargin, horizontalInset);
|
mSensorProps, displayWidth, dialogMargin, horizontalInset);
|
||||||
|
|
||||||
final int sensorDiameter = mSensorProps.sensorRadius * 2;
|
final int sensorDiameter = mSensorProps.getLocation().sensorRadius * 2;
|
||||||
final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth;
|
final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth;
|
||||||
|
|
||||||
int remeasuredHeight = 0;
|
int remeasuredHeight = 0;
|
||||||
@@ -257,10 +258,10 @@ public class UdfpsDialogMeasureAdapter {
|
|||||||
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx,
|
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx,
|
||||||
int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx,
|
int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx,
|
||||||
int navbarBottomInsetPx) {
|
int navbarBottomInsetPx) {
|
||||||
|
final SensorLocationInternal location = sensorProperties.getLocation();
|
||||||
final int sensorDistanceFromBottom = displayHeightPx
|
final int sensorDistanceFromBottom = displayHeightPx
|
||||||
- sensorProperties.sensorLocationY
|
- location.sensorLocationY
|
||||||
- sensorProperties.sensorRadius;
|
- location.sensorRadius;
|
||||||
|
|
||||||
final int spacerHeight = sensorDistanceFromBottom
|
final int spacerHeight = sensorDistanceFromBottom
|
||||||
- textIndicatorHeightPx
|
- textIndicatorHeightPx
|
||||||
@@ -318,10 +319,10 @@ public class UdfpsDialogMeasureAdapter {
|
|||||||
static int calculateHorizontalSpacerWidthForLandscape(
|
static int calculateHorizontalSpacerWidthForLandscape(
|
||||||
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx,
|
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx,
|
||||||
int dialogMarginPx, int navbarHorizontalInsetPx) {
|
int dialogMarginPx, int navbarHorizontalInsetPx) {
|
||||||
|
final SensorLocationInternal location = sensorProperties.getLocation();
|
||||||
final int sensorDistanceFromEdge = displayWidthPx
|
final int sensorDistanceFromEdge = displayWidthPx
|
||||||
- sensorProperties.sensorLocationY
|
- location.sensorLocationY
|
||||||
- sensorProperties.sensorRadius;
|
- location.sensorRadius;
|
||||||
|
|
||||||
final int horizontalPadding = sensorDistanceFromEdge
|
final int horizontalPadding = sensorDistanceFromEdge
|
||||||
- dialogMarginPx
|
- dialogMarginPx
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
|
|||||||
|
|
||||||
void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
||||||
View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
|
View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
|
||||||
final int sensorHeight = sensorProps.sensorRadius * 2;
|
final int sensorHeight = sensorProps.getLocation().sensorRadius * 2;
|
||||||
final int sensorWidth = sensorHeight;
|
final int sensorWidth = sensorHeight;
|
||||||
ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
|
ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
|
||||||
params.width = sensorWidth;
|
params.width = sensorWidth;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import android.graphics.Color;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
@@ -141,11 +142,12 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
|
|||||||
: mAnimationViewController.getPaddingX();
|
: mAnimationViewController.getPaddingX();
|
||||||
int paddingY = mAnimationViewController == null ? 0
|
int paddingY = mAnimationViewController == null ? 0
|
||||||
: mAnimationViewController.getPaddingY();
|
: mAnimationViewController.getPaddingY();
|
||||||
|
final SensorLocationInternal location = mSensorProps.getLocation();
|
||||||
mSensorRect.set(
|
mSensorRect.set(
|
||||||
paddingX,
|
paddingX,
|
||||||
paddingY,
|
paddingY,
|
||||||
2 * mSensorProps.sensorRadius + paddingX,
|
2 * location.sensorRadius + paddingX,
|
||||||
2 * mSensorProps.sensorRadius + paddingY);
|
2 * location.sensorRadius + paddingY);
|
||||||
|
|
||||||
if (mAnimationViewController != null) {
|
if (mAnimationViewController != null) {
|
||||||
mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));
|
mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.hardware.biometrics.ComponentInfoInternal;
|
import android.hardware.biometrics.ComponentInfoInternal;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.biometrics.SensorProperties;
|
import android.hardware.biometrics.SensorProperties;
|
||||||
import android.hardware.fingerprint.FingerprintSensorProperties;
|
import android.hardware.fingerprint.FingerprintSensorProperties;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
@@ -257,9 +258,10 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
|
|||||||
componentInfo,
|
componentInfo,
|
||||||
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
||||||
true /* resetLockoutRequiresHardwareAuthToken */,
|
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||||
|
List.of(new SensorLocationInternal("" /* displayId */,
|
||||||
540 /* sensorLocationX */,
|
540 /* sensorLocationX */,
|
||||||
1600 /* sensorLocationY */,
|
1600 /* sensorLocationY */,
|
||||||
100 /* sensorRadius */);
|
100 /* sensorRadius */)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestableView extends AuthBiometricFaceToFingerprintView {
|
public class TestableView extends AuthBiometricFaceToFingerprintView {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.biometrics
|
package com.android.systemui.biometrics
|
||||||
|
|
||||||
|
import android.graphics.Rect
|
||||||
import android.hardware.biometrics.SensorProperties
|
import android.hardware.biometrics.SensorProperties
|
||||||
import android.hardware.display.DisplayManager
|
import android.hardware.display.DisplayManager
|
||||||
import android.hardware.display.DisplayManagerGlobal
|
import android.hardware.display.DisplayManagerGlobal
|
||||||
@@ -30,8 +31,12 @@ import android.view.Display
|
|||||||
import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
|
import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
|
||||||
import android.view.DisplayInfo
|
import android.view.DisplayInfo
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowInsets
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.view.WindowMetrics
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.airbnb.lottie.LottieAnimationView
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
@@ -42,9 +47,13 @@ import org.junit.Test
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
import org.mockito.ArgumentMatchers.eq
|
import org.mockito.ArgumentMatchers.eq
|
||||||
|
import org.mockito.Captor
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
import org.mockito.Mockito.any
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.reset
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.junit.MockitoJUnit
|
import org.mockito.junit.MockitoJUnit
|
||||||
|
|
||||||
@@ -66,11 +75,13 @@ class SidefpsControllerTest : SysuiTestCase() {
|
|||||||
@Mock
|
@Mock
|
||||||
lateinit var windowManager: WindowManager
|
lateinit var windowManager: WindowManager
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var sidefpsView: SidefpsView
|
lateinit var sidefpsView: View
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var displayManager: DisplayManager
|
lateinit var displayManager: DisplayManager
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var handler: Handler
|
lateinit var handler: Handler
|
||||||
|
@Captor
|
||||||
|
lateinit var overlayCaptor: ArgumentCaptor<View>
|
||||||
|
|
||||||
private val executor = FakeExecutor(FakeSystemClock())
|
private val executor = FakeExecutor(FakeSystemClock())
|
||||||
private lateinit var overlayController: ISidefpsController
|
private lateinit var overlayController: ISidefpsController
|
||||||
@@ -79,6 +90,8 @@ class SidefpsControllerTest : SysuiTestCase() {
|
|||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
`when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView)
|
`when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView)
|
||||||
|
`when`(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
|
||||||
|
.thenReturn(mock(LottieAnimationView::class.java))
|
||||||
`when`(fingerprintManager.sensorPropertiesInternal).thenReturn(
|
`when`(fingerprintManager.sensorPropertiesInternal).thenReturn(
|
||||||
listOf(
|
listOf(
|
||||||
FingerprintSensorPropertiesInternal(
|
FingerprintSensorPropertiesInternal(
|
||||||
@@ -99,6 +112,9 @@ class SidefpsControllerTest : SysuiTestCase() {
|
|||||||
DEFAULT_DISPLAY_ADJUSTMENTS
|
DEFAULT_DISPLAY_ADJUSTMENTS
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
`when`(windowManager.maximumWindowMetrics).thenReturn(
|
||||||
|
WindowMetrics(Rect(0, 0, 800, 800), WindowInsets.CONSUMED)
|
||||||
|
)
|
||||||
|
|
||||||
sideFpsController = SidefpsController(
|
sideFpsController = SidefpsController(
|
||||||
mContext, layoutInflater, fingerprintManager, windowManager, executor,
|
mContext, layoutInflater, fingerprintManager, windowManager, executor,
|
||||||
@@ -121,4 +137,44 @@ class SidefpsControllerTest : SysuiTestCase() {
|
|||||||
executor.runAllReady()
|
executor.runAllReady()
|
||||||
verify(displayManager).unregisterDisplayListener(any())
|
verify(displayManager).unregisterDisplayListener(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testShowsAndHides() {
|
||||||
|
overlayController.show()
|
||||||
|
executor.runAllReady()
|
||||||
|
|
||||||
|
verify(windowManager).addView(overlayCaptor.capture(), any())
|
||||||
|
|
||||||
|
reset(windowManager)
|
||||||
|
overlayController.hide()
|
||||||
|
executor.runAllReady()
|
||||||
|
|
||||||
|
verify(windowManager, never()).addView(any(), any())
|
||||||
|
verify(windowManager).removeView(eq(overlayCaptor.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testShowsOnce() {
|
||||||
|
repeat(5) {
|
||||||
|
overlayController.show()
|
||||||
|
executor.runAllReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(windowManager).addView(any(), any())
|
||||||
|
verify(windowManager, never()).removeView(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testHidesOnce() {
|
||||||
|
overlayController.show()
|
||||||
|
executor.runAllReady()
|
||||||
|
|
||||||
|
repeat(5) {
|
||||||
|
overlayController.hide()
|
||||||
|
executor.runAllReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(windowManager).addView(any(), any())
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.systemui.biometrics;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.hardware.biometrics.ComponentInfoInternal;
|
import android.hardware.biometrics.ComponentInfoInternal;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.biometrics.SensorProperties;
|
import android.hardware.biometrics.SensorProperties;
|
||||||
import android.hardware.fingerprint.FingerprintSensorProperties;
|
import android.hardware.fingerprint.FingerprintSensorProperties;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
@@ -61,8 +62,9 @@ public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
|
|||||||
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
|
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
|
||||||
componentInfo,
|
componentInfo,
|
||||||
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
||||||
true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
|
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||||
sensorRadius);
|
List.of(new SensorLocationInternal("" /* displayId */,
|
||||||
|
sensorLocationX, sensorLocationY, sensorRadius)));
|
||||||
|
|
||||||
assertEquals(970,
|
assertEquals(970,
|
||||||
UdfpsDialogMeasureAdapter.calculateBottomSpacerHeightForPortrait(
|
UdfpsDialogMeasureAdapter.calculateBottomSpacerHeightForPortrait(
|
||||||
@@ -125,8 +127,9 @@ public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
|
|||||||
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
|
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
|
||||||
componentInfo,
|
componentInfo,
|
||||||
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
||||||
true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
|
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||||
sensorRadius);
|
List.of(new SensorLocationInternal("" /* displayId */,
|
||||||
|
sensorLocationX, sensorLocationY, sensorRadius)));
|
||||||
|
|
||||||
assertEquals(1205,
|
assertEquals(1205,
|
||||||
UdfpsDialogMeasureAdapter.calculateHorizontalSpacerWidthForLandscape(
|
UdfpsDialogMeasureAdapter.calculateHorizontalSpacerWidthForLandscape(
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
@@ -132,7 +133,8 @@ public class LockIconViewControllerTest extends SysuiTestCase {
|
|||||||
/* component info */ new ArrayList<>(),
|
/* component info */ new ArrayList<>(),
|
||||||
/* sensorType */ 3,
|
/* sensorType */ 3,
|
||||||
/* resetLockoutRequiresHwToken */ false,
|
/* resetLockoutRequiresHwToken */ false,
|
||||||
(int) udfpsLocation.x, (int) udfpsLocation.y, radius);
|
List.of(new SensorLocationInternal("" /* displayId */,
|
||||||
|
(int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
|
||||||
when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
|
when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
|
||||||
when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
|
when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
|
||||||
|
|
||||||
@@ -165,7 +167,8 @@ public class LockIconViewControllerTest extends SysuiTestCase {
|
|||||||
/* component info */ new ArrayList<>(),
|
/* component info */ new ArrayList<>(),
|
||||||
/* sensorType */ 3,
|
/* sensorType */ 3,
|
||||||
/* resetLockoutRequiresHwToken */ false,
|
/* resetLockoutRequiresHwToken */ false,
|
||||||
(int) udfpsLocation.x, (int) udfpsLocation.y, radius);
|
List.of(new SensorLocationInternal("" /* displayId */,
|
||||||
|
(int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
|
||||||
when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
|
when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
|
||||||
when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
|
when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import android.hardware.biometrics.IInvalidationCallback;
|
|||||||
import android.hardware.biometrics.ITestSession;
|
import android.hardware.biometrics.ITestSession;
|
||||||
import android.hardware.biometrics.ITestSessionCallback;
|
import android.hardware.biometrics.ITestSessionCallback;
|
||||||
import android.hardware.biometrics.PromptInfo;
|
import android.hardware.biometrics.PromptInfo;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.biometrics.SensorPropertiesInternal;
|
import android.hardware.biometrics.SensorPropertiesInternal;
|
||||||
import android.hardware.face.FaceSensorProperties;
|
import android.hardware.face.FaceSensorProperties;
|
||||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||||
@@ -766,8 +767,9 @@ public class AuthService extends SystemService {
|
|||||||
if (isUdfps && udfpsProps.length == 3) {
|
if (isUdfps && udfpsProps.length == 3) {
|
||||||
return new FingerprintSensorPropertiesInternal(sensorId,
|
return new FingerprintSensorPropertiesInternal(sensorId,
|
||||||
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
|
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
|
||||||
componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken, udfpsProps[0],
|
componentInfo, sensorType, resetLockoutRequiresHardwareAuthToken,
|
||||||
udfpsProps[1], udfpsProps[2]);
|
List.of(new SensorLocationInternal("" /* display */,
|
||||||
|
udfpsProps[0], udfpsProps[1], udfpsProps[2])));
|
||||||
} else {
|
} else {
|
||||||
return new FingerprintSensorPropertiesInternal(sensorId,
|
return new FingerprintSensorPropertiesInternal(sensorId,
|
||||||
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
|
Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import android.hardware.biometrics.BiometricsProtoEnums;
|
|||||||
import android.hardware.biometrics.common.ICancellationSignal;
|
import android.hardware.biometrics.common.ICancellationSignal;
|
||||||
import android.hardware.biometrics.fingerprint.ISession;
|
import android.hardware.biometrics.fingerprint.ISession;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
|
import android.hardware.fingerprint.ISidefpsController;
|
||||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -67,6 +68,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
|
|||||||
int sensorId, boolean isStrongBiometric, int statsClient,
|
int sensorId, boolean isStrongBiometric, int statsClient,
|
||||||
@Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
|
@Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
|
||||||
@Nullable IUdfpsOverlayController udfpsOverlayController,
|
@Nullable IUdfpsOverlayController udfpsOverlayController,
|
||||||
|
@Nullable ISidefpsController sidefpsController,
|
||||||
boolean allowBackgroundAuthentication,
|
boolean allowBackgroundAuthentication,
|
||||||
@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
||||||
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
|
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
|
||||||
@@ -76,7 +78,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
|
|||||||
false /* isKeyguardBypassEnabled */);
|
false /* isKeyguardBypassEnabled */);
|
||||||
setRequestId(requestId);
|
setRequestId(requestId);
|
||||||
mLockoutCache = lockoutCache;
|
mLockoutCache = lockoutCache;
|
||||||
mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */);
|
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
||||||
mSensorProps = sensorProps;
|
mSensorProps = sensorProps;
|
||||||
mALSProbeCallback = createALSCallback(false /* startWithClient */);
|
mALSProbeCallback = createALSCallback(false /* startWithClient */);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,12 @@ import android.app.ActivityTaskManager;
|
|||||||
import android.app.TaskStackListener;
|
import android.app.TaskStackListener;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.hardware.biometrics.ComponentInfoInternal;
|
import android.hardware.biometrics.ComponentInfoInternal;
|
||||||
import android.hardware.biometrics.IInvalidationCallback;
|
import android.hardware.biometrics.IInvalidationCallback;
|
||||||
import android.hardware.biometrics.ITestSession;
|
import android.hardware.biometrics.ITestSession;
|
||||||
import android.hardware.biometrics.ITestSessionCallback;
|
import android.hardware.biometrics.ITestSessionCallback;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
import android.hardware.biometrics.common.ComponentInfo;
|
import android.hardware.biometrics.common.ComponentInfo;
|
||||||
import android.hardware.biometrics.fingerprint.IFingerprint;
|
import android.hardware.biometrics.fingerprint.IFingerprint;
|
||||||
import android.hardware.biometrics.fingerprint.SensorProps;
|
import android.hardware.biometrics.fingerprint.SensorProps;
|
||||||
@@ -145,6 +147,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
|||||||
mActivityTaskManager = ActivityTaskManager.getInstance();
|
mActivityTaskManager = ActivityTaskManager.getInstance();
|
||||||
mTaskStackListener = new BiometricTaskStackListener();
|
mTaskStackListener = new BiometricTaskStackListener();
|
||||||
|
|
||||||
|
final List<SensorLocationInternal> workaroundLocations = getWorkaroundSensorProps(context);
|
||||||
|
|
||||||
for (SensorProps prop : props) {
|
for (SensorProps prop : props) {
|
||||||
final int sensorId = prop.commonProps.sensorId;
|
final int sensorId = prop.commonProps.sensorId;
|
||||||
|
|
||||||
@@ -164,9 +168,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
|||||||
componentInfo,
|
componentInfo,
|
||||||
prop.sensorType,
|
prop.sensorType,
|
||||||
true /* resetLockoutRequiresHardwareAuthToken */,
|
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||||
|
!workaroundLocations.isEmpty() ? workaroundLocations :
|
||||||
|
List.of(new SensorLocationInternal(
|
||||||
|
"" /* displayId */,
|
||||||
prop.sensorLocations[0].sensorLocationX,
|
prop.sensorLocations[0].sensorLocationX,
|
||||||
prop.sensorLocations[0].sensorLocationY,
|
prop.sensorLocations[0].sensorLocationY,
|
||||||
prop.sensorLocations[0].sensorRadius);
|
prop.sensorLocations[0].sensorRadius)));
|
||||||
final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
|
final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
|
||||||
internalProp, lockoutResetDispatcher, gestureAvailabilityDispatcher);
|
internalProp, lockoutResetDispatcher, gestureAvailabilityDispatcher);
|
||||||
|
|
||||||
@@ -403,7 +410,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
|||||||
userId, operationId, restricted, opPackageName, cookie,
|
userId, operationId, restricted, opPackageName, cookie,
|
||||||
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
|
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
|
||||||
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
|
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
|
||||||
mUdfpsOverlayController, allowBackgroundAuthentication,
|
mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication,
|
||||||
mSensors.get(sensorId).getSensorProperties());
|
mSensors.get(sensorId).getSensorProperties());
|
||||||
scheduleForSensor(sensorId, client, mFingerprintStateCallback);
|
scheduleForSensor(sensorId, client, mFingerprintStateCallback);
|
||||||
});
|
});
|
||||||
@@ -647,4 +654,45 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
|
|||||||
void setTestHalEnabled(boolean enabled) {
|
void setTestHalEnabled(boolean enabled) {
|
||||||
mTestHalEnabled = enabled;
|
mTestHalEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(b/174868353): workaround for gaps in HAL interface (remove and get directly from HAL)
|
||||||
|
// reads values via an overlay instead of querying the HAL
|
||||||
|
@NonNull
|
||||||
|
private List<SensorLocationInternal> getWorkaroundSensorProps(@NonNull Context context) {
|
||||||
|
final List<SensorLocationInternal> sensorLocations = new ArrayList<>();
|
||||||
|
|
||||||
|
final TypedArray sfpsProps = context.getResources().obtainTypedArray(
|
||||||
|
com.android.internal.R.array.config_sfps_sensor_props);
|
||||||
|
for (int i = 0; i < sfpsProps.length(); i++) {
|
||||||
|
final int id = sfpsProps.getResourceId(i, -1);
|
||||||
|
if (id > 0) {
|
||||||
|
final SensorLocationInternal location = parseSensorLocation(
|
||||||
|
context.getResources().obtainTypedArray(id));
|
||||||
|
if (location != null) {
|
||||||
|
sensorLocations.add(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sfpsProps.recycle();
|
||||||
|
|
||||||
|
return sensorLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private SensorLocationInternal parseSensorLocation(@Nullable TypedArray array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new SensorLocationInternal(
|
||||||
|
array.getString(0),
|
||||||
|
array.getInt(1, 0),
|
||||||
|
array.getInt(2, 0),
|
||||||
|
array.getInt(3, 0));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.w(getTag(), "malformed sensor location", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -629,7 +629,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
|
|||||||
mContext, mLazyDaemon, token, requestId, listener, userId, operationId,
|
mContext, mLazyDaemon, token, requestId, listener, userId, operationId,
|
||||||
restricted, opPackageName, cookie, false /* requireConfirmation */,
|
restricted, opPackageName, cookie, false /* requireConfirmation */,
|
||||||
mSensorProperties.sensorId, isStrongBiometric, statsClient,
|
mSensorProperties.sensorId, isStrongBiometric, statsClient,
|
||||||
mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
|
mTaskStackListener, mLockoutTracker,
|
||||||
|
mUdfpsOverlayController, mSidefpsController,
|
||||||
allowBackgroundAuthentication, mSensorProperties);
|
allowBackgroundAuthentication, mSensorProperties);
|
||||||
mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
|
mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -426,8 +426,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
|
|||||||
mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId,
|
mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId,
|
||||||
sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo,
|
sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo,
|
||||||
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
||||||
resetLockoutRequiresHardwareAuthToken, sensorProps.sensorLocationX,
|
resetLockoutRequiresHardwareAuthToken, sensorProps.getAllLocations());
|
||||||
sensorProps.sensorLocationY, sensorProps.sensorRadius);
|
|
||||||
mMockHalResultController = controller;
|
mMockHalResultController = controller;
|
||||||
mUserHasTrust = new SparseBooleanArray();
|
mUserHasTrust = new SparseBooleanArray();
|
||||||
mTrustManager = context.getSystemService(TrustManager.class);
|
mTrustManager = context.getSystemService(TrustManager.class);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricFingerprintConstants;
|
|||||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||||
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
|
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
|
import android.hardware.fingerprint.ISidefpsController;
|
||||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -67,6 +68,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
|
|||||||
@NonNull TaskStackListener taskStackListener,
|
@NonNull TaskStackListener taskStackListener,
|
||||||
@NonNull LockoutFrameworkImpl lockoutTracker,
|
@NonNull LockoutFrameworkImpl lockoutTracker,
|
||||||
@Nullable IUdfpsOverlayController udfpsOverlayController,
|
@Nullable IUdfpsOverlayController udfpsOverlayController,
|
||||||
|
@Nullable ISidefpsController sidefpsController,
|
||||||
boolean allowBackgroundAuthentication,
|
boolean allowBackgroundAuthentication,
|
||||||
@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
@NonNull FingerprintSensorPropertiesInternal sensorProps) {
|
||||||
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
|
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
|
||||||
@@ -76,7 +78,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
|
|||||||
false /* isKeyguardBypassEnabled */);
|
false /* isKeyguardBypassEnabled */);
|
||||||
setRequestId(requestId);
|
setRequestId(requestId);
|
||||||
mLockoutFrameworkImpl = lockoutTracker;
|
mLockoutFrameworkImpl = lockoutTracker;
|
||||||
mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */);
|
mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
|
||||||
mSensorProps = sensorProps;
|
mSensorProps = sensorProps;
|
||||||
mALSProbeCallback = createALSCallback(false /* startWithClient */);
|
mALSProbeCallback = createALSCallback(false /* startWithClient */);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,13 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.mockito.Mockito.anyInt;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.hardware.biometrics.common.CommonProps;
|
import android.hardware.biometrics.common.CommonProps;
|
||||||
import android.hardware.biometrics.fingerprint.IFingerprint;
|
import android.hardware.biometrics.fingerprint.IFingerprint;
|
||||||
import android.hardware.biometrics.fingerprint.SensorLocation;
|
import android.hardware.biometrics.fingerprint.SensorLocation;
|
||||||
@@ -56,6 +59,8 @@ public class FingerprintProviderTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
@Mock
|
@Mock
|
||||||
|
private Resources mResources;
|
||||||
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
@Mock
|
@Mock
|
||||||
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
|
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
|
||||||
@@ -74,19 +79,21 @@ public class FingerprintProviderTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
when(mContext.getResources()).thenReturn(mResources);
|
||||||
|
when(mResources.obtainTypedArray(anyInt())).thenReturn(mock(TypedArray.class));
|
||||||
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
|
||||||
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
|
||||||
|
|
||||||
final SensorProps sensor1 = new SensorProps();
|
final SensorProps sensor1 = new SensorProps();
|
||||||
sensor1.commonProps = new CommonProps();
|
sensor1.commonProps = new CommonProps();
|
||||||
sensor1.commonProps.sensorId = 0;
|
sensor1.commonProps.sensorId = 0;
|
||||||
sensor1.sensorLocations = new SensorLocation[] {new SensorLocation()};
|
sensor1.sensorLocations = new SensorLocation[]{new SensorLocation()};
|
||||||
final SensorProps sensor2 = new SensorProps();
|
final SensorProps sensor2 = new SensorProps();
|
||||||
sensor2.commonProps = new CommonProps();
|
sensor2.commonProps = new CommonProps();
|
||||||
sensor2.commonProps.sensorId = 1;
|
sensor2.commonProps.sensorId = 1;
|
||||||
sensor2.sensorLocations = new SensorLocation[] {new SensorLocation()};
|
sensor2.sensorLocations = new SensorLocation[]{new SensorLocation()};
|
||||||
|
|
||||||
mSensorProps = new SensorProps[] {sensor1, sensor2};
|
mSensorProps = new SensorProps[]{sensor1, sensor2};
|
||||||
|
|
||||||
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user