Added lottie animations for udfps side/tip

Bug: 209807883
Test: Verified animations show for multiple devices.
Change-Id: Ic63a0eca226309b92aa64cb4f80791ef179b8154
This commit is contained in:
Joshua Mccloskey
2021-12-09 17:47:11 -08:00
parent f280687ac7
commit 0902b44744
7 changed files with 134 additions and 17 deletions

View File

@@ -17,6 +17,7 @@
<com.google.android.setupdesign.GlifLayout <com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android" 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:id="@+id/setup_wizard_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -30,6 +31,35 @@
android:clipChildren="false" android:clipChildren="false"
android:orientation="vertical"> android:orientation="vertical">
<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 <TextView
android:id="@+id/error_text" android:id="@+id/error_text"
style="@style/TextAppearance.ErrorText" style="@style/TextAppearance.ErrorText"
@@ -40,5 +70,6 @@
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:visibility="invisible" /> android:visibility="invisible" />
</LinearLayout> </LinearLayout>
</LinearLayout>
</com.google.android.setupdesign.GlifLayout> </com.google.android.setupdesign.GlifLayout>

View File

View File

View File

@@ -212,6 +212,7 @@
fingerprint_finish_max_size = fingerprint_progress_bar_max_size fingerprint_finish_max_size = fingerprint_progress_bar_max_size
+ (fingerprint_enrolling_content_margin_vertical x 2) --> + (fingerprint_enrolling_content_margin_vertical x 2) -->
<dimen name="fingerprint_finish_max_size">288dp</dimen> <dimen name="fingerprint_finish_max_size">288dp</dimen>
<dimen name="udfps_lottie_translate_y">0dp</dimen>
<!-- Face --> <!-- Face -->
<item name="face_preview_translate_y" format="float" type="dimen">0</item> <item name="face_preview_translate_y" format="float" type="dimen">0</item>

View File

@@ -1113,6 +1113,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> <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] --> <!-- Button text to skip enrollment of fingerprint [CHAR LIMIT=40] -->
<string name="security_settings_fingerprint_enroll_enrolling_skip">Do it later</string> <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] --> <!-- 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> <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] --> <!-- Content of the dialog shown when the user tries to skip fingerprint setup, asking them to confirm the action [CHAR LIMIT=NONE] -->

View File

@@ -289,4 +289,14 @@ public class BiometricUtils {
} }
return false; 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;
}
} }

View File

@@ -19,11 +19,13 @@ package com.android.settings.biometrics.fingerprint;
import android.animation.Animator; import android.animation.Animator;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.Dialog; import android.app.Dialog;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.drawable.Animatable2; import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -54,7 +56,9 @@ import com.android.settings.biometrics.BiometricEnrollSidecar;
import com.android.settings.biometrics.BiometricUtils; import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.BiometricsEnrollEnrolling; import com.android.settings.biometrics.BiometricsEnrollEnrolling;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 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.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton; import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -126,6 +130,10 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
private boolean mIsSetupWizard; private boolean mIsSetupWizard;
private AccessibilityManager mAccessibilityManager; private AccessibilityManager mAccessibilityManager;
private boolean mIsAccessibilityEnabled; private boolean mIsAccessibilityEnabled;
private LottieAnimationView mIllustrationLottie;
private boolean mHaveShownUdfpsTipLottie;
private boolean mHaveShownUdfpsSideLottie;
private boolean mShouldShowLottie;
private OrientationEventListener mOrientationEventListener; private OrientationEventListener mOrientationEventListener;
private int mPreviousRotation = 0; private int mPreviousRotation = 0;
@@ -163,6 +171,20 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title); 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;
// 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());
updateOrientation((isLandscape
? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT));
mErrorText = findViewById(R.id.error_text); mErrorText = findViewById(R.id.error_text);
mProgressBar = findViewById(R.id.fingerprint_progress_bar); mProgressBar = findViewById(R.id.fingerprint_progress_bar);
mVibrator = getSystemService(Vibrator.class); mVibrator = getSystemService(Vibrator.class);
@@ -339,21 +361,35 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
case STAGE_FINGERTIP: case STAGE_FINGERTIP:
setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title); setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title);
if (isStageHalfCompleted()) { if (!mHaveShownUdfpsTipLottie && mIllustrationLottie != null) {
setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_title); mHaveShownUdfpsTipLottie = true;
} else {
setDescriptionText(""); 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));
} }
break; break;
case STAGE_EDGES: case STAGE_EDGES:
setHeaderText(R.string.security_settings_udfps_enroll_edge_title); setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
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()) { if (isStageHalfCompleted()) {
setDescriptionText( setDescriptionText(
R.string.security_settings_fingerprint_enroll_repeat_message); R.string.security_settings_fingerprint_enroll_repeat_message);
} else { } else {
setDescriptionText(R.string.security_settings_udfps_enroll_edge_message); setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);
} }
}
break; break;
case STAGE_UNKNOWN: case STAGE_UNKNOWN:
@@ -634,6 +670,41 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
return SettingsEnums.FINGERPRINT_ENROLLING; 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) {
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 { public static class IconTouchDialog extends InstrumentedDialogFragment {
@Override @Override