From 8547eb1921498390e01d1a4937ccb2dae567f905 Mon Sep 17 00:00:00 2001 From: menghanli Date: Sat, 18 Feb 2023 12:20:18 +0800 Subject: [PATCH 1/5] fix(tablet): fix a11y button gesture assets to match new fancy ones on other a11y preferences Fix: 269717670 Test: 1. Go to Settings > Accessibility shortcuts > accessibility button & gesture. 2. Observe The Gesture's picture. 3. Go to any other accessibility's shortcut. 4. Observe the picture of the Use accessibility gesture. #2 should look like #4 Change-Id: I11f64648412c9795383d356e80d9dd499095f53b --- ...sture_navigation_three_finger_preview.xml} | 0 ...navigation_three_finger_preview_tablet.xml | 80 ++++++++++++++ ...gesture_navigation_two_finger_preview.xml} | 0 ...e_navigation_two_finger_preview_tablet.xml | 66 ++++++++++++ ...ibility_shortcut_type_software_gesture.xml | 38 +++---- ..._shortcut_type_software_gesture_tablet.xml | 84 +++++++-------- ...hortcut_type_software_gesture_talkback.xml | 44 ++++---- ..._type_software_gesture_talkback_tablet.xml | 101 ++++++++---------- ...sture_navigation_three_finger_preview.xml} | 0 ...navigation_three_finger_preview_tablet.xml | 80 ++++++++++++++ ...gesture_navigation_two_finger_preview.xml} | 0 ...e_navigation_two_finger_preview_tablet.xml | 66 ++++++++++++ ...ibility_shortcut_type_software_gesture.xml | 72 ++++++------- ..._shortcut_type_software_gesture_tablet.xml | 84 +++++++-------- ...hortcut_type_software_gesture_talkback.xml | 44 ++++---- ..._type_software_gesture_talkback_tablet.xml | 101 ++++++++---------- res/values/drawables.xml | 26 +++-- ...ccessibilityGestureNavigationTutorial.java | 4 +- 18 files changed, 575 insertions(+), 315 deletions(-) rename res/drawable-night/{illustration_accessibility_gesture_three_finger.xml => accessibility_gesture_navigation_three_finger_preview.xml} (100%) create mode 100644 res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml rename res/drawable-night/{illustration_accessibility_gesture_two_finger.xml => accessibility_gesture_navigation_two_finger_preview.xml} (100%) create mode 100644 res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml rename res/drawable/{illustration_accessibility_gesture_three_finger.xml => accessibility_gesture_navigation_three_finger_preview.xml} (100%) create mode 100644 res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml rename res/drawable/{illustration_accessibility_gesture_two_finger.xml => accessibility_gesture_navigation_two_finger_preview.xml} (100%) create mode 100644 res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml diff --git a/res/drawable-night/illustration_accessibility_gesture_three_finger.xml b/res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml similarity index 100% rename from res/drawable-night/illustration_accessibility_gesture_three_finger.xml rename to res/drawable-night/accessibility_gesture_navigation_three_finger_preview.xml diff --git a/res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml b/res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml new file mode 100644 index 00000000000..1710fa41f23 --- /dev/null +++ b/res/drawable-night/accessibility_gesture_navigation_three_finger_preview_tablet.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable-night/illustration_accessibility_gesture_two_finger.xml b/res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml similarity index 100% rename from res/drawable-night/illustration_accessibility_gesture_two_finger.xml rename to res/drawable-night/accessibility_gesture_navigation_two_finger_preview.xml diff --git a/res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml b/res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml new file mode 100644 index 00000000000..7a5cc48402c --- /dev/null +++ b/res/drawable-night/accessibility_gesture_navigation_two_finger_preview_tablet.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable-night/accessibility_shortcut_type_software_gesture.xml b/res/drawable-night/accessibility_shortcut_type_software_gesture.xml index 905586599fe..ea19f7451ff 100644 --- a/res/drawable-night/accessibility_shortcut_type_software_gesture.xml +++ b/res/drawable-night/accessibility_shortcut_type_software_gesture.xml @@ -19,22 +19,22 @@ android:height="300dp" android:viewportWidth="412" android:viewportHeight="300"> - - - - - - - + + + + + + + \ No newline at end of file diff --git a/res/drawable-night/accessibility_shortcut_type_software_gesture_tablet.xml b/res/drawable-night/accessibility_shortcut_type_software_gesture_tablet.xml index 51d4ba710c2..129f13db30a 100644 --- a/res/drawable-night/accessibility_shortcut_type_software_gesture_tablet.xml +++ b/res/drawable-night/accessibility_shortcut_type_software_gesture_tablet.xml @@ -1,50 +1,46 @@ + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback.xml b/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback.xml index 0b6f1e6142e..bd9bf19cae6 100644 --- a/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback.xml +++ b/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback.xml @@ -19,25 +19,25 @@ android:height="300dp" android:viewportWidth="412" android:viewportHeight="300"> - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback_tablet.xml b/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback_tablet.xml index c02d8a73805..d113fff8b72 100644 --- a/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback_tablet.xml +++ b/res/drawable-night/accessibility_shortcut_type_software_gesture_talkback_tablet.xml @@ -1,64 +1,49 @@ + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/res/drawable/illustration_accessibility_gesture_three_finger.xml b/res/drawable/accessibility_gesture_navigation_three_finger_preview.xml similarity index 100% rename from res/drawable/illustration_accessibility_gesture_three_finger.xml rename to res/drawable/accessibility_gesture_navigation_three_finger_preview.xml diff --git a/res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml b/res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml new file mode 100644 index 00000000000..fab08537886 --- /dev/null +++ b/res/drawable/accessibility_gesture_navigation_three_finger_preview_tablet.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable/illustration_accessibility_gesture_two_finger.xml b/res/drawable/accessibility_gesture_navigation_two_finger_preview.xml similarity index 100% rename from res/drawable/illustration_accessibility_gesture_two_finger.xml rename to res/drawable/accessibility_gesture_navigation_two_finger_preview.xml diff --git a/res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml b/res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml new file mode 100644 index 00000000000..f976f02efa4 --- /dev/null +++ b/res/drawable/accessibility_gesture_navigation_two_finger_preview_tablet.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable/accessibility_shortcut_type_software_gesture.xml b/res/drawable/accessibility_shortcut_type_software_gesture.xml index 514dd517898..2ded59f63c8 100644 --- a/res/drawable/accessibility_shortcut_type_software_gesture.xml +++ b/res/drawable/accessibility_shortcut_type_software_gesture.xml @@ -19,40 +19,40 @@ android:height="300dp" android:viewportWidth="412" android:viewportHeight="300"> - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/drawable/accessibility_shortcut_type_software_gesture_tablet.xml b/res/drawable/accessibility_shortcut_type_software_gesture_tablet.xml index 927c0e5b7e3..2dccf2a846d 100644 --- a/res/drawable/accessibility_shortcut_type_software_gesture_tablet.xml +++ b/res/drawable/accessibility_shortcut_type_software_gesture_tablet.xml @@ -1,50 +1,46 @@ + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/res/drawable/accessibility_shortcut_type_software_gesture_talkback.xml b/res/drawable/accessibility_shortcut_type_software_gesture_talkback.xml index 9388e66e8d5..2de804c333b 100644 --- a/res/drawable/accessibility_shortcut_type_software_gesture_talkback.xml +++ b/res/drawable/accessibility_shortcut_type_software_gesture_talkback.xml @@ -19,25 +19,25 @@ android:height="300dp" android:viewportWidth="412" android:viewportHeight="300"> - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/res/drawable/accessibility_shortcut_type_software_gesture_talkback_tablet.xml b/res/drawable/accessibility_shortcut_type_software_gesture_talkback_tablet.xml index abd2eb6296f..e122ae1fef8 100644 --- a/res/drawable/accessibility_shortcut_type_software_gesture_talkback_tablet.xml +++ b/res/drawable/accessibility_shortcut_type_software_gesture_talkback_tablet.xml @@ -1,64 +1,49 @@ + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/res/values/drawables.xml b/res/values/drawables.xml index d0bc4ceb1c7..a2d66e72cf9 100644 --- a/res/values/drawables.xml +++ b/res/values/drawables.xml @@ -14,9 +14,6 @@ limitations under the License. --> - @drawable/accessibility_shortcut_type_software_gesture_talkback - @drawable/accessibility_shortcut_type_software_gesture_talkback_tablet - @drawable/accessibility_button_preview_base @drawable/accessibility_button_preview_base_tablet @@ -26,12 +23,6 @@ @drawable/accessibility_button_preview_small_floating_menu @drawable/accessibility_button_preview_small_floating_menu_tablet - @drawable/accessibility_button_preview_three_finger - @drawable/accessibility_button_preview_three_finger_tablet - - @drawable/accessibility_button_preview_two_finger - @drawable/accessibility_button_preview_two_finger_tablet - @drawable/accessibility_button_navigation @drawable/accessibility_button_navigation_tablet @@ -50,6 +41,21 @@ @drawable/accessibility_shortcut_type_software_gesture @drawable/accessibility_shortcut_type_software_gesture_tablet + @drawable/accessibility_shortcut_type_software_gesture_talkback + @drawable/accessibility_shortcut_type_software_gesture_talkback_tablet + + @drawable/accessibility_gesture_navigation_two_finger_preview + @drawable/accessibility_gesture_navigation_two_finger_preview_tablet + + @drawable/accessibility_gesture_navigation_three_finger_preview + @drawable/accessibility_gesture_navigation_three_finger_preview_tablet + + @drawable/accessibility_button_preview_two_finger + @drawable/accessibility_button_preview_two_finger_tablet + + @drawable/accessibility_button_preview_three_finger + @drawable/accessibility_button_preview_three_finger_tablet + @drawable/accessibility_magnification_mode_fullscreen @drawable/accessibility_magnification_mode_fullscreen_tablet @@ -58,4 +64,4 @@ @drawable/accessibility_magnification_mode_window @drawable/accessibility_magnification_mode_window_tablet - \ No newline at end of file + diff --git a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java index 52e58c0f819..7e11f952464 100644 --- a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java +++ b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java @@ -177,8 +177,8 @@ public final class AccessibilityGestureNavigationTutorial { final ImageView imageView = view.findViewById(R.id.image); final int gestureSettingsImageResId = - isTouchExploreEnabled ? R.drawable.illustration_accessibility_gesture_three_finger - : R.drawable.illustration_accessibility_gesture_two_finger; + isTouchExploreEnabled ? R.drawable.a11y_gesture_navigation_three_finger_preview + : R.drawable.a11y_gesture_navigation_two_finger_preview; imageView.setImageResource(gestureSettingsImageResId); final TextView textView = view.findViewById(R.id.gesture_tutorial_message); From 20c73a9b0695bcbfac252278a34a8f98ac4f6585 Mon Sep 17 00:00:00 2001 From: Milton Wu Date: Thu, 16 Feb 2023 16:32:24 +0800 Subject: [PATCH 2/5] Attach v2 EnrollingSfpsFragment to activity 1. Attach FingerprintEnrollEnrollingSfpsFragment to FingerprintEnrollmentActivity. 2. Refine FinSensor rotation case for SFPS and RFPS Bug: 260957939 Test: atest FingerprintEnrollmentActivityTest Change-Id: Ibbeff8deb009271df044480f9f5d6c64ab6e6264 --- .../repository/AccessibilityRepository.java | 21 + ...ingerprintEnrollEnrollingRfpsFragment.java | 6 - ...ingerprintEnrollEnrollingSfpsFragment.java | 508 +++++++++--------- .../FingerprintEnrollFindRfpsFragment.java | 58 +- .../FingerprintEnrollFindSfpsFragment.java | 81 ++- .../FingerprintEnrollEnrollingViewModel.java | 19 + .../FingerprintEnrollProgressViewModel.java | 10 + 7 files changed, 407 insertions(+), 296 deletions(-) diff --git a/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java b/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java index 5353f8982d7..8777b4fd4ac 100644 --- a/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java +++ b/src/com/android/settings/biometrics2/data/repository/AccessibilityRepository.java @@ -16,8 +16,12 @@ package com.android.settings.biometrics2.data.repository; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import androidx.annotation.NonNull; + /** * This repository is used to call all APIs in {@link AccessibilityManager} */ @@ -44,4 +48,21 @@ public class AccessibilityRepository { public boolean isEnabled() { return mAccessibilityManager.isEnabled(); } + + /** + * Sends an {@link AccessibilityEvent}. + * + * @param event The event to send. + * + * @throws IllegalStateException if accessibility is not enabled. + * + * Note: 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) { + mAccessibilityManager.sendAccessibilityEvent(event); + } } diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java index 842bf423d89..74ae6fb4cce 100644 --- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java +++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingRfpsFragment.java @@ -410,12 +410,6 @@ public class FingerprintEnrollEnrollingRfpsFragment extends Fragment { } } - @Override - public void onDestroy() { - // TODO stopListenOrientationEvent(); - super.onDestroy(); - } - private void animateProgress(int progress) { if (mProgressAnim != null) { mProgressAnim.cancel(); diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java index 7d2ef9fdbb4..a91e20632e7 100644 --- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java +++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingSfpsFragment.java @@ -27,35 +27,34 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Animatable2; -import android.graphics.drawable.AnimatedVectorDrawable; -import android.graphics.drawable.Drawable; +import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; +import android.text.TextUtils; import android.util.Log; 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; import android.widget.ProgressBar; -import android.widget.TextView; +import android.widget.RelativeLayout; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; -import androidx.transition.Transition; -import androidx.transition.TransitionSet; import com.android.settings.R; +import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog; 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.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieCompositionFactory; @@ -73,8 +72,10 @@ import com.google.android.setupdesign.template.HeaderMixin; public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { private static final String TAG = FingerprintEnrollEnrollingSfpsFragment.class.getSimpleName(); + private static final boolean DEBUG = false; private static final int PROGRESS_BAR_MAX = 10000; + private static final long ANIMATION_DURATION = 250L; private static final long ICON_TOUCH_DURATION_UNTIL_DIALOG_SHOWN = 500; private static final int ICON_TOUCH_COUNT_SHOW_UNTIL_DIALOG_SHOWN = 3; @@ -86,101 +87,75 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { private static final int SFPS_STAGE_RIGHT_EDGE = 4; private FingerprintEnrollEnrollingViewModel mEnrollingViewModel; - private DeviceRotationViewModel mRotationViewModel; private FingerprintEnrollProgressViewModel mProgressViewModel; private Interpolator mFastOutSlowInInterpolator; - private Interpolator mLinearOutSlowInInterpolator; - private Interpolator mFastOutLinearInInterpolator; - private boolean mAnimationCancelled; private GlifLayout mView; private ProgressBar mProgressBar; private ObjectAnimator mProgressAnim; - private TextView mErrorText; - private FooterBarMixin mFooterBarMixin; - private AnimatedVectorDrawable mIconAnimationDrawable; - private AnimatedVectorDrawable mIconBackgroundBlinksDrawable; private LottieAnimationView mIllustrationLottie; - private boolean mShouldShowLottie; - private boolean mIsAccessibilityEnabled; private boolean mHaveShownSfpsNoAnimationLottie; private boolean mHaveShownSfpsCenterLottie; private boolean mHaveShownSfpsTipLottie; private boolean mHaveShownSfpsLeftEdgeLottie; private boolean mHaveShownSfpsRightEdgeLottie; + private ObjectAnimator mHelpAnimation; + private int mIconTouchCount; private final View.OnClickListener mOnSkipClickListener = (v) -> mEnrollingViewModel.onCancelledDueToOnSkipPressed(); + private final Observer mProgressObserver = progress -> { - // TODO - }; - private final Observer mHelpMessageObserver = helpMessage -> { - // TODO - }; - private final Observer mErrorMessageObserver = errorMessage -> { - // TODO - }; - private final Observer mAcquireObserver = isAcquiredGood -> { - // TODO - }; - private final Observer mPointerDownObserver = sensorId -> { - // TODO - }; - private final Observer mPointerUpObserver = sensorId -> { - // TODO + if (DEBUG) { + Log.d(TAG, "mProgressObserver(" + progress + ")"); + } + if (progress != null && progress.getSteps() >= 0) { + onEnrollmentProgressChange(progress); + } }; - private int mIconTouchCount; + private final Observer mHelpMessageObserver = helpMessage -> { + if (DEBUG) { + Log.d(TAG, "mHelpMessageObserver(" + helpMessage + ")"); + } + if (helpMessage != null) { + onEnrollmentHelp(helpMessage); + } + }; + + private final Observer mErrorMessageObserver = errorMessage -> { + if (DEBUG) { + Log.d(TAG, "mErrorMessageObserver(" + errorMessage + ")"); + } + if (errorMessage != null) { + onEnrollmentError(errorMessage); + } + }; @Override public void onAttach(@NonNull Context context) { final FragmentActivity activity = getActivity(); final ViewModelProvider provider = new ViewModelProvider(activity); mEnrollingViewModel = provider.get(FingerprintEnrollEnrollingViewModel.class); - mRotationViewModel = provider.get(DeviceRotationViewModel.class); mProgressViewModel = provider.get(FingerprintEnrollProgressViewModel.class); super.onAttach(context); - final TransitionSet transitionSet = (TransitionSet) getSharedElementEnterTransition(); - if (transitionSet != null) { - transitionSet.addListener(new Transition.TransitionListener() { - @Override - public void onTransitionStart(@NonNull Transition transition) { - - } - - @Override - public void onTransitionEnd(@NonNull Transition transition) { - transition.removeListener(this); - mAnimationCancelled = false; - startIconAnimation(); - } - - @Override - public void onTransitionCancel(@NonNull Transition transition) { - - } - - @Override - public void onTransitionPause(@NonNull Transition transition) { - - } - - @Override - public void onTransitionResume(@NonNull Transition transition) { - - } - }); - } + requireActivity().getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + setEnabled(false); + mEnrollingViewModel.setOnBackPressed(); + cancelEnrollment(); + } + }); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mEnrollingViewModel.restoreSavedState(savedInstanceState); - mIsAccessibilityEnabled = mEnrollingViewModel.isAccessibilityEnabled(); } @Override @@ -193,6 +168,7 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = initSfpsLayout(inflater, container); + maybeHideSfpsText(getActivity().getResources().getConfiguration()); return mView; } @@ -204,13 +180,22 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { new GlifLayoutHelper(activity, containView).setDescriptionText( getString(R.string.security_settings_fingerprint_enroll_start_message)); - mShouldShowLottie = shouldShowLottie(); // Move shouldShowLottie into updateOrientation()? + // setHelpAnimation() + final float translationX = 40; + final int duration = 550; + final RelativeLayout progressLottieLayout = containView.findViewById(R.id.progress_lottie); + mHelpAnimation = ObjectAnimator.ofFloat(progressLottieLayout, + "translationX" /* propertyName */, + 0, translationX, -1 * translationX, translationX, 0f); + mHelpAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); + mHelpAnimation.setDuration(duration); + mHelpAnimation.setAutoCancel(false); + mIllustrationLottie = containView.findViewById(R.id.illustration_lottie); - mErrorText = containView.findViewById(R.id.error_text); mProgressBar = containView.findViewById(R.id.fingerprint_progress_bar); - mFooterBarMixin = containView.getMixin(FooterBarMixin.class); - mFooterBarMixin.setSecondaryButton( + final FooterBarMixin footerBarMixin = containView.getMixin(FooterBarMixin.class); + footerBarMixin.setSecondaryButton( new FooterButton.Builder(activity) .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip) .setListener(mOnSkipClickListener) @@ -221,10 +206,6 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator( activity, android.R.interpolator.fast_out_slow_in); - mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator( - activity, android.R.interpolator.linear_out_slow_in); - mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator( - activity, android.R.interpolator.fast_out_linear_in); mProgressBar.setProgressBackgroundTintMode(PorterDuff.Mode.SRC); mProgressBar.setOnTouchListener((v, event) -> { @@ -243,7 +224,6 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { return true; }); - maybeHideSfpsText(activity.getResources().getConfiguration()); return containView; } @@ -251,46 +231,135 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { public void onStart() { super.onStart(); startEnrollment(); - updateProgress(false /* animate */); - updateTitleAndDescription(new GlifLayoutHelper(getActivity(), mView)); - if (true /* TODO mRestoring */) { - startIconAnimation(); - } + updateProgress(false /* animate */, mProgressViewModel.getProgressLiveData().getValue()); + updateTitleAndDescription(); } @Override public void onStop() { - stopIconAnimation(); - mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver); - mProgressViewModel.getHelpMessageLiveData().removeObserver(mHelpMessageObserver); - mProgressViewModel.getErrorMessageLiveData().removeObserver(mErrorMessageObserver); - mProgressViewModel.getAcquireLiveData().removeObserver(mAcquireObserver); - mProgressViewModel.getPointerDownLiveData().removeObserver(mPointerDownObserver); - mProgressViewModel.getPointerUpLiveData().removeObserver(mPointerUpObserver); - if (!getActivity().isChangingConfigurations()) { + removeEnrollmentObservers(); + if (!getActivity().isChangingConfigurations() && mProgressViewModel.isEnrolling()) { mProgressViewModel.cancelEnrollment(); } super.onStop(); } + private void removeEnrollmentObservers() { + preRemoveEnrollmentObservers(); + mProgressViewModel.getErrorMessageLiveData().removeObserver(mErrorMessageObserver); + } + + private void preRemoveEnrollmentObservers() { + mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver); + mProgressViewModel.getHelpMessageLiveData().removeObserver(mHelpMessageObserver); + } + + private void cancelEnrollment() { + preRemoveEnrollmentObservers(); + mProgressViewModel.cancelEnrollment(); + } + private void startEnrollment() { + final boolean startResult = mProgressViewModel.startEnrollment(ENROLL_ENROLL); + if (!startResult) { + Log.e(TAG, "startEnrollment(), failed"); + } mProgressViewModel.getProgressLiveData().observe(this, mProgressObserver); mProgressViewModel.getHelpMessageLiveData().observe(this, mHelpMessageObserver); mProgressViewModel.getErrorMessageLiveData().observe(this, mErrorMessageObserver); - mProgressViewModel.getAcquireLiveData().observe(this, mAcquireObserver); - mProgressViewModel.getPointerDownLiveData().observe(this, mPointerDownObserver); - mProgressViewModel.getPointerUpLiveData().observe(this, mPointerUpObserver); - mProgressViewModel.startEnrollment(ENROLL_ENROLL); } - private void updateProgress(boolean animate) { + private void configureEnrollmentStage(CharSequence description, @RawRes int lottie) { + new GlifLayoutHelper(getActivity(), mView).setDescriptionText(description); + LottieCompositionFactory.fromRawRes(getActivity(), lottie) + .addListener((c) -> { + mIllustrationLottie.setComposition(c); + mIllustrationLottie.setVisibility(View.VISIBLE); + mIllustrationLottie.playAnimation(); + }); + } + + private int getCurrentSfpsStage() { + EnrollmentProgress progressLiveData = mProgressViewModel.getProgressLiveData().getValue(); + + if (progressLiveData == null) { + return STAGE_UNKNOWN; + } + + final int progressSteps = progressLiveData.getSteps() - progressLiveData.getRemaining(); + if (progressSteps < getStageThresholdSteps(0)) { + return SFPS_STAGE_NO_ANIMATION; + } else if (progressSteps < getStageThresholdSteps(1)) { + return SFPS_STAGE_CENTER; + } else if (progressSteps < getStageThresholdSteps(2)) { + return SFPS_STAGE_FINGERTIP; + } else if (progressSteps < getStageThresholdSteps(3)) { + return SFPS_STAGE_LEFT_EDGE; + } else { + return SFPS_STAGE_RIGHT_EDGE; + } + } + + private void onEnrollmentHelp(@NonNull EnrollmentStatusMessage helpMessage) { + final CharSequence helpStr = helpMessage.getStr(); + if (!TextUtils.isEmpty(helpStr)) { + showError(helpStr); + } + } + + private void onEnrollmentError(@NonNull EnrollmentStatusMessage errorMessage) { + removeEnrollmentObservers(); + + if (mEnrollingViewModel.getOnBackPressed() + && errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { + mEnrollingViewModel.onCancelledDueToOnBackPressed(); + } else if (mEnrollingViewModel.getOnSkipPressed() + && errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { + mEnrollingViewModel.onCancelledDueToOnSkipPressed(); + } else { + final int errMsgId = errorMessage.getMsgId(); + mEnrollingViewModel.showErrorDialog( + new FingerprintEnrollEnrollingViewModel.ErrorDialogData( + getString(FingerprintErrorDialog.getErrorMessage(errMsgId)), + getString(FingerprintErrorDialog.getErrorTitle(errMsgId)), + errMsgId + )); + mProgressViewModel.cancelEnrollment(); + } + } + + 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); + } + + private void onEnrollmentProgressChange(@NonNull EnrollmentProgress progress) { + updateProgress(true /* animate */, progress); + if (mEnrollingViewModel.isAccessibilityEnabled()) { + final int percent = (int) (((float) (progress.getSteps() - progress.getRemaining()) + / (float) progress.getSteps()) * 100); + + CharSequence announcement = getString( + R.string.security_settings_sfps_enroll_progress_a11y_message, percent); + announceEnrollmentProgress(announcement); + + mIllustrationLottie.setContentDescription( + getString(R.string.security_settings_sfps_animation_a11y_label, percent) + ); + } + updateTitleAndDescription(); + } + + private void updateProgress(boolean animate, @NonNull EnrollmentProgress enrollmentProgress) { if (!mProgressViewModel.isEnrolling()) { Log.d(TAG, "Enrollment not started yet"); return; } - final EnrollmentProgress enrollmentProgress = - mProgressViewModel.getProgressLiveData().getValue(); final int progress = getProgress(enrollmentProgress); // Only clear the error when progress has been made. // TODO (b/234772728) Add tests. @@ -318,19 +387,43 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { return PROGRESS_BAR_MAX * displayProgress / (progress.getSteps() + 1); } + private void showError(CharSequence error) { + mView.setHeaderText(error); + mView.getHeaderTextView().setContentDescription(error); + new GlifLayoutHelper(getActivity(), mView).setDescriptionText(""); + if (!mHelpAnimation.isRunning()) { + mHelpAnimation.start(); + } + applySfpsErrorDynamicColors(true); + if (isResumed() && mEnrollingViewModel.isAccessibilityEnabled()) { + mEnrollingViewModel.vibrateError(getClass().getSimpleName() + "::showError"); + } + } + private void clearError() { applySfpsErrorDynamicColors(false); } + private void animateProgress(int progress) { + if (mProgressAnim != null) { + mProgressAnim.cancel(); + } + ObjectAnimator anim = ObjectAnimator.ofInt(mProgressBar, "progress", + mProgressBar.getProgress(), progress); + anim.addListener(mProgressAnimationListener); + anim.setInterpolator(mFastOutSlowInInterpolator); + anim.setDuration(ANIMATION_DURATION); + anim.start(); + mProgressAnim = anim; + } + /** * Applies dynamic colors corresponding to showing or clearing errors on the progress bar * and finger lottie for SFPS */ private void applySfpsErrorDynamicColors(boolean isError) { applyProgressBarDynamicColor(isError); - if (mIllustrationLottie != null) { - applyLottieDynamicColor(isError); - } + applyLottieDynamicColor(isError); } private void applyProgressBarDynamicColor(boolean isError) { @@ -358,36 +451,39 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { mIllustrationLottie.invalidate(); } - @Override - public void onDestroy() { - // TODO stopListenOrientationEvent(); - super.onDestroy(); - } + private int getStageThresholdSteps(int index) { + final EnrollmentProgress progressLiveData = + mProgressViewModel.getProgressLiveData().getValue(); - private void animateProgress(int progress) { - if (mProgressAnim != null) { - mProgressAnim.cancel(); + if (progressLiveData == null || progressLiveData.getSteps() == -1) { + Log.w(TAG, "getStageThresholdSteps: Enrollment not started yet"); + return 1; } - ObjectAnimator anim = ObjectAnimator.ofInt(mProgressBar, "progress", - mProgressBar.getProgress(), progress); - anim.addListener(mProgressAnimationListener); - anim.setInterpolator(mFastOutSlowInInterpolator); - anim.setDuration(250); - anim.start(); - mProgressAnim = anim; + return Math.round(progressLiveData.getSteps() + * mEnrollingViewModel.getEnrollStageThreshold(index)); } - private void updateTitleAndDescription(@NonNull GlifLayoutHelper glifLayoutHelper) { - if (mIsAccessibilityEnabled) { + private void updateTitleAndDescription() { + final GlifLayoutHelper glifLayoutHelper = new GlifLayoutHelper(getActivity(), mView); + if (mEnrollingViewModel.isAccessibilityEnabled()) { mEnrollingViewModel.clearTalkback(); glifLayoutHelper.getGlifLayout().getDescriptionTextView().setAccessibilityLiveRegion( View.ACCESSIBILITY_LIVE_REGION_POLITE); } - switch (getCurrentSfpsStage()) { + final int stage = getCurrentSfpsStage(); + if (DEBUG) { + Log.d(TAG, "updateTitleAndDescription, stage:" + stage + + ", noAnimation:" + mHaveShownSfpsNoAnimationLottie + + ", center:" + mHaveShownSfpsCenterLottie + + ", tip:" + mHaveShownSfpsTipLottie + + ", leftEdge:" + mHaveShownSfpsLeftEdgeLottie + + ", rightEdge:" + mHaveShownSfpsRightEdgeLottie); + } + switch (stage) { case SFPS_STAGE_NO_ANIMATION: glifLayoutHelper.setHeaderText( R.string.security_settings_fingerprint_enroll_repeat_title); - if (!mHaveShownSfpsNoAnimationLottie && mIllustrationLottie != null) { + if (!mHaveShownSfpsNoAnimationLottie) { mHaveShownSfpsNoAnimationLottie = true; mIllustrationLottie.setContentDescription( getString( @@ -405,7 +501,7 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { case SFPS_STAGE_CENTER: glifLayoutHelper.setHeaderText( R.string.security_settings_sfps_enroll_finger_center_title); - if (!mHaveShownSfpsCenterLottie && mIllustrationLottie != null) { + if (!mHaveShownSfpsCenterLottie) { mHaveShownSfpsCenterLottie = true; configureEnrollmentStage( getString(R.string.security_settings_sfps_enroll_start_message), @@ -417,7 +513,7 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { case SFPS_STAGE_FINGERTIP: glifLayoutHelper.setHeaderText( R.string.security_settings_sfps_enroll_fingertip_title); - if (!mHaveShownSfpsTipLottie && mIllustrationLottie != null) { + if (!mHaveShownSfpsTipLottie) { mHaveShownSfpsTipLottie = true; configureEnrollmentStage("", R.raw.sfps_lottie_tip); } @@ -426,7 +522,7 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { case SFPS_STAGE_LEFT_EDGE: glifLayoutHelper.setHeaderText( R.string.security_settings_sfps_enroll_left_edge_title); - if (!mHaveShownSfpsLeftEdgeLottie && mIllustrationLottie != null) { + if (!mHaveShownSfpsLeftEdgeLottie) { mHaveShownSfpsLeftEdgeLottie = true; configureEnrollmentStage("", R.raw.sfps_lottie_left_edge); } @@ -435,7 +531,7 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { case SFPS_STAGE_RIGHT_EDGE: glifLayoutHelper.setHeaderText( R.string.security_settings_sfps_enroll_right_edge_title); - if (!mHaveShownSfpsRightEdgeLottie && mIllustrationLottie != null) { + if (!mHaveShownSfpsRightEdgeLottie) { mHaveShownSfpsRightEdgeLottie = true; configureEnrollmentStage("", R.raw.sfps_lottie_right_edge); } @@ -460,7 +556,38 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { } } - private void maybeHideSfpsText(@android.annotation.NonNull Configuration newConfig) { + private void showIconTouchDialog() { + mIconTouchCount = 0; + //TODO EnrollingActivity should observe live data and add dialog fragment + mEnrollingViewModel.onIconTouchDialogShow(); + } + + private final Runnable mShowDialogRunnable = () -> showIconTouchDialog(); + + private final Animator.AnimatorListener mProgressAnimationListener = + new Animator.AnimatorListener() { + + @Override + public void onAnimationStart(Animator animation) { } + + @Override + public void onAnimationRepeat(Animator animation) { } + + @Override + public void onAnimationEnd(Animator animation) { + if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) { + mProgressBar.postDelayed(mDelayedFinishRunnable, ANIMATION_DURATION); + } + } + + @Override + public void onAnimationCancel(Animator animation) { } + }; + + // Give the user a chance to see progress completed before jumping to the next stage. + private final Runnable mDelayedFinishRunnable = () -> mEnrollingViewModel.onEnrollingDone(); + + private void maybeHideSfpsText(@NonNull Configuration newConfig) { final HeaderMixin headerMixin = ((GlifLayout) mView).getMixin(HeaderMixin.class); final DescriptionMixin descriptionMixin = ((GlifLayout) mView).getMixin( DescriptionMixin.class); @@ -480,137 +607,4 @@ public class FingerprintEnrollEnrollingSfpsFragment extends Fragment { } } - - private int getCurrentSfpsStage() { - EnrollmentProgress progressLiveData = mProgressViewModel.getProgressLiveData().getValue(); - - if (progressLiveData == null || progressLiveData.getSteps() == -1) { - return STAGE_UNKNOWN; - } - - final int progressSteps = progressLiveData.getSteps() - progressLiveData.getRemaining(); - if (progressSteps < getStageThresholdSteps(0)) { - return SFPS_STAGE_NO_ANIMATION; - } else if (progressSteps < getStageThresholdSteps(1)) { - return SFPS_STAGE_CENTER; - } else if (progressSteps < getStageThresholdSteps(2)) { - return SFPS_STAGE_FINGERTIP; - } else if (progressSteps < getStageThresholdSteps(3)) { - return SFPS_STAGE_LEFT_EDGE; - } else { - return SFPS_STAGE_RIGHT_EDGE; - } - } - - private int getStageThresholdSteps(int index) { - final EnrollmentProgress progressLiveData = - mProgressViewModel.getProgressLiveData().getValue(); - - if (progressLiveData == null || progressLiveData.getSteps() == -1) { - Log.w(TAG, "getStageThresholdSteps: Enrollment not started yet"); - return 1; - } - return Math.round(progressLiveData.getSteps() - * mEnrollingViewModel.getEnrollStageThreshold(index)); - } - - private void updateOrientation() { - mIllustrationLottie = mView.findViewById(R.id.illustration_lottie); - } - - private boolean shouldShowLottie() { - DisplayDensityUtils displayDensity = new DisplayDensityUtils(getContext()); - int currentDensityIndex = displayDensity.getCurrentIndexForDefaultDisplay(); - final int currentDensity = displayDensity.getDefaultDisplayDensityValues() - [currentDensityIndex]; - final int defaultDensity = displayDensity.getDefaultDensityForDefaultDisplay(); - return defaultDensity == currentDensity; - } - - - private void startIconAnimation() { - if (mIconAnimationDrawable != null) { - mIconAnimationDrawable.start(); - } - } - - private void stopIconAnimation() { - mAnimationCancelled = true; - if (mIconAnimationDrawable != null) { - mIconAnimationDrawable.stop(); - } - } - - private void showIconTouchDialog() { - mIconTouchCount = 0; - //TODO EnrollingActivity should observe live data and add dialog fragment - mEnrollingViewModel.onIconTouchDialogShow(); - } - - private void configureEnrollmentStage(CharSequence description, @RawRes int lottie) { - new GlifLayoutHelper(getActivity(), mView).setDescriptionText(description); - LottieCompositionFactory.fromRawRes(getActivity(), lottie) - .addListener((c) -> { - mIllustrationLottie.setComposition(c); - mIllustrationLottie.setVisibility(View.VISIBLE); - mIllustrationLottie.playAnimation(); - }); - } - - private final Runnable mShowDialogRunnable = new Runnable() { - @Override - public void run() { - showIconTouchDialog(); - } - }; - - private final Animator.AnimatorListener mProgressAnimationListener = - new Animator.AnimatorListener() { - - @Override - public void onAnimationStart(Animator animation) { - startIconAnimation(); - } - - @Override - public void onAnimationRepeat(Animator animation) { } - - @Override - public void onAnimationEnd(Animator animation) { - stopIconAnimation(); - - if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) { - mProgressBar.postDelayed(mDelayedFinishRunnable, 250L); - } - } - - @Override - public void onAnimationCancel(Animator animation) { } - }; - - // Give the user a chance to see progress completed before jumping to the next stage. - private final Runnable mDelayedFinishRunnable = new Runnable() { - @Override - public void run() { - /* TODO launchFinish(); */ - } - }; - - private final Animatable2.AnimationCallback mIconAnimationCallback = - new Animatable2.AnimationCallback() { - @Override - public void onAnimationEnd(Drawable d) { - if (mAnimationCancelled) { - return; - } - - // Start animation after it has ended. - mProgressBar.post(new Runnable() { - @Override - public void run() { - startIconAnimation(); - } - }); - } - }; } diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.java index 1ea26fa20a7..61f8e823fe0 100644 --- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.java +++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindRfpsFragment.java @@ -25,6 +25,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; +import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -32,6 +33,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; @@ -39,6 +41,7 @@ import com.android.settings.R; import com.android.settings.biometrics.fingerprint.FingerprintFindSensorAnimation; 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.FingerprintEnrollFindSensorViewModel; import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel; @@ -67,12 +70,23 @@ public class FingerprintEnrollFindRfpsFragment extends Fragment { private FingerprintEnrollFindSensorViewModel mViewModel; private FingerprintEnrollProgressViewModel mProgressViewModel; + private DeviceRotationViewModel mRotationViewModel; private View mView; private GlifLayout mGlifLayout; private FooterBarMixin mFooterBarMixin; private final OnClickListener mOnSkipClickListener = (v) -> mViewModel.onSkipButtonClick(); @Nullable private FingerprintFindSensorAnimation mAnimation; + @Surface.Rotation private int mLastRotation = -1; + + private final Observer mRotationObserver = rotation -> { + if (DEBUG) { + Log.d(TAG, "rotationObserver " + rotation); + } + if (rotation != null) { + onRotationChanged(rotation); + } + }; private final Observer mProgressObserver = progress -> { if (DEBUG) { @@ -85,15 +99,10 @@ public class FingerprintEnrollFindRfpsFragment extends Fragment { private final Observer mLastCancelMessageObserver = errorMessage -> { if (DEBUG) { - Log.d(TAG, "mErrorMessageObserver(" + errorMessage + ")"); + Log.d(TAG, "mLastCancelMessageObserver(" + errorMessage + ")"); } if (errorMessage != null) { - if (errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { - mProgressViewModel.clearProgressLiveData(); - mViewModel.onStartButtonClick(); - } else { - Log.e(TAG, "mErrorMessageObserver(" + errorMessage + ")"); - } + onLastCancelMessage(errorMessage); } }; @@ -144,6 +153,10 @@ public class FingerprintEnrollFindRfpsFragment extends Fragment { @Override public void onResume() { + final LiveData rotationLiveData = mRotationViewModel.getLiveData(); + mLastRotation = rotationLiveData.getValue(); + rotationLiveData.observe(this, mRotationObserver); + if (mAnimation != null) { if (DEBUG) { Log.d(TAG, "onResume(), start animation"); @@ -198,15 +211,39 @@ public class FingerprintEnrollFindRfpsFragment extends Fragment { return; } + if (waitForLastCancelErrMsg) { + mProgressViewModel.clearErrorMessageLiveData(); // Prevent got previous error message + mProgressViewModel.getErrorMessageLiveData().observe(this, + mLastCancelMessageObserver); + } + mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver); final boolean cancelResult = mProgressViewModel.cancelEnrollment(); if (!cancelResult) { Log.e(TAG, "stopLookingForFingerprint(), failed to cancel enrollment"); } + } - if (waitForLastCancelErrMsg) { - mProgressViewModel.getErrorMessageLiveData().observe(this, - mLastCancelMessageObserver); + private void onRotationChanged(@Surface.Rotation int newRotation) { + if (DEBUG) { + Log.d(TAG, "onRotationChanged() from " + mLastRotation + " to " + newRotation); + } + if (newRotation % 2 != mLastRotation % 2) { + // Fragment is going to be recreated, just stopLookingForFingerprint() here. + stopLookingForFingerprint(true); + } + } + + private void onLastCancelMessage(@NonNull EnrollmentStatusMessage errorMessage) { + if (errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { + final EnrollmentProgress progress = mProgressViewModel.getProgressLiveData().getValue(); + mProgressViewModel.clearProgressLiveData(); + mProgressViewModel.getErrorMessageLiveData().removeObserver(mLastCancelMessageObserver); + if (progress != null && !progress.isInitialStep()) { + mViewModel.onStartButtonClick(); + } + } else { + Log.e(TAG, "mErrorMessageObserver(" + errorMessage + ")"); } } @@ -227,6 +264,7 @@ public class FingerprintEnrollFindRfpsFragment extends Fragment { final ViewModelProvider provider = new ViewModelProvider(activity); mViewModel = provider.get(FingerprintEnrollFindSensorViewModel.class); mProgressViewModel = provider.get(FingerprintEnrollProgressViewModel.class); + mRotationViewModel = provider.get(DeviceRotationViewModel.class); super.onAttach(context); } } diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.java index c363f04e1e5..75207cad630 100644 --- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.java +++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.java @@ -20,6 +20,7 @@ import static android.hardware.fingerprint.FingerprintManager.ENROLL_FIND_SENSOR import android.app.Activity; import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -39,6 +40,7 @@ import androidx.lifecycle.ViewModelProvider; import com.android.settings.R; import com.android.settings.biometrics2.ui.model.EnrollmentProgress; +import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage; import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel; import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel; import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel; @@ -75,30 +77,36 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { private DeviceRotationViewModel mRotationViewModel; private DeviceFoldedViewModel mFoldedViewModel; + private GlifLayout mView; + private FooterBarMixin mFooterBarMixin; + private final OnClickListener mOnSkipClickListener = (v) -> mViewModel.onSkipButtonClick(); + private LottieAnimationView mIllustrationLottie; + @Surface.Rotation private int mAnimationRotation = -1; + private final Observer mRotationObserver = rotation -> { if (DEBUG) { Log.d(TAG, "rotationObserver " + rotation); } - if (rotation == null) { - return; + if (rotation != null) { + onRotationChanged(rotation); } - onRotationChanged(rotation); }; - @Surface.Rotation private int mAnimationRotation = -1; - - private View mView; - private GlifLayout mGlifLayout; - private FooterBarMixin mFooterBarMixin; - private final OnClickListener mOnSkipClickListener = (v) -> mViewModel.onSkipButtonClick(); - private LottieAnimationView mIllustrationLottie; - private final Observer mProgressObserver = progress -> { if (DEBUG) { Log.d(TAG, "mProgressObserver(" + progress + ")"); } if (progress != null && !progress.isInitialStep()) { - mViewModel.onStartButtonClick(); + stopLookingForFingerprint(true); + } + }; + + private final Observer mLastCancelMessageObserver = errorMessage -> { + if (DEBUG) { + Log.d(TAG, "mLastCancelMessageObserver(" + errorMessage + ")"); + } + if (errorMessage != null) { + onLastCancelMessage(errorMessage); } }; @@ -107,10 +115,10 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { final Context context = inflater.getContext(); - mView = inflater.inflate(R.layout.sfps_enroll_find_sensor_layout, container, false); - mGlifLayout = mView.findViewById(R.id.setup_wizard_layout); + mView = (GlifLayout) inflater.inflate(R.layout.sfps_enroll_find_sensor_layout, container, + false); mIllustrationLottie = mView.findViewById(R.id.illustration_lottie); - mFooterBarMixin = mGlifLayout.getMixin(FooterBarMixin.class); + mFooterBarMixin = mView.getMixin(FooterBarMixin.class); mFooterBarMixin.setSecondaryButton( new FooterButton.Builder(context) .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip) @@ -125,7 +133,7 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); final Activity activity = getActivity(); - final GlifLayoutHelper glifLayoutHelper = new GlifLayoutHelper(activity, mGlifLayout); + final GlifLayoutHelper glifLayoutHelper = new GlifLayoutHelper(activity, mView); glifLayoutHelper.setHeaderText(R.string.security_settings_sfps_enroll_find_sensor_title); glifLayoutHelper.setDescriptionText( getText(R.string.security_settings_sfps_enroll_find_sensor_message)); @@ -136,10 +144,13 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { public void onStart() { super.onStart(); + final boolean isEnrolling = mProgressViewModel.isEnrolling(); if (DEBUG) { - Log.d(TAG, "onStart(), start looking for fingerprint"); + Log.d(TAG, "onStart(), isEnrolling:" + isEnrolling); + } + if (!isEnrolling) { + startLookingForFingerprint(); } - startLookingForFingerprint(); } @Override @@ -159,10 +170,13 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { @Override public void onStop() { super.onStop(); + final boolean isEnrolling = mProgressViewModel.isEnrolling(); if (DEBUG) { - Log.d(TAG, "onStop(), stop looking for fingerprint"); + Log.d(TAG, "onStop(), isEnrolling:" + isEnrolling); + } + if (isEnrolling) { + stopLookingForFingerprint(false); } - stopLookingForFingerprint(); } private void startLookingForFingerprint() { @@ -180,13 +194,19 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { } } - private void stopLookingForFingerprint() { + private void stopLookingForFingerprint(boolean waitForLastCancelErrMsg) { if (!mProgressViewModel.isEnrolling()) { Log.d(TAG, "stopLookingForFingerprint(), failed because isEnrolling is false before" + " stopping"); return; } + if (waitForLastCancelErrMsg) { + mProgressViewModel.clearErrorMessageLiveData(); // Prevent got previous error message + mProgressViewModel.getErrorMessageLiveData().observe(this, + mLastCancelMessageObserver); + } + mProgressViewModel.getProgressLiveData().removeObserver(mProgressObserver); final boolean cancelResult = mProgressViewModel.cancelEnrollment(); if (!cancelResult) { @@ -199,10 +219,25 @@ public class FingerprintEnrollFindSfpsFragment extends Fragment { Log.d(TAG, "onRotationChanged() from " + mAnimationRotation + " to " + newRotation); } if ((newRotation + 2) % 4 == mAnimationRotation) { + // Fragment not changed, we just need to play correct rotation animation playLottieAnimation(newRotation); + } else if (newRotation % 2 != mAnimationRotation % 2) { + // Fragment is going to be recreated, just stopLookingForFingerprint() here. + stopLookingForFingerprint(true); + } + } + + private void onLastCancelMessage(@NonNull EnrollmentStatusMessage errorMessage) { + if (errorMessage.getMsgId() == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { + final EnrollmentProgress progress = mProgressViewModel.getProgressLiveData().getValue(); + mProgressViewModel.clearProgressLiveData(); + mProgressViewModel.getErrorMessageLiveData().removeObserver(mLastCancelMessageObserver); + if (progress != null && !progress.isInitialStep()) { + mViewModel.onStartButtonClick(); + } + } else { + Log.e(TAG, "mErrorMessageObserver(" + errorMessage + ")"); } - // Fragment will be re-created if it's changed between landscape and portrait, so no need to - // handle other cases. } private void playLottieAnimation(@Surface.Rotation int rotation) { diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java index bf7b0acb7b5..6a9adb74d3f 100644 --- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java +++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java @@ -23,6 +23,8 @@ 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; import androidx.annotation.NonNull; @@ -278,6 +280,23 @@ public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel { return mAccessibilityRepository.isEnabled(); } + /** + * Sends an {@link AccessibilityEvent}. + * + * @param event The event to send. + * + * @throws IllegalStateException if accessibility is not enabled. + * + * Note: 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); + } + /** * Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the * caller to specify the vibration is owned by someone else and set a reason for vibration. diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java index eebbc4270e9..2a918f5eb8a 100644 --- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java +++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java @@ -92,6 +92,9 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { @Override public void onEnrollmentError(int errMsgId, CharSequence errString) { + if (DEBUG) { + Log.d(TAG, "onEnrollmentError(" + errMsgId + ", " + errString + ")"); + } mErrorMessageLiveData.postValue(new EnrollmentStatusMessage(errMsgId, errString)); } @@ -146,6 +149,13 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { mErrorMessageLiveData.setValue(null); } + /** + * clear error message + */ + public void clearErrorMessageLiveData() { + mErrorMessageLiveData.setValue(null); + } + public LiveData getProgressLiveData() { return mProgressLiveData; } From 67fd7d8f6f795c358691714eb3b76d1aad88a4ea Mon Sep 17 00:00:00 2001 From: Zaiyue Xue Date: Mon, 20 Feb 2023 11:36:55 +0800 Subject: [PATCH 3/5] Move the same-name-different-product configs from res folder to res-product folder This could unblock the build in go/settings-studio. Bug: 269974284 Fix: 269974284 Test: presubmit Change-Id: I962ce24c827d6412af2b861753ae57bd17a27de2 --- res-product/values/config.xml | 33 +++++++++++++++++++++++ {res => res-product}/values/drawables.xml | 0 res/values/config.xml | 16 ----------- 3 files changed, 33 insertions(+), 16 deletions(-) create mode 100755 res-product/values/config.xml rename {res => res-product}/values/drawables.xml (100%) diff --git a/res-product/values/config.xml b/res-product/values/config.xml new file mode 100755 index 00000000000..39fbdffb0e1 --- /dev/null +++ b/res-product/values/config.xml @@ -0,0 +1,33 @@ + + + + + + @raw/accessibility_timeout_banner + @raw/accessibility_timeout_banner_tablet + + @raw/accessibility_shortcut_type_triple_tap + @raw/accessibility_shortcut_type_triple_tap_tablet + + @raw/accessibility_color_inversion_banner + @raw/accessibility_color_inversion_banner_tablet + + @raw/accessibility_magnification_banner + @raw/accessibility_magnification_banner_tablet + + @raw/extra_dim_banner + @raw/extra_dim_banner_tablet + diff --git a/res/values/drawables.xml b/res-product/values/drawables.xml similarity index 100% rename from res/values/drawables.xml rename to res-product/values/drawables.xml diff --git a/res/values/config.xml b/res/values/config.xml index e27f25734f6..07f6432ed3d 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -695,20 +695,4 @@ false - - - @raw/accessibility_timeout_banner - @raw/accessibility_timeout_banner_tablet - - @raw/accessibility_shortcut_type_triple_tap - @raw/accessibility_shortcut_type_triple_tap_tablet - - @raw/accessibility_color_inversion_banner - @raw/accessibility_color_inversion_banner_tablet - - @raw/accessibility_magnification_banner - @raw/accessibility_magnification_banner_tablet - - @raw/extra_dim_banner - @raw/extra_dim_banner_tablet From 0e48c55a2a7e0e1c25ebf24527a5ef7e1c2ac668 Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Wed, 15 Feb 2023 08:23:58 +0000 Subject: [PATCH 4/5] Fixes fail test cases in AccessibilitySettingsTest AccessibilityHearingAidPreferenceController can't be instantiated correctly in tests with the lack of LocalBluetoothManager. This causes null pointer exception when AccessibilityHearingAidPreferenceController.setFragmentManager() is called in AccessibilitySettings.onAttach(). Solution: Mocks the LocalBluetoothManager for tests to successfully instantiate AccessibilityHearingAidPreferenceController to prevent null pointer exception from happening. Bug: 269407238 Test: atest AccessibilitySettingsTest Change-Id: Ibcfffa10b46fd6e85c1b74b03343e5ee0e8843b3 --- .../settings/accessibility/AccessibilitySettingsTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java index 695e86b3604..16d14837b06 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java @@ -56,9 +56,11 @@ import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.content.PackageMonitor; import com.android.settings.R; import com.android.settings.testutils.XmlTestUtils; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.RestrictedPreference; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexableRaw; @@ -85,6 +87,7 @@ import java.util.List; /** Test for {@link AccessibilitySettings}. */ @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothUtils.class}) public class AccessibilitySettingsTest { private static final String PACKAGE_NAME = "com.android.test"; private static final String CLASS_NAME = PACKAGE_NAME + ".test_a11y_service"; @@ -116,6 +119,8 @@ public class AccessibilitySettingsTest { private ShadowAccessibilityManager mShadowAccessibilityManager; @Mock private AppOpsManager mAppOpsManager; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; private Lifecycle mLifecycle; @@ -134,6 +139,7 @@ public class AccessibilitySettingsTest { anyInt(), anyString())).thenReturn(AppOpsManager.MODE_ALLOWED); mLifecycle = new Lifecycle(() -> mLifecycle); when(mFragment.getSettingsLifecycle()).thenReturn(mLifecycle); + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; } @Test From 5cb2a1fa8d8f578c8039d0415ff1a9a514185a78 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Sat, 18 Feb 2023 22:56:56 +0800 Subject: [PATCH 5/5] Put mobile NetworkTemplate in Intent for SearchResultTeampoline BillingCycleSettings and Settings.ACTION_MOBILE_DATA_USAGE needs mobile NetworkTemplate to work correctly. Bug: 268411305 Test: manual Change-Id: I7e2eafff39f1bffeb8adbe4d7c3567b7a4ea7dda --- .../datausage/BillingCycleSettings.java | 14 +++++++++++++ .../settings/datausage/DataUsageList.java | 9 ++++++++ .../settings/datausage/DataUsageUtils.java | 21 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/com/android/settings/datausage/BillingCycleSettings.java b/src/com/android/settings/datausage/BillingCycleSettings.java index 395d1c724dd..3047d73dddf 100644 --- a/src/com/android/settings/datausage/BillingCycleSettings.java +++ b/src/com/android/settings/datausage/BillingCycleSettings.java @@ -27,6 +27,7 @@ import android.icu.util.MeasureUnit; import android.net.NetworkPolicy; import android.net.NetworkTemplate; import android.os.Bundle; +import android.provider.Settings; import android.text.method.NumberKeyListener; import android.util.Log; import android.view.LayoutInflater; @@ -54,6 +55,7 @@ import com.android.settingslib.search.SearchIndexable; import java.text.NumberFormat; import java.text.ParseException; +import java.util.Optional; import java.util.TimeZone; @SearchIndexable @@ -115,6 +117,18 @@ public class BillingCycleSettings extends DataUsageBaseFragment implements Bundle args = getArguments(); mNetworkTemplate = args.getParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE); + if (mNetworkTemplate == null && getIntent() != null) { + mNetworkTemplate = getIntent().getParcelableExtra(Settings.EXTRA_NETWORK_TEMPLATE); + } + + if (mNetworkTemplate == null) { + Optional mobileNetworkTemplateFromSim = + DataUsageUtils.getMobileNetworkTemplateFromSubId(context, getIntent()); + if (mobileNetworkTemplateFromSim.isPresent()) { + mNetworkTemplate = mobileNetworkTemplateFromSim.get(); + } + } + if (mNetworkTemplate == null) { mNetworkTemplate = DataUsageUtils.getDefaultTemplate(context, DataUsageUtils.getDefaultSubscriptionId(context)); diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java index 1499dede384..68751e5a2df 100644 --- a/src/com/android/settings/datausage/DataUsageList.java +++ b/src/com/android/settings/datausage/DataUsageList.java @@ -69,6 +69,7 @@ import com.android.settingslib.net.UidDetailProvider; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * Panel showing data usage history across various networks, including options @@ -266,6 +267,14 @@ public class DataUsageList extends DataUsageBaseFragment mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); mTemplate = intent.getParcelableExtra(Settings.EXTRA_NETWORK_TEMPLATE); + + if (mTemplate == null) { + Optional mobileNetworkTemplateFromSim = + DataUsageUtils.getMobileNetworkTemplateFromSubId(getContext(), getIntent()); + if (mobileNetworkTemplateFromSim.isPresent()) { + mTemplate = mobileNetworkTemplateFromSim.get(); + } + } } } diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java index 9fec27e0bef..cce7ca1fa8f 100644 --- a/src/com/android/settings/datausage/DataUsageUtils.java +++ b/src/com/android/settings/datausage/DataUsageUtils.java @@ -22,11 +22,13 @@ import static android.telephony.TelephonyManager.SIM_STATE_READY; import android.app.usage.NetworkStats.Bucket; import android.app.usage.NetworkStatsManager; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkTemplate; import android.os.RemoteException; import android.os.SystemProperties; +import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -39,6 +41,7 @@ import com.android.settings.datausage.lib.DataUsageLib; import com.android.settings.network.ProxySubscriptionManager; import java.util.List; +import java.util.Optional; /** * Utility methods for data usage classes. @@ -193,4 +196,22 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU } } + /** + * Returns a mobile NetworkTemplate if EXTRA_SUB_ID of the Intent is available and the subId + * is valid & hasMobileData. Otherwise, returns empty data. + */ + public static Optional getMobileNetworkTemplateFromSubId(Context context, + Intent intent) { + if (intent == null || !intent.hasExtra(Settings.EXTRA_SUB_ID)) { + return Optional.empty(); + } + + int subId = intent.getIntExtra(Settings.EXTRA_SUB_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (SubscriptionManager.isValidSubscriptionId(subId) && hasMobileData(context)) { + return Optional.of(DataUsageLib.getMobileTemplate(context, subId)); + } + + return Optional.empty(); + } }