Merge "Refactor FingerprintEnrollEnrolling to fragment" into udc-dev

This commit is contained in:
Vincent Wang
2023-02-21 05:21:51 +00:00
committed by Android (Google) Code Review
6 changed files with 243 additions and 52 deletions

View File

@@ -142,7 +142,10 @@ public class UdfpsEnrollHelper extends InstrumentedFragment {
setRetainInstance(true);
}
void onEnrollmentProgress(int totalSteps, int remaining) {
/**
* Called when a enroll progress update
*/
public void onEnrollmentProgress(int totalSteps, int remaining) {
if (mTotalSteps == -1) {
mTotalSteps = totalSteps;
}
@@ -161,25 +164,37 @@ public class UdfpsEnrollHelper extends InstrumentedFragment {
}
}
void onEnrollmentHelp() {
/**
* Called when a receive error has been encountered during enrollment.
*/
public void onEnrollmentHelp() {
if (mListener != null) {
mListener.onEnrollmentHelp(mRemainingSteps, mTotalSteps);
}
}
void onAcquired(boolean isAcquiredGood) {
/**
* Called when a fingerprint image has been acquired, but wasn't processed yet.
*/
public void onAcquired(boolean isAcquiredGood) {
if (mListener != null && mTotalSteps != -1) {
mListener.onAcquired(isAcquiredGood && animateIfLastStep());
}
}
void onPointerDown(int sensorId) {
/**
* Called when pointer down
*/
public void onPointerDown(int sensorId) {
if (mListener != null) {
mListener.onPointerDown(sensorId);
}
}
void onPointerUp(int sensorId) {
/**
* Called when pointer up
*/
public void onPointerUp(int sensorId) {
if (mListener != null) {
mListener.onPointerUp(sensorId);
}

View File

@@ -108,7 +108,10 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
return mOverlayParams;
}
void setOverlayParams(UdfpsOverlayParams params) {
/**
* Set UdfpsOverlayParams
*/
public void setOverlayParams(UdfpsOverlayParams params) {
mOverlayParams = params;
post(() -> {
@@ -121,7 +124,10 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
});
}
void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
/**
* Set UdfpsEnrollHelper
*/
public void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
mFingerprintDrawable.setEnrollHelper(enrollHelper);
enrollHelper.setListener(this);
}
@@ -193,6 +199,8 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
params.height = rotatedBounds.height() + 2 * getPaddingX();
params.width = rotatedBounds.width() + 2 * getPaddingY();
setLayoutParams(params);
}
private void onFingerDown() {

View File

@@ -65,4 +65,13 @@ public class AccessibilityRepository {
public void sendAccessibilityEvent(@NonNull AccessibilityEvent event) {
mAccessibilityManager.sendAccessibilityEvent(event);
}
/**
* Returns if the touch exploration in the system is enabled.
*
* @return True if touch exploration is enabled, false otherwise.
*/
public boolean isTouchExplorationEnabled() {
return mAccessibilityManager.isTouchExplorationEnabled();
}
}

View File

@@ -35,7 +35,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -329,12 +328,7 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment {
}
private void announceEnrollmentProgress(CharSequence announcement) {
AccessibilityEvent event = new AccessibilityEvent();
event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
event.setClassName(getClass().getName());
event.setPackageName(getClass().getPackageName());
event.getText().add(announcement);
mEnrollingViewModel.sendAccessibilityEvent(event);
mEnrollingViewModel.sendAccessibilityEvent(announcement);
}
private void onEnrollmentProgressChange(@NonNull EnrollmentProgress progress) {

View File

@@ -22,18 +22,23 @@ import android.annotation.RawRes;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.DisplayInfo;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -47,15 +52,20 @@ import androidx.transition.TransitionSet;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.fingerprint.UdfpsEnrollHelper;
import com.android.settings.biometrics.fingerprint.UdfpsEnrollView;
import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel;
import com.android.settingslib.display.DisplayDensityUtils;
import com.android.settingslib.udfps.UdfpsOverlayParams;
import com.android.settingslib.udfps.UdfpsUtils;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieCompositionFactory;
import com.google.android.setupcompat.template.FooterActionButton;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
@@ -70,9 +80,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private static final String TAG = FingerprintEnrollEnrollingUdfpsFragment.class.getSimpleName();
private static final int PROGRESS_BAR_MAX = 10000;
private static final long ICON_TOUCH_DURATION_UNTIL_DIALOG_SHOWN = 500;
private static final int ICON_TOUCH_COUNT_SHOW_UNTIL_DIALOG_SHOWN = 3;
private static final int HINT_TIMEOUT_DURATION = 2500;
private static final int STAGE_UNKNOWN = -1;
private static final int STAGE_CENTER = 0;
@@ -100,35 +107,52 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private GlifLayout mView;
private TextView mErrorText;
private FooterBarMixin mFooterBarMixin;
private AnimatedVectorDrawable mIconAnimationDrawable;
private AnimatedVectorDrawable mIconBackgroundBlinksDrawable;
private boolean mShouldShowLottie;
private boolean mIsAccessibilityEnabled;
private final View.OnClickListener mOnSkipClickListener =
(v) -> mEnrollingViewModel.onCancelledDueToOnSkipPressed();
private final Observer<EnrollmentProgress> mProgressObserver = progress -> {
private Observer<EnrollmentProgress> mProgressObserver = progress -> {
if (progress != null) {
onEnrollmentProgressChange(progress);
}
};
private Observer<EnrollmentStatusMessage> mHelpMessageObserver = helpMessage -> {
if (helpMessage != null) {
onEnrollmentHelp(helpMessage.getMsgId(), helpMessage.getStr());
}
};
private Observer<EnrollmentStatusMessage> mErrorMessageObserver = errorMessage -> {
// TODO
};
private final Observer<EnrollmentStatusMessage> mHelpMessageObserver = helpMessage -> {
// TODO
};
private final Observer<EnrollmentStatusMessage> mErrorMessageObserver = errorMessage -> {
// TODO
};
private final Observer<Boolean> mAcquireObserver = isAcquiredGood -> {
// TODO
private Observer<Boolean> mAcquireObserver = isAcquiredGood -> {
if (isAcquiredGood != null) {
onAcquired(isAcquiredGood);
}
};
private final Observer<Integer> mPointerDownObserver = sensorId -> {
// TODO
if (sensorId != null) {
onPointerDown(sensorId);
}
};
private final Observer<Integer> mPointerUpObserver = sensorId -> {
// TODO
if (sensorId != null) {
onPointerUp(sensorId);
}
};
private int mIconTouchCount;
private UdfpsUtils mUdfpsUtils;
private float mScaleFactor = 1.0f;
//TODO UdfpsEnrollHelper should not be a Fragment, we should tell enrollview & progress
// drawable enough information EnrollView & ProgressDrawable should draw themselves without
// UdfpsEnrollHelper
private UdfpsEnrollHelper mUdfpsEnrollHelper;
@Override
public void onAttach(@NonNull Context context) {
final FragmentActivity activity = getActivity();
@@ -176,6 +200,10 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
super.onCreate(savedInstanceState);
mEnrollingViewModel.restoreSavedState(savedInstanceState);
mIsAccessibilityEnabled = mEnrollingViewModel.isAccessibilityEnabled();
mUdfpsUtils = new UdfpsUtils();
mUdfpsEnrollHelper = new UdfpsEnrollHelper(getActivity(), getActivity().getSystemService(
FingerprintManager.class
));
}
@Override
@@ -188,13 +216,15 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = initUdfpsLayout(inflater, container);
return mView;
}
private GlifLayout initUdfpsLayout(LayoutInflater inflater, ViewGroup container) {
final GlifLayout containView = (GlifLayout) inflater.inflate(
R.layout.udfps_enroll_enrolling, container, false);
final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(inflater,
mEnrollingViewModel.getFirstFingerprintSensorPropertiesInternal());
final int rotation = mRotationViewModel.getLiveData().getValue();
if (rotation == Surface.ROTATION_90) {
final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(
@@ -207,19 +237,36 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
isLayoutRtl ? 0 : (int) getResources().getDimension(
R.dimen.rotation_90_enroll_padding_end),
0);
final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
lp.setMarginEnd((int) getResources().getDimension(
R.dimen.rotation_90_enroll_margin_end));
layoutContainer.setLayoutParams(lp);
containView.addView(udfpsEnrollView);
containView.setClipChildren(false);
containView.setClipToPadding(false);
containView.setLayoutParams(lp);
setOnHoverListener(true, containView, udfpsEnrollView);
} else if (rotation == Surface.ROTATION_270) {
containView.addView(udfpsEnrollView);
containView.setClipChildren(false);
containView.setClipToPadding(false);
setOnHoverListener(true, containView, udfpsEnrollView);
} else {
final FrameLayout portraitLayoutContainer = containView.findViewById(
R.id.layout_container);
portraitLayoutContainer.addView(udfpsEnrollView);
ViewGroup parent = ((ViewGroup) portraitLayoutContainer.getParent());
parent.setClipChildren(false);
parent.setClipToPadding(false);
setOnHoverListener(false, containView, udfpsEnrollView);
}
final Activity activity = getActivity();
new GlifLayoutHelper(activity, containView).setDescriptionText(
getString(R.string.security_settings_udfps_enroll_start_message));
updateTitleAndDescription();
mShouldShowLottie = shouldShowLottie();
boolean isLandscape = BiometricUtils.isReverseLandscape(activity)
@@ -245,6 +292,19 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(
activity, android.R.interpolator.fast_out_linear_in);
final LinearLayout buttonContainer = mFooterBarMixin.getButtonContainer();
View spaceView = null;
for (int i = 0; i < buttonContainer.getChildCount(); i++) {
if (!(buttonContainer.getChildAt(i) instanceof FooterActionButton)) {
spaceView = buttonContainer.getChildAt(i);
break;
}
}
if (spaceView != null) {
spaceView.setVisibility(View.GONE);
buttonContainer.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
return containView;
}
@@ -298,6 +358,9 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
final int progress = getProgress(enrollmentProgress);
mUdfpsEnrollHelper.onEnrollmentProgress(enrollmentProgress.getSteps(),
enrollmentProgress.getRemaining());
if (animate) {
animateProgress(progress);
} else if (progress >= PROGRESS_BAR_MAX) {
@@ -319,6 +382,38 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
super.onDestroy();
}
private UdfpsEnrollView addUdfpsEnrollView(LayoutInflater inflater,
FingerprintSensorPropertiesInternal udfpsProps) {
UdfpsEnrollView enrollView = (UdfpsEnrollView) inflater.inflate(R.layout.udfps_enroll_view,
null, false);
DisplayInfo displayInfo = new DisplayInfo();
getActivity().getDisplay().getDisplayInfo(displayInfo);
mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
Rect udfpsBounds = udfpsProps.getLocation().getRect();
udfpsBounds.scale(mScaleFactor);
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(),
mScaleFactor,
displayInfo.rotation);
enrollView.setOverlayParams(params);
enrollView.setEnrollHelper(mUdfpsEnrollHelper);
return enrollView;
}
private void animateProgress(int progress) {
// UDFPS animations are owned by SystemUI
if (progress >= PROGRESS_BAR_MAX) {
@@ -462,16 +557,10 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
private void startIconAnimation() {
if (mIconAnimationDrawable != null) {
mIconAnimationDrawable.start();
}
}
private void stopIconAnimation() {
mAnimationCancelled = true;
if (mIconAnimationDrawable != null) {
mIconAnimationDrawable.stop();
}
}
private int getCurrentStage() {
@@ -545,6 +634,79 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
});
}
private void setOnHoverListener(boolean isLandscape, GlifLayout enrollLayout,
UdfpsEnrollView udfpsEnrollView) {
if (!mIsAccessibilityEnabled) return;
final Context context = getActivity();
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, udfpsEnrollView.getOverlayParams());
final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea(
mEnrollingViewModel.isTouchExplorationEnabled(), context,
scaledTouch.x, scaledTouch.y, udfpsEnrollView.getOverlayParams());
if (theStr != null) {
v.announceForAccessibility(theStr);
}
return false;
};
enrollLayout.findManagedViewById(isLandscape ? R.id.sud_landscape_content_area
: R.id.sud_layout_content).setOnHoverListener(onHoverListener);
}
private void onEnrollmentProgressChange(@NonNull EnrollmentProgress progress) {
updateProgress(true /* animate */, progress);
updateTitleAndDescription();
if (mIsAccessibilityEnabled) {
final int steps = progress.getSteps();
final int remaining = progress.getRemaining();
final int percent = (int) (((float) (steps - remaining) / (float) steps) * 100);
CharSequence announcement = getActivity().getString(
R.string.security_settings_udfps_enroll_progress_a11y_message, percent);
mEnrollingViewModel.sendAccessibilityEvent(announcement);
}
}
private void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (!TextUtils.isEmpty(helpString)) {
showError(helpString);
mUdfpsEnrollHelper.onEnrollmentHelp();
}
}
private void onAcquired(boolean isAcquiredGood) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onAcquired(isAcquiredGood);
}
}
private void onPointerDown(int sensorId) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onPointerDown(sensorId);
}
}
private void onPointerUp(int sensorId) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onPointerUp(sensorId);
}
}
private void showError(CharSequence error) {
mView.setHeaderText(error);
mView.getHeaderTextView().setContentDescription(error);
new GlifLayoutHelper(getActivity(), mView).setDescriptionText("");
}
private final Runnable mShowDialogRunnable = new Runnable() {
@Override
public void run() {

View File

@@ -23,7 +23,6 @@ import android.os.Bundle;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -282,19 +281,23 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
/**
* Sends an {@link AccessibilityEvent}.
*
* @param event The event to send.
*
* @throws IllegalStateException if accessibility is not enabled.
*
* <strong>Note:</strong> The preferred mechanism for sending custom accessibility
* events is through calling
* {@link android.view.ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
* instead of this method to allow predecessors to augment/filter events sent by
* their descendants.
*/
public void sendAccessibilityEvent(@NonNull AccessibilityEvent event) {
mAccessibilityRepository.sendAccessibilityEvent(event);
public void sendAccessibilityEvent(CharSequence announcement) {
AccessibilityEvent e = AccessibilityEvent.obtain();
e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
e.setClassName(getClass().getName());
e.setPackageName(getApplication().getPackageName());
e.getText().add(announcement);
mAccessibilityRepository.sendAccessibilityEvent(e);
}
/**
* Returns if the touch exploration in the system is enabled.
*
* @return True if touch exploration is enabled, false otherwise.
*/
public boolean isTouchExplorationEnabled() {
return mAccessibilityRepository.isTouchExplorationEnabled();
}
/**