Animations/success state for external confirm device credentials (2/2)
Bug: 20929186
Change-Id: I4489dd37f1148fb03315ec337a546eee04660cb5
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8728ab4..56faa51 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1407,7 +1407,7 @@
android:theme="@style/Theme.ConfirmDeviceCredentials"/>
<activity android:name="ConfirmLockPassword"
- android:windowSoftInputMode="adjustResize"
+ android:windowSoftInputMode="stateHidden|adjustResize"
android:theme="@style/Theme.ConfirmDeviceCredentials"/>
<activity android:name=".fingerprint.FingerprintSettings" android:exported="false"/>
diff --git a/res/anim/confirm_credential_close_enter.xml b/res/anim/confirm_credential_close_enter.xml
new file mode 100644
index 0000000..fcc3241
--- /dev/null
+++ b/res/anim/confirm_credential_close_enter.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@*android:interpolator/decelerate_quart"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="200"/>
+ <translate android:fromYDelta="8%" android:toYDelta="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@*android:interpolator/decelerate_quint"
+ android:duration="350"/>
+</set>
diff --git a/res/anim/confirm_credential_close_exit.xml b/res/anim/confirm_credential_close_exit.xml
new file mode 100644
index 0000000..5afd8b2
--- /dev/null
+++ b/res/anim/confirm_credential_close_exit.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="350" />
diff --git a/res/anim/confirm_credential_open_enter.xml b/res/anim/confirm_credential_open_enter.xml
new file mode 100644
index 0000000..06f3af8
--- /dev/null
+++ b/res/anim/confirm_credential_open_enter.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="160" />
diff --git a/res/anim/confirm_credential_open_exit.xml b/res/anim/confirm_credential_open_exit.xml
new file mode 100644
index 0000000..3f20a04
--- /dev/null
+++ b/res/anim/confirm_credential_open_exit.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:duration="160" />
diff --git a/res/drawable/ic_fingerprint_success.xml b/res/drawable/ic_fingerprint_success.xml
new file mode 100644
index 0000000..e800fae
--- /dev/null
+++ b/res/drawable/ic_fingerprint_success.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="40.0"
+ android:viewportHeight="40.0">
+ <path
+ android:pathData="M20.0,20.0m-20.0,0.0a20.0,20.0 0.0,1.0 1.0,40.0 0.0a20.0,20.0 0.0,1.0 1.0,-40.0 0.0"
+ android:fillColor="?android:attr/colorAccent"/>
+ <path
+ android:pathData="M11.2,21.41l1.63,-1.619999 4.17,4.169998 10.59,-10.589999 1.619999,1.63 -12.209999,12.209999z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5e9d870..1d58779 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -225,6 +225,11 @@
<item name="android:layout_height">wrap_content</item>
</style>
+ <style name="ConfirmDeviceCredentialsAnimationStyle" parent="@*android:style/Animation.Material.Activity">
+ <item name="android:activityOpenEnterAnimation">@anim/confirm_credential_open_enter</item>
+ <item name="android:activityOpenExitAnimation">@anim/confirm_credential_open_exit</item>
+ </style>
+
<style name="Transparent">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 76fc04f..f508f76 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -199,7 +199,7 @@
<item name="android:colorPrimaryDark">@*android:color/material_blue_grey_950</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
- <item name="preferenceBackgroundColor">@color/confirm_device_credential_dark_background</item>
+ <item name="android:windowBackground">@color/confirm_device_credential_dark_background</item>
<item name="confirmDeviceCredentialsSideMargin">32dp</item>
<item name="confirmDeviceCredentialsTopMargin">32dp</item>
@@ -208,6 +208,8 @@
<item name="@*android:regularColor">@color/lock_pattern_view_regular_color_dark</item>
<item name="@*android:successColor">@color/lock_pattern_view_regular_color_dark</item>
<item name="@*android:errorColor">@color/lock_pattern_view_error_color</item>
+
+ <item name="android:windowAnimationStyle">@style/ConfirmDeviceCredentialsAnimationStyle</item>
</style>
<style name="Theme.FingerprintEnroll" parent="@*android:style/Theme.Material.Settings.NoActionBar">
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java b/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java
index fe3de97..f56c315 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseActivity.java
@@ -16,17 +16,23 @@
package com.android.settings;
+import android.app.Fragment;
import android.app.KeyguardManager;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.WindowManager;
-public class ConfirmDeviceCredentialBaseActivity extends SettingsActivity {
+public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivity {
+
+ private boolean mRestoring;
+ private boolean mDark;
+ private boolean mEnterAnimationPending;
@Override
protected void onCreate(Bundle savedState) {
if (getIntent().getBooleanExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false)) {
setTheme(R.style.Theme_ConfirmDeviceCredentialsDark);
+ mDark = true;
}
super.onCreate(savedState);
boolean deviceLocked = getSystemService(KeyguardManager.class).isKeyguardLocked();
@@ -41,6 +47,7 @@
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
}
+ mRestoring = savedState != null;
}
@Override
@@ -51,4 +58,37 @@
}
return super.onOptionsItemSelected(item);
}
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (!isChangingConfigurations() && !mRestoring && mDark) {
+ prepareEnterAnimation();
+ mEnterAnimationPending = true;
+ }
+ }
+
+ private ConfirmDeviceCredentialBaseFragment getFragment() {
+ Fragment fragment = getFragmentManager().findFragmentById(R.id.main_content);
+ if (fragment != null && fragment instanceof ConfirmDeviceCredentialBaseFragment) {
+ return (ConfirmDeviceCredentialBaseFragment) fragment;
+ }
+ return null;
+ }
+
+ @Override
+ public void onEnterAnimationComplete() {
+ super.onEnterAnimationComplete();
+ if (mEnterAnimationPending) {
+ startEnterAnimation();
+ }
+ }
+
+ public void prepareEnterAnimation() {
+ getFragment().prepareEnterAnimation();
+ }
+
+ public void startEnterAnimation() {
+ getFragment().startEnterAnimation();
+ }
}
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
index 414aa01..a8b5f2d 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
@@ -45,6 +45,8 @@
private FingerprintUiHelper mFingerprintHelper;
private boolean mAllowFpAuthentication;
+ protected Button mCancelButton;
+ protected ImageView mFingerprintIcon;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -56,14 +58,15 @@
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+ mCancelButton = (Button) view.findViewById(R.id.cancelButton);
+ mFingerprintIcon = (ImageView) view.findViewById(R.id.fingerprintIcon);
mFingerprintHelper = new FingerprintUiHelper(
- (ImageView) view.findViewById(R.id.fingerprintIcon),
+ mFingerprintIcon,
(TextView) view.findViewById(R.id.errorText), this);
boolean showCancelButton = getActivity().getIntent().getBooleanExtra(
SHOW_CANCEL_BUTTON, false);
- Button cancelButton = (Button) view.findViewById(R.id.cancelButton);
- cancelButton.setVisibility(showCancelButton ? View.VISIBLE : View.GONE);
- cancelButton.setOnClickListener(new View.OnClickListener() {
+ mCancelButton.setVisibility(showCancelButton ? View.VISIBLE : View.GONE);
+ mCancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
@@ -100,4 +103,10 @@
@Override
public void onFingerprintIconVisibilityChanged(boolean visible) {
}
+
+ public void prepareEnterAnimation() {
+ }
+
+ public void startEnterAnimation() {
+ }
}
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index db0b44a..7761807 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -19,9 +19,12 @@
import android.os.UserHandle;
import android.text.TextUtils;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.TextViewInputDisabler;
+import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.animation.DisappearAnimationUtils;
import android.app.Fragment;
import android.app.admin.DevicePolicyManager;
@@ -39,11 +42,14 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
+import java.util.ArrayList;
+
public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
public static class InternalActivity extends ConfirmLockPassword {
@@ -89,6 +95,9 @@
private boolean mIsAlpha;
private InputMethodManager mImm;
private boolean mUsingFingerprint = false;
+ private AppearAnimationUtils mAppearAnimationUtils;
+ private DisappearAnimationUtils mDisappearAnimationUtils;
+ private boolean mBlockImm;
// required constructor for fragments
public ConfirmLockPasswordFragment() {
@@ -144,6 +153,14 @@
int currentType = mPasswordEntry.getInputType();
mPasswordEntry.setInputType(mIsAlpha ? currentType
: (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
+ mAppearAnimationUtils = new AppearAnimationUtils(getContext(),
+ 220, 2f /* translationScale */, 1f /* delayScale*/,
+ AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.linear_out_slow_in));
+ mDisappearAnimationUtils = new DisappearAnimationUtils(getContext(),
+ 110, 1f /* translationScale */,
+ 0.5f /* delayScale */, AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.fast_out_linear_in));
return view;
}
@@ -163,6 +180,43 @@
}
@Override
+ public void prepareEnterAnimation() {
+ super.prepareEnterAnimation();
+ mHeaderTextView.setAlpha(0f);
+ mDetailsTextView.setAlpha(0f);
+ mCancelButton.setAlpha(0f);
+ mPasswordEntry.setAlpha(0f);
+ mFingerprintIcon.setAlpha(0f);
+ mBlockImm = true;
+ }
+
+ private View[] getActiveViews() {
+ ArrayList<View> result = new ArrayList<>();
+ result.add(mHeaderTextView);
+ result.add(mDetailsTextView);
+ if (mCancelButton.getVisibility() == View.VISIBLE) {
+ result.add(mCancelButton);
+ }
+ result.add(mPasswordEntry);
+ if (mFingerprintIcon.getVisibility() == View.VISIBLE) {
+ result.add(mFingerprintIcon);
+ }
+ return result.toArray(new View[] {});
+ }
+
+ @Override
+ public void startEnterAnimation() {
+ super.startEnterAnimation();
+ mAppearAnimationUtils.startAnimation(getActiveViews(), new Runnable() {
+ @Override
+ public void run() {
+ mBlockImm = false;
+ resetState();
+ }
+ });
+ }
+
+ @Override
public void onPause() {
super.onPause();
if (mCountdownTimer != null) {
@@ -199,9 +253,7 @@
@Override
protected void authenticationSucceeded() {
- Intent intent = new Intent();
- getActivity().setResult(RESULT_OK, intent);
- getActivity().finish();
+ startDisappearAnimation(new Intent());
}
@Override
@@ -210,6 +262,7 @@
}
private void resetState() {
+ if (mBlockImm) return;
mPasswordEntry.setEnabled(true);
mPasswordEntryInputDisabler.setInputEnabled(true);
if (shouldAutoShowSoftKeyboard()) {
@@ -222,7 +275,7 @@
}
public void onWindowFocusChanged(boolean hasFocus) {
- if (!hasFocus) {
+ if (!hasFocus || mBlockImm) {
return;
}
// Post to let window focus logic to finish to allow soft input show/hide properly.
@@ -312,11 +365,28 @@
});
}
+ private void startDisappearAnimation(final Intent intent) {
+ if (getActivity().getThemeResId() == R.style.Theme_ConfirmDeviceCredentialsDark) {
+ mDisappearAnimationUtils.startAnimation(getActiveViews(), new Runnable() {
+ @Override
+ public void run() {
+ getActivity().setResult(RESULT_OK, intent);
+ getActivity().finish();
+ getActivity().overridePendingTransition(
+ R.anim.confirm_credential_close_enter,
+ R.anim.confirm_credential_close_exit);
+ }
+ });
+ } else {
+ getActivity().setResult(RESULT_OK, intent);
+ getActivity().finish();
+ }
+ }
+
private void onPasswordChecked(boolean matched, Intent intent, int timeoutMs) {
mPasswordEntryInputDisabler.setInputEnabled(true);
if (matched) {
- getActivity().setResult(RESULT_OK, intent);
- getActivity().finish();
+ startDisappearAnimation(intent);
} else {
if (timeoutMs > 0) {
long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index 90a39f9..1737635 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -22,10 +22,21 @@
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternView.Cell;
+import com.android.settingslib.animation.AppearAnimationCreator;
+import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.animation.DisappearAnimationUtils;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.app.Activity;
+import android.app.Fragment;
import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.os.AsyncTask;
@@ -33,11 +44,16 @@
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.view.MenuItem;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.TextView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
@@ -70,7 +86,8 @@
return false;
}
- public static class ConfirmLockPatternFragment extends ConfirmDeviceCredentialBaseFragment {
+ public static class ConfirmLockPatternFragment extends ConfirmDeviceCredentialBaseFragment
+ implements AppearAnimationCreator<Object> {
// how long we wait to clear a wrong pattern
private static final int WRONG_PATTERN_CLEAR_TIMEOUT_MS = 2000;
@@ -93,6 +110,9 @@
private CharSequence mHeaderText;
private CharSequence mDetailsText;
+ private AppearAnimationUtils mAppearAnimationUtils;
+ private DisappearAnimationUtils mDisappearAnimationUtils;
+
// required constructor for fragments
public ConfirmLockPatternFragment() {
@@ -144,6 +164,20 @@
getActivity().finish();
}
}
+ mAppearAnimationUtils = new AppearAnimationUtils(getContext(),
+ AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 2f /* translationScale */,
+ 1.3f /* delayScale */, AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.linear_out_slow_in));
+ mDisappearAnimationUtils = new DisappearAnimationUtils(getContext(),
+ 125, 4f /* translationScale */,
+ 0.3f /* delayScale */, AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.fast_out_linear_in),
+ new AppearAnimationUtils.RowTranslationScaler() {
+ @Override
+ public float getRowTranslationScale(int row, int numRows) {
+ return (float)(numRows - row) / numRows;
+ }
+ });
return view;
}
@@ -187,6 +221,51 @@
}
}
+ @Override
+ public void prepareEnterAnimation() {
+ super.prepareEnterAnimation();
+ mHeaderTextView.setAlpha(0f);
+ mCancelButton.setAlpha(0f);
+ mLockPatternView.setAlpha(0f);
+ mDetailsTextView.setAlpha(0f);
+ mFingerprintIcon.setAlpha(0f);
+ }
+
+ private Object[][] getActiveViews() {
+ ArrayList<ArrayList<Object>> result = new ArrayList<>();
+ result.add(new ArrayList<Object>(Collections.singletonList(mHeaderTextView)));
+ result.add(new ArrayList<Object>(Collections.singletonList(mDetailsTextView)));
+ if (mCancelButton.getVisibility() == View.VISIBLE) {
+ result.add(new ArrayList<Object>(Collections.singletonList(mCancelButton)));
+ }
+ LockPatternView.CellState[][] cellStates = mLockPatternView.getCellStates();
+ for (int i = 0; i < cellStates.length; i++) {
+ ArrayList<Object> row = new ArrayList<>();
+ for (int j = 0; j < cellStates[i].length; j++) {
+ row.add(cellStates[i][j]);
+ }
+ result.add(row);
+ }
+ if (mFingerprintIcon.getVisibility() == View.VISIBLE) {
+ result.add(new ArrayList<Object>(Collections.singletonList(mFingerprintIcon)));
+ }
+ Object[][] resultArr = new Object[result.size()][cellStates[0].length];
+ for (int i = 0; i < result.size(); i++) {
+ ArrayList<Object> row = result.get(i);
+ for (int j = 0; j < row.size(); j++) {
+ resultArr[i][j] = row.get(j);
+ }
+ }
+ return resultArr;
+ }
+
+ @Override
+ public void startEnterAnimation() {
+ super.startEnterAnimation();
+ mLockPatternView.setAlpha(1f);
+ mAppearAnimationUtils.startAnimation2d(getActiveViews(), null, this);
+ }
+
private void updateStage(Stage stage) {
switch (stage) {
case NeedToUnlock:
@@ -242,9 +321,27 @@
@Override
protected void authenticationSucceeded() {
- Intent intent = new Intent();
- getActivity().setResult(Activity.RESULT_OK, intent);
- getActivity().finish();
+ startDisappearAnimation(new Intent());
+ }
+
+ private void startDisappearAnimation(final Intent intent) {
+ if (getActivity().getThemeResId() == R.style.Theme_ConfirmDeviceCredentialsDark) {
+ mLockPatternView.clearPattern();
+ mDisappearAnimationUtils.startAnimation2d(getActiveViews(),
+ new Runnable() {
+ @Override
+ public void run() {
+ getActivity().setResult(RESULT_OK, intent);
+ getActivity().finish();
+ getActivity().overridePendingTransition(
+ R.anim.confirm_credential_close_enter,
+ R.anim.confirm_credential_close_exit);
+ }
+ }, this);
+ } else {
+ getActivity().setResult(RESULT_OK, intent);
+ getActivity().finish();
+ }
}
@Override
@@ -357,8 +454,7 @@
boolean matched, Intent intent, int timeoutMs) {
mLockPatternView.setEnabled(true);
if (matched) {
- getActivity().setResult(Activity.RESULT_OK, intent);
- getActivity().finish();
+ startDisappearAnimation(intent);
} else {
if (timeoutMs > 0) {
long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
@@ -394,5 +490,52 @@
}
}.start();
}
+
+ @Override
+ public void createAnimation(Object obj, long delay,
+ long duration, float translationY, final boolean appearing,
+ Interpolator interpolator,
+ final Runnable finishListener) {
+ if (obj instanceof LockPatternView.CellState) {
+ final LockPatternView.CellState animatedCell = (LockPatternView.CellState) obj;
+ if (appearing) {
+ animatedCell.scale = 0.0f;
+ animatedCell.alpha = 1.0f;
+ }
+ animatedCell.translateY = appearing ? translationY : 0;
+ ValueAnimator animator = ValueAnimator.ofFloat(animatedCell.translateY,
+ appearing ? 0 : translationY);
+ animator.setInterpolator(interpolator);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float animatedFraction = animation.getAnimatedFraction();
+ if (appearing) {
+ animatedCell.scale = animatedFraction;
+ } else {
+ animatedCell.alpha = 1 - animatedFraction;
+ }
+ animatedCell.translateY = (float) animation.getAnimatedValue();
+ mLockPatternView.invalidate();
+ }
+ });
+ if (finishListener != null) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishListener.run();
+ }
+ });
+ }
+
+ animator.start();
+ mLockPatternView.invalidate();
+ } else {
+ mAppearAnimationUtils.createAnimation((View) obj, delay, duration, translationY,
+ appearing, interpolator, finishListener);
+ }
+ }
}
}
diff --git a/src/com/android/settings/fingerprint/FingerprintUiHelper.java b/src/com/android/settings/fingerprint/FingerprintUiHelper.java
index 6ae76aa..23a135e 100644
--- a/src/com/android/settings/fingerprint/FingerprintUiHelper.java
+++ b/src/com/android/settings/fingerprint/FingerprintUiHelper.java
@@ -18,7 +18,6 @@
import android.hardware.fingerprint.FingerprintManager;
import android.os.CancellationSignal;
-import android.os.Vibrator;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -31,8 +30,6 @@
public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallback {
private static final long ERROR_TIMEOUT = 1300;
- private static final long[] FP_ERROR_VIBRATE_PATTERN = new long[] {0, 30, 100, 30};
- private static final long[] FP_SUCCESS_VIBRATE_PATTERN = new long[] {0, 30};
private ImageView mIcon;
private TextView mErrorTextView;
@@ -92,7 +89,7 @@
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
- vibrateFingerprintSuccess();
+ mIcon.setImageResource(R.drawable.ic_fingerprint_success);
mCallback.onAuthenticated();
}
@@ -101,21 +98,12 @@
return;
}
- vibrateFingerprintError();
mIcon.setImageResource(R.drawable.ic_fingerprint_error);
mErrorTextView.setText(error);
mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT);
}
- private void vibrateFingerprintError() {
- mIcon.getContext().getSystemService(Vibrator.class).vibrate(FP_ERROR_VIBRATE_PATTERN, -1);
- }
-
- private void vibrateFingerprintSuccess() {
- mIcon.getContext().getSystemService(Vibrator.class).vibrate(FP_SUCCESS_VIBRATE_PATTERN, -1);
- }
-
private Runnable mResetErrorTextRunnable = new Runnable() {
@Override
public void run() {