Merge "Added lottie animations for udfps side/tip" into sc-v2-dev
diff --git a/res/layout/udfps_enroll_enrolling.xml b/res/layout/udfps_enroll_enrolling.xml
index 67c127b..e933753 100644
--- a/res/layout/udfps_enroll_enrolling.xml
+++ b/res/layout/udfps_enroll_enrolling.xml
@@ -17,6 +17,7 @@
 
 <com.google.android.setupdesign.GlifLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/setup_wizard_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
@@ -30,15 +31,45 @@
         android:clipChildren="false"
         android:orientation="vertical">
 
-        <TextView
-            android:id="@+id/error_text"
-            style="@style/TextAppearance.ErrorText"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal|bottom"
-            android:accessibilityLiveRegion="polite"
-            android:gravity="center_horizontal"
-            android:visibility="invisible" />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:gravity="center|bottom"
+            android:orientation="vertical">
+
+          <FrameLayout
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:clipChildren="false"
+              android:clipToPadding="false"
+              android:layout_gravity="center_horizontal|bottom">
+
+              <!-- Animation res MUST be set in code -->
+              <com.airbnb.lottie.LottieAnimationView
+                  android:id="@+id/illustration_lottie"
+                  android:layout_width="match_parent"
+                  android:layout_height="200dp"
+                  android:layout_marginTop="@dimen/udfps_lottie_translate_y"
+                  android:scaleType="centerInside"
+                  android:visibility="gone"
+                  app:lottie_autoPlay="true"
+                  app:lottie_loop="true"
+                  android:clipChildren="false"
+                  android:clipToPadding="false"
+                  app:lottie_speed=".85" />
+          </FrameLayout>
+
+          <TextView
+              android:id="@+id/error_text"
+              style="@style/TextAppearance.ErrorText"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_gravity="center_horizontal|bottom"
+              android:accessibilityLiveRegion="polite"
+              android:gravity="center_horizontal"
+              android:visibility="invisible" />
+      </LinearLayout>
     </LinearLayout>
 
 </com.google.android.setupdesign.GlifLayout>
diff --git a/res/raw/udfps_edge_hint_lottie.json b/res/raw/udfps_edge_hint_lottie.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/res/raw/udfps_edge_hint_lottie.json
diff --git a/res/raw/udfps_tip_hint_lottie.json b/res/raw/udfps_tip_hint_lottie.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/res/raw/udfps_tip_hint_lottie.json
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 2468db6..a5753df 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -235,6 +235,7 @@
          fingerprint_finish_max_size = fingerprint_progress_bar_max_size
                   + (fingerprint_enrolling_content_margin_vertical x 2) -->
     <dimen name="fingerprint_finish_max_size">288dp</dimen>
+    <dimen name="udfps_lottie_translate_y">0dp</dimen>
 
     <!-- Face -->
     <item name="face_preview_translate_y" format="float" type="dimen">0</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 300b3a4..f7be31c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1084,6 +1084,10 @@
     <string name="security_settings_fingerprint_enroll_finish_message">Now you can use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps</string>
     <!-- Button text to skip enrollment of fingerprint [CHAR LIMIT=40] -->
     <string name="security_settings_fingerprint_enroll_enrolling_skip">Do it later</string>
+    <!-- Accessibility message for fingerprint enrollment asking the user to place the tip of their finger on the fingerprint sensor [CHAR LIMIT=NONE] -->
+    <string name="security_settings_udfps_tip_fingerprint_help">Lift, then touch again</string>
+    <!-- Accessibility message for fingerprint enrollment asking the user to place the sides of their finger on the fingerprint sensor [CHAR LIMIT=NONE] -->
+    <string name="security_settings_udfps_side_fingerprint_help">Place the side of your fingerprint on the sensor and hold, then switch to the other side</string>
     <!-- Title of the dialog shown when the user tries to skip fingerprint setup, asking them to confirm the action [CHAR LIMIT=40] -->
     <string name="setup_fingerprint_enroll_enrolling_skip_title">Skip fingerprint setup?</string>
     <!-- Content of the dialog shown when the user tries to skip fingerprint setup, asking them to confirm the action [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/biometrics/BiometricUtils.java b/src/com/android/settings/biometrics/BiometricUtils.java
index 5ee7880..febe3c6 100644
--- a/src/com/android/settings/biometrics/BiometricUtils.java
+++ b/src/com/android/settings/biometrics/BiometricUtils.java
@@ -289,4 +289,14 @@
         }
         return false;
     }
+
+    /**
+     * Returns {@code true} if the screen is going into a landscape mode and the angle is equal to
+     * 90.
+     * @param context Context that we use to get the display this context is associated with
+     * @return True if the angle of the rotation is equal to 90.
+     */
+    public static boolean isLandscape(@NonNull Context context) {
+        return context.getDisplay().getRotation() == Surface.ROTATION_90;
+    }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index c2bcee3..84519f8 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -19,11 +19,13 @@
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
@@ -54,7 +56,9 @@
 import com.android.settings.biometrics.BiometricUtils;
 import com.android.settings.biometrics.BiometricsEnrollEnrolling;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settingslib.display.DisplayDensityUtils;
 
+import com.airbnb.lottie.LottieAnimationView;
 import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupcompat.template.FooterButton;
 import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -126,10 +130,16 @@
     private boolean mIsSetupWizard;
     private AccessibilityManager mAccessibilityManager;
     private boolean mIsAccessibilityEnabled;
+    private LottieAnimationView mIllustrationLottie;
+    private boolean mHaveShownUdfpsTipLottie;
+    private boolean mHaveShownUdfpsSideLottie;
+    private boolean mShouldShowLottie;
 
     private OrientationEventListener mOrientationEventListener;
     private int mPreviousRotation = 0;
 
+    private boolean mShowingNewUdfpsEnroll = false;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -163,6 +173,25 @@
             setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
         }
 
+        DisplayDensityUtils displayDensity =
+                new DisplayDensityUtils(getApplicationContext());
+        int currentDensityIndex = displayDensity.getCurrentIndex();
+        final int currentDensity = displayDensity.getValues()[currentDensityIndex];
+        final int defaultDensity = displayDensity.getDefaultDensity();
+        mShouldShowLottie = defaultDensity == currentDensity;
+
+        mShowingNewUdfpsEnroll = getApplicationContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_udfpsSupportsNewUi);
+        // Only show the lottie if the current display density is the default density.
+        // Otherwise, the lottie will overlap with the settings header text.
+        boolean isLandscape = BiometricUtils.isReverseLandscape(getApplicationContext())
+                || BiometricUtils.isLandscape(getApplicationContext());
+
+        if (mShowingNewUdfpsEnroll) {
+            updateOrientation((isLandscape
+                    ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT));
+        }
+
         mErrorText = findViewById(R.id.error_text);
         mProgressBar = findViewById(R.id.fingerprint_progress_bar);
         mVibrator = getSystemService(Vibrator.class);
@@ -339,20 +368,53 @@
 
             case STAGE_FINGERTIP:
                 setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title);
-                if (isStageHalfCompleted()) {
-                    setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_title);
+                if (mShowingNewUdfpsEnroll) {
+                    if (!mHaveShownUdfpsTipLottie && mIllustrationLottie != null) {
+                        mHaveShownUdfpsTipLottie = true;
+                        setDescriptionText("");
+                        mIllustrationLottie.setAnimation(R.raw.udfps_tip_hint_lottie);
+                        mIllustrationLottie.setVisibility(View.VISIBLE);
+                        mIllustrationLottie.playAnimation();
+                        mIllustrationLottie.setContentDescription(
+                                getString(R.string.security_settings_udfps_tip_fingerprint_help));
+                    }
                 } else {
-                    setDescriptionText("");
+                    if (isStageHalfCompleted()) {
+                        setDescriptionText(
+                                R.string.security_settings_fingerprint_enroll_repeat_title);
+                    } else {
+                        setDescriptionText("");
+                    }
                 }
                 break;
 
             case STAGE_EDGES:
                 setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
-                if (isStageHalfCompleted()) {
-                    setDescriptionText(
-                            R.string.security_settings_fingerprint_enroll_repeat_message);
+                if (mShowingNewUdfpsEnroll) {
+                    if (!mHaveShownUdfpsSideLottie && mIllustrationLottie != null) {
+                        mHaveShownUdfpsSideLottie = true;
+                        setDescriptionText("");
+                        mIllustrationLottie.setAnimation(R.raw.udfps_edge_hint_lottie);
+                        mIllustrationLottie.setVisibility(View.VISIBLE);
+                        mIllustrationLottie.playAnimation();
+                        mIllustrationLottie.setContentDescription(
+                                getString(R.string.security_settings_udfps_side_fingerprint_help));
+                    } else if (mIllustrationLottie == null) {
+                        if (isStageHalfCompleted()) {
+                            setDescriptionText(
+                                    R.string.security_settings_fingerprint_enroll_repeat_message);
+                        } else {
+                            setDescriptionText(
+                                    R.string.security_settings_udfps_enroll_edge_message);
+                        }
+                    }
                 } else {
-                    setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);
+                    if (isStageHalfCompleted()) {
+                        setDescriptionText(
+                                R.string.security_settings_fingerprint_enroll_repeat_message);
+                    } else {
+                        setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);
+                    }
                 }
                 break;
 
@@ -634,6 +696,45 @@
         return SettingsEnums.FINGERPRINT_ENROLLING;
     }
 
+    private void updateOrientation(int orientation) {
+        switch(orientation) {
+            case Configuration.ORIENTATION_LANDSCAPE: {
+                mIllustrationLottie = null;
+                break;
+            }
+            case Configuration.ORIENTATION_PORTRAIT: {
+                if (mShouldShowLottie) {
+                    mIllustrationLottie = findViewById(R.id.illustration_lottie);
+                }
+                break;
+            }
+            default:
+                Log.e(TAG, "Error unhandled configuration change");
+                break;
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        if (!mShowingNewUdfpsEnroll) {
+            return;
+        }
+
+        switch(newConfig.orientation) {
+            case Configuration.ORIENTATION_LANDSCAPE: {
+                updateOrientation(Configuration.ORIENTATION_LANDSCAPE);
+                break;
+            }
+            case Configuration.ORIENTATION_PORTRAIT: {
+                updateOrientation(Configuration.ORIENTATION_PORTRAIT);
+                break;
+            }
+            default:
+                Log.e(TAG, "Error unhandled configuration change");
+                break;
+        }
+    }
+
     public static class IconTouchDialog extends InstrumentedDialogFragment {
 
         @Override