From be823bc5982df40990d92e0d342da7ea689f411e Mon Sep 17 00:00:00 2001 From: Hao Dong Date: Wed, 7 Jun 2023 00:02:48 +0000 Subject: [PATCH] Wait for systemui udfps overlay ready to show settings udfps enroll view. Previously, we show settings's udfps enroll animation view (the fingerprint icon and progress view) once the FingerprintEnrollEnrolling is shown. However, touch events have to wait for systemui's udfps overlay to be valid. This CL lets settings's udfps enroll view wait for systemui's overlay. 1. Sets udfps enroll animation view's default visibility Gone. 2. Propagates FingerprintManager#onUdfpsOverlayShown to FingerprintEnrollEnrolling and when it's called, set the enroll view visible. Besides, this CL renames onPointerDown() and onPointerUp() with Udfps. Bug: 280718879 Test: atest FingerprintEnrollEnrollingTest Change-Id: Ieed3e74c182828918785edcacb021f19a3665f2a --- res/layout/udfps_enroll_view.xml | 3 +- .../biometrics/BiometricEnrollSidecar.java | 48 ++-- .../FingerprintEnrollEnrolling.java | 11 +- .../fingerprint/FingerprintEnrollSidecar.java | 13 +- .../fingerprint/FingerprintUpdater.java | 13 +- .../fingerprint/UdfpsEnrollEnrollingView.java | 236 ++++++++++++++++++ .../FingerprintEnrollProgressViewModel.java | 4 +- .../FingerprintEnrollEnrollingTest.java | 21 +- ...ingerprintEnrollProgressViewModelTest.java | 4 +- 9 files changed, 320 insertions(+), 33 deletions(-) create mode 100644 src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java diff --git a/res/layout/udfps_enroll_view.xml b/res/layout/udfps_enroll_view.xml index 6bf339b6b07..bd626093ce4 100644 --- a/res/layout/udfps_enroll_view.xml +++ b/res/layout/udfps_enroll_view.xml @@ -18,7 +18,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/udfps_animation_view" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:visibility="gone"> { + secondaryButtonView.setLayoutParams( + new LinearLayout.LayoutParams(mHeaderView.getMeasuredWidth(), + ViewGroup.LayoutParams.WRAP_CONTENT)); + }); + } + + private void initUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps, + UdfpsEnrollHelper udfpsEnrollHelper) { + DisplayInfo displayInfo = new DisplayInfo(); + mContext.getDisplay().getDisplayInfo(displayInfo); + + final float scaleFactor = mUdfpsUtils.getScaleFactor(displayInfo); + Rect udfpsBounds = udfpsProps.getLocation().getRect(); + udfpsBounds.scale(scaleFactor); + + final Rect overlayBounds = new Rect( + 0, /* left */ + displayInfo.getNaturalHeight() / 2, /* top */ + displayInfo.getNaturalWidth(), /* right */ + displayInfo.getNaturalHeight() /* botom */); + + UdfpsOverlayParams params = new UdfpsOverlayParams( + udfpsBounds, + overlayBounds, + displayInfo.getNaturalWidth(), + displayInfo.getNaturalHeight(), + scaleFactor, + displayInfo.rotation); + + mUdfpsEnrollView.setOverlayParams(params); + mUdfpsEnrollView.setEnrollHelper(udfpsEnrollHelper); + } + + private void adjustPortraitPaddings() { + // In the portrait mode, layout_container's height is 0, so it's + // always shown at the bottom of the screen. + final FrameLayout portraitLayoutContainer = findViewById(R.id.layout_container); + + // In the portrait mode, the title and lottie animation view may + // overlap when title needs three lines, so adding some paddings + // between them, and adjusting the fp progress view here accordingly. + final int layoutLottieAnimationPadding = (int) getResources() + .getDimension(R.dimen.udfps_lottie_padding_top); + portraitLayoutContainer.setPadding(0, + layoutLottieAnimationPadding, 0, 0); + final ImageView progressView = mUdfpsEnrollView.findViewById( + R.id.udfps_enroll_animation_fp_progress_view); + progressView.setPadding(0, -(layoutLottieAnimationPadding), + 0, layoutLottieAnimationPadding); + final ImageView fingerprintView = mUdfpsEnrollView.findViewById( + R.id.udfps_enroll_animation_fp_view); + fingerprintView.setPadding(0, -layoutLottieAnimationPadding, + 0, layoutLottieAnimationPadding); + + // TODO(b/260970216) Instead of hiding the description text view, we should + // make the header view scrollable if the text is too long. + // If description text view has overlap with udfps progress view, hide it. + final View descView = getDescriptionTextView(); + getViewTreeObserver().addOnDrawListener(() -> { + if (descView.getVisibility() == View.VISIBLE + && hasOverlap(descView, mUdfpsEnrollView)) { + descView.setVisibility(View.GONE); + } + }); + } + + private void setOnHoverListener() { + if (!mAccessibilityManager.isEnabled()) return; + + final View.OnHoverListener onHoverListener = (v, event) -> { + // Map the touch to portrait mode if the device is in + // landscape mode. + final Point scaledTouch = + mUdfpsUtils.getTouchInNativeCoordinates(event.getPointerId(0), + event, mUdfpsEnrollView.getOverlayParams()); + + if (mUdfpsUtils.isWithinSensorArea(event.getPointerId(0), event, + mUdfpsEnrollView.getOverlayParams())) { + return false; + } + + final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea( + mAccessibilityManager.isTouchExplorationEnabled(), mContext, + scaledTouch.x, scaledTouch.y, mUdfpsEnrollView.getOverlayParams()); + if (theStr != null) { + v.announceForAccessibility(theStr); + } + return false; + }; + + findManagedViewById(mIsLandscape ? R.id.sud_landscape_content_area + : R.id.sud_layout_content).setOnHoverListener(onHoverListener); + } + + private void swapHeaderAndContent() { + // Reverse header and body + ViewGroup parentView = (ViewGroup) mHeaderView.getParent(); + parentView.removeView(mHeaderView); + parentView.addView(mHeaderView); + + // Hide scroll indicators + BottomScrollView headerScrollView = mHeaderView.findViewById(R.id.sud_header_scroll_view); + headerScrollView.setScrollIndicators(0); + } + + @VisibleForTesting + boolean hasOverlap(View view1, View view2) { + int[] firstPosition = new int[2]; + int[] secondPosition = new int[2]; + + view1.getLocationOnScreen(firstPosition); + view2.getLocationOnScreen(secondPosition); + + // Rect constructor parameters: left, top, right, bottom + Rect rectView1 = new Rect(firstPosition[0], firstPosition[1], + firstPosition[0] + view1.getMeasuredWidth(), + firstPosition[1] + view1.getMeasuredHeight()); + Rect rectView2 = new Rect(secondPosition[0], secondPosition[1], + secondPosition[0] + view2.getMeasuredWidth(), + secondPosition[1] + view2.getMeasuredHeight()); + return rectView1.intersect(rectView2); + } +} diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java index d77d9d3f7e8..7074288716e 100644 --- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java +++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java @@ -103,12 +103,12 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { } @Override - public void onPointerDown(int sensorId) { + public void onUdfpsPointerDown(int sensorId) { mPointerDownLiveData.postValue(sensorId); } @Override - public void onPointerUp(int sensorId) { + public void onUdfpsPointerUp(int sensorId) { mPointerUpLiveData.postValue(sensorId); } }; diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java index 959c6426894..e5b283ae185 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java @@ -339,6 +339,19 @@ public class FingerprintEnrollEnrollingTest { assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE); } + @Test + public void fingerprintUdfpsOverlayEnrollment_udfpsAnimationViewVisibility() { + initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL); + when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0); + createActivity(); + + final UdfpsEnrollView enrollView = mActivity.findViewById(R.id.udfps_animation_view); + assertThat(enrollView.getVisibility()).isEqualTo(View.GONE); + + mActivity.onUdfpsOverlayShown(); + assertThat(enrollView.getVisibility()).isEqualTo(View.VISIBLE); + } + @Test public void forwardEnrollProgressEvents() { initializeActivityFor(TYPE_UDFPS_OPTICAL); @@ -380,11 +393,11 @@ public class FingerprintEnrollEnrollingTest { } @Test - public void forwardEnrollPointerDownEvents() { + public void forwardUdfpsEnrollPointerDownEvents() { initializeActivityFor(TYPE_UDFPS_OPTICAL); EnrollListener listener = new EnrollListener(mActivity); - mActivity.onPointerDown(0); + mActivity.onUdfpsPointerDown(0); assertThat(listener.mProgress).isFalse(); assertThat(listener.mHelp).isFalse(); assertThat(listener.mAcquired).isFalse(); @@ -393,11 +406,11 @@ public class FingerprintEnrollEnrollingTest { } @Test - public void forwardEnrollPointerUpEvents() { + public void forwardUdfpsEnrollPointerUpEvents() { initializeActivityFor(TYPE_UDFPS_OPTICAL); EnrollListener listener = new EnrollListener(mActivity); - mActivity.onPointerUp(0); + mActivity.onUdfpsPointerUp(0); assertThat(listener.mProgress).isFalse(); assertThat(listener.mHelp).isFalse(); assertThat(listener.mAcquired).isFalse(); diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java index bdb45b0300f..2c830ad314c 100644 --- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java +++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java @@ -379,7 +379,7 @@ public class FingerprintEnrollProgressViewModelTest { // Notify acquire message final int value = 33; - mCallbackWrapper.mValue.onPointerDown(value); + mCallbackWrapper.mValue.onUdfpsPointerDown(value); assertThat(liveData.getValue()).isEqualTo(value); } @@ -397,7 +397,7 @@ public class FingerprintEnrollProgressViewModelTest { // Notify acquire message final int value = 44; - mCallbackWrapper.mValue.onPointerUp(value); + mCallbackWrapper.mValue.onUdfpsPointerUp(value); assertThat(liveData.getValue()).isEqualTo(value); }