Merge "Flicker in Fingerprint Enrollment" into tm-qpr-dev
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 73de183..42d60ee 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1664,9 +1664,4 @@
[CHAR LIMIT=NONE] -->
<string-array name="allowlist_hide_summary_in_battery_usage" translatable="false">
</string-array>
-
- <!-- Array containing help message codes that should not be displayed
- during fingerprint enrollment. -->
- <integer-array name="fingerprint_acquired_ignore_list">
- </integer-array>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 2d04bc9..e3b8618 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -645,4 +645,11 @@
<!-- Whether the toggle for Auto-rotate with Face Detection should be shown. -->
<bool name="config_auto_rotate_face_detection_available">true</bool>
+ <!-- In the case of receiving both help and progress message, display progress message. -->
+ <bool name="enrollment_progress_priority_over_help">false</bool>
+ <!-- Prioritize help message by their occurrence -->
+ <bool name="enrollment_prioritize_acquire_messages">false</bool>
+ <!-- Control messages displayed during enrollment -->
+ <bool name="enrollment_message_display_controller_flag">false</bool>
+
</resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index d110de2..530f987 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -26,4 +26,11 @@
<integer name="suw_max_faces_enrollable">1</integer>
<!-- Controls the maximum number of fingerprints enrollable during SUW -->
<integer name="suw_max_fingerprints_enrollable">1</integer>
+
+ <!-- Minimum display time (in millis) for help messages in fingerprint enrollment. -->
+ <integer name="enrollment_help_minimum_time_display">0</integer>
+ <!-- Minimum display time (in millis) for progress messages in fingerprint enrollment. -->
+ <integer name="enrollment_progress_minimum_time_display">0</integer>
+ <!-- The time (in millis) to wait to collect messages in fingerprint enrollment before displaying it. -->
+ <integer name="enrollment_collect_time">0</integer>
</resources>
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 897e290..2eadc33 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -350,8 +350,8 @@
@Override
protected BiometricEnrollSidecar getSidecar() {
- final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar();
- sidecar.setEnrollReason(FingerprintManager.ENROLL_ENROLL);
+ final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar(this,
+ FingerprintManager.ENROLL_ENROLL);
return sidecar;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 200b8c5..778ee5c 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -293,8 +293,8 @@
mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag(
FingerprintEnrollEnrolling.TAG_SIDECAR);
if (mSidecar == null) {
- mSidecar = new FingerprintEnrollSidecar();
- mSidecar.setEnrollReason(FingerprintManager.ENROLL_FIND_SENSOR);
+ mSidecar = new FingerprintEnrollSidecar(this,
+ FingerprintManager.ENROLL_FIND_SENSOR);
getSupportFragmentManager().beginTransaction()
.add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR)
.commitAllowingStateLoss();
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
index d1e512e..b3b9975 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
@@ -16,19 +16,19 @@
package com.android.settings.biometrics.fingerprint;
+import static android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL;
+
import android.app.Activity;
import android.app.settings.SettingsEnums;
+import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollSidecar;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
/**
* Sidecar fragment to handle the state around fingerprint enrollment.
*/
@@ -37,19 +37,41 @@
private FingerprintUpdater mFingerprintUpdater;
private @FingerprintManager.EnrollReason int mEnrollReason;
- private Set<Integer> mHelpIgnore;
+ private final MessageDisplayController mMessageDisplayController;
+ private final boolean mMessageDisplayControllerFlag;
+
+ /**
+ * Create a new FingerprintEnrollSidecar object.
+ * @param context associated context
+ * @param enrollReason reason for enrollment
+ */
+ public FingerprintEnrollSidecar(Context context,
+ @FingerprintManager.EnrollReason int enrollReason) {
+ mEnrollReason = enrollReason;
+
+ int helpMinimumDisplayTime = context.getResources().getInteger(
+ R.integer.enrollment_help_minimum_time_display);
+ int progressMinimumDisplayTime = context.getResources().getInteger(
+ R.integer.enrollment_progress_minimum_time_display);
+ boolean progressPriorityOverHelp = context.getResources().getBoolean(
+ R.bool.enrollment_progress_priority_over_help);
+ boolean prioritizeAcquireMessages = context.getResources().getBoolean(
+ R.bool.enrollment_prioritize_acquire_messages);
+ int collectTime = context.getResources().getInteger(
+ R.integer.enrollment_collect_time);
+ mMessageDisplayControllerFlag = context.getResources().getBoolean(
+ R.bool.enrollment_message_display_controller_flag);
+
+ mMessageDisplayController = new MessageDisplayController(context.getMainThreadHandler(),
+ mEnrollmentCallback, SystemClock.elapsedRealtimeClock(), helpMinimumDisplayTime,
+ progressMinimumDisplayTime, progressPriorityOverHelp, prioritizeAcquireMessages,
+ collectTime);
+ }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mFingerprintUpdater = new FingerprintUpdater(activity);
- final int[] ignoreAcquiredInfo = getResources().getIntArray(
- R.array.fingerprint_acquired_ignore_list);
- mHelpIgnore = new HashSet<>();
- for (int acquiredInfo: ignoreAcquiredInfo) {
- mHelpIgnore.add(acquiredInfo);
- }
- mHelpIgnore = Collections.unmodifiableSet(mHelpIgnore);
}
@Override
@@ -62,8 +84,16 @@
getString(R.string.fingerprint_intro_error_unknown));
return;
}
- mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
- mEnrollReason);
+
+ if (mEnrollReason == ENROLL_ENROLL && mMessageDisplayControllerFlag) {
+ //API calls need to be processed for {@link FingerprintEnrollEnrolling}
+ mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId,
+ mMessageDisplayController, mEnrollReason);
+ } else {
+ //No processing required for {@link FingerprintEnrollFindSensor}
+ mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
+ mEnrollReason);
+ }
}
public void setEnrollReason(@FingerprintManager.EnrollReason int enrollReason) {
@@ -80,9 +110,6 @@
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
- if (mHelpIgnore.contains(helpMsgId)) {
- return;
- }
FingerprintEnrollSidecar.super.onEnrollmentHelp(helpMsgId, helpString);
}
diff --git a/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java b/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java
new file mode 100644
index 0000000..11f3ee3
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package com.android.settings.biometrics.fingerprint;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import java.time.Clock;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+
+/**
+ * Processes message provided from the enrollment callback and filters them based
+ * on the below configurable flags. This is primarily used to reduce the rate
+ * at which messages come through, which in turns eliminates UI flicker.
+ */
+public class MessageDisplayController extends FingerprintManager.EnrollmentCallback {
+
+ private final int mHelpMinimumDisplayTime;
+ private final int mProgressMinimumDisplayTime;
+ private final boolean mProgressPriorityOverHelp;
+ private final boolean mPrioritizeAcquireMessages;
+ private final int mCollectTime;
+ @NonNull
+ private final Deque<HelpMessage> mHelpMessageList;
+ @NonNull
+ private final Deque<ProgressMessage> mProgressMessageList;
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final Clock mClock;
+ @NonNull
+ private final Runnable mDisplayMessageRunnable;
+
+ @Nullable
+ private ProgressMessage mLastProgressMessageDisplayed;
+ private boolean mMustDisplayProgress;
+ private boolean mWaitingForMessage;
+ @NonNull FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+
+ private abstract static class Message {
+ long mTimeStamp = 0;
+ abstract void display();
+ }
+
+ private class HelpMessage extends Message {
+ private final int mHelpMsgId;
+ private final CharSequence mHelpString;
+
+ HelpMessage(int helpMsgId, CharSequence helpString) {
+ mHelpMsgId = helpMsgId;
+ mHelpString = helpString;
+ mTimeStamp = mClock.millis();
+ }
+
+ @Override
+ void display() {
+ mEnrollmentCallback.onEnrollmentHelp(mHelpMsgId, mHelpString);
+ mHandler.postDelayed(mDisplayMessageRunnable, mHelpMinimumDisplayTime);
+ }
+ }
+
+ private class ProgressMessage extends Message {
+ private final int mRemaining;
+
+ ProgressMessage(int remaining) {
+ mRemaining = remaining;
+ mTimeStamp = mClock.millis();
+ }
+
+ @Override
+ void display() {
+ mEnrollmentCallback.onEnrollmentProgress(mRemaining);
+ mLastProgressMessageDisplayed = this;
+ mHandler.postDelayed(mDisplayMessageRunnable, mProgressMinimumDisplayTime);
+ }
+ }
+
+ /**
+ * Creating a MessageDisplayController object.
+ * @param handler main handler to run message queue
+ * @param enrollmentCallback callback to display messages
+ * @param clock real time system clock
+ * @param helpMinimumDisplayTime the minimum duration (in millis) that
+* a help message needs to be displayed for
+ * @param progressMinimumDisplayTime the minimum duration (in millis) that
+* a progress message needs to be displayed for
+ * @param progressPriorityOverHelp if true, then progress message is displayed
+* when both help and progress message APIs have been called
+ * @param prioritizeAcquireMessages if true, then displays the help message
+* which has occurred the most after the last display message
+ * @param collectTime the waiting time (in millis) to collect messages when it is idle
+ */
+ public MessageDisplayController(@NonNull Handler handler,
+ FingerprintManager.EnrollmentCallback enrollmentCallback,
+ @NonNull Clock clock, int helpMinimumDisplayTime, int progressMinimumDisplayTime,
+ boolean progressPriorityOverHelp, boolean prioritizeAcquireMessages,
+ int collectTime) {
+ mClock = clock;
+ mWaitingForMessage = false;
+ mHelpMessageList = new ArrayDeque<>();
+ mProgressMessageList = new ArrayDeque<>();
+ mHandler = handler;
+ mEnrollmentCallback = enrollmentCallback;
+
+ mHelpMinimumDisplayTime = helpMinimumDisplayTime;
+ mProgressMinimumDisplayTime = progressMinimumDisplayTime;
+ mProgressPriorityOverHelp = progressPriorityOverHelp;
+ mPrioritizeAcquireMessages = prioritizeAcquireMessages;
+ mCollectTime = collectTime;
+
+ mDisplayMessageRunnable = () -> {
+ long timeStamp = mClock.millis();
+ Message messageToDisplay = getMessageToDisplay(timeStamp);
+
+ if (messageToDisplay != null) {
+ messageToDisplay.display();
+ } else {
+ mWaitingForMessage = true;
+ }
+ };
+
+ mHandler.postDelayed(mDisplayMessageRunnable, 0);
+ }
+
+ /**
+ * Adds help message to the queue to be processed later.
+ *
+ * @param helpMsgId message Id associated with the help message
+ * @param helpString string associated with the help message
+ */
+ @Override
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+ mHelpMessageList.add(new HelpMessage(helpMsgId, helpString));
+
+ if (mWaitingForMessage) {
+ mWaitingForMessage = false;
+ mHandler.postDelayed(mDisplayMessageRunnable, mCollectTime);
+ }
+ }
+
+ /**
+ * Adds progress change message to the queue to be processed later.
+ *
+ * @param remaining remaining number of steps to complete enrollment
+ */
+ @Override
+ public void onEnrollmentProgress(int remaining) {
+ mProgressMessageList.add(new ProgressMessage(remaining));
+
+ if (mWaitingForMessage) {
+ mWaitingForMessage = false;
+ mHandler.postDelayed(mDisplayMessageRunnable, mCollectTime);
+ }
+ }
+
+ @Override
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {
+ mEnrollmentCallback.onEnrollmentError(errMsgId, errString);
+ }
+
+ private Message getMessageToDisplay(long timeStamp) {
+ ProgressMessage progressMessageToDisplay = getProgressMessageToDisplay(timeStamp);
+ if (mMustDisplayProgress) {
+ mMustDisplayProgress = false;
+ if (progressMessageToDisplay != null) {
+ return progressMessageToDisplay;
+ }
+ if (mLastProgressMessageDisplayed != null) {
+ return mLastProgressMessageDisplayed;
+ }
+ }
+
+ Message helpMessageToDisplay = getHelpMessageToDisplay(timeStamp);
+ if (helpMessageToDisplay != null || progressMessageToDisplay != null) {
+ if (mProgressPriorityOverHelp && progressMessageToDisplay != null) {
+ return progressMessageToDisplay;
+ } else if (helpMessageToDisplay != null) {
+ if (progressMessageToDisplay != null) {
+ mMustDisplayProgress = true;
+ mLastProgressMessageDisplayed = progressMessageToDisplay;
+ }
+ return helpMessageToDisplay;
+ } else {
+ return progressMessageToDisplay;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private ProgressMessage getProgressMessageToDisplay(long timeStamp) {
+ ProgressMessage finalProgressMessage = null;
+ while (mProgressMessageList != null && !mProgressMessageList.isEmpty()) {
+ Message message = mProgressMessageList.peekFirst();
+ if (message.mTimeStamp <= timeStamp) {
+ ProgressMessage progressMessage = mProgressMessageList.pollFirst();
+ if (mLastProgressMessageDisplayed != null
+ && mLastProgressMessageDisplayed.mRemaining == progressMessage.mRemaining) {
+ continue;
+ }
+ finalProgressMessage = progressMessage;
+ } else {
+ break;
+ }
+ }
+
+ return finalProgressMessage;
+ }
+
+ private HelpMessage getHelpMessageToDisplay(long timeStamp) {
+ HashMap<CharSequence, Integer> messageCount = new HashMap<>();
+ HelpMessage finalHelpMessage = null;
+
+ while (mHelpMessageList != null && !mHelpMessageList.isEmpty()) {
+ Message message = mHelpMessageList.peekFirst();
+ if (message.mTimeStamp <= timeStamp) {
+ finalHelpMessage = mHelpMessageList.pollFirst();
+ CharSequence errString = finalHelpMessage.mHelpString;
+ messageCount.put(errString, messageCount.getOrDefault(errString, 0) + 1);
+ } else {
+ break;
+ }
+ }
+ if (mPrioritizeAcquireMessages) {
+ finalHelpMessage = prioritizeHelpMessageByCount(messageCount);
+ }
+
+ return finalHelpMessage;
+ }
+
+ private HelpMessage prioritizeHelpMessageByCount(HashMap<CharSequence, Integer> messageCount) {
+ int maxCount = 0;
+ CharSequence maxCountMessage = null;
+
+ for (CharSequence key :
+ messageCount.keySet()) {
+ if (maxCount < messageCount.get(key)) {
+ maxCountMessage = key;
+ maxCount = messageCount.get(key);
+ }
+ }
+
+ return maxCountMessage != null ? new HelpMessage(0 /* errMsgId */,
+ maxCountMessage) : null;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index b049b7b..b899206 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -18,7 +18,6 @@
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
-import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UNKNOWN;
import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.KEY_STATE_PREVIOUS_ROTATION;
import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.SFPS_STAGE_NO_ANIMATION;
@@ -36,8 +35,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.mock;
-
import android.content.Context;
import android.content.res.ColorStateList;
@@ -53,9 +50,6 @@
import android.os.Vibrator;
import android.view.Display;
import android.view.Surface;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -104,42 +98,6 @@
}
@Test
- public void fingerprintEnrollHelp_shouldShowHelpText() {
- initializeActivityFor(TYPE_UNKNOWN);
- TestFingerprintEnrollSidecar sidecar = new TestFingerprintEnrollSidecar();
- Resources resources = mock(Resources.class);
- doReturn(resources).when(mContext).getResources();
- when(resources.getIntArray(R.array.fingerprint_acquired_ignore_list))
- .thenReturn(new int[]{3});
-
- sidecar.setListener(mActivity);
- sidecar.onAttach(mActivity);
- sidecar.mEnrollmentCallback.onEnrollmentHelp(5,
- "Help message should be displayed.");
-
- TextView errorText = mActivity.findViewById(R.id.error_text);
- assertThat(errorText.getText()).isEqualTo("Help message should be displayed.");
- }
-
- @Test
- public void fingerprintEnrollHelp_shouldNotShowHelpText() {
- initializeActivityFor(TYPE_UNKNOWN);
- TestFingerprintEnrollSidecar sidecar = new TestFingerprintEnrollSidecar();
- Resources resources = mock(Resources.class);
- doReturn(resources).when(mContext).getResources();
- when(resources.getIntArray(R.array.fingerprint_acquired_ignore_list))
- .thenReturn(new int[]{3});
-
- sidecar.setListener(mActivity);
- sidecar.onAttach(mActivity);
- sidecar.mEnrollmentCallback.onEnrollmentHelp(3,
- "Help message should not be displayed.");
-
- TextView errorText = mActivity.findViewById(R.id.error_text);
- assertThat(errorText.getText()).isEqualTo("");
- }
-
- @Test
public void fingerprintUdfpsEnrollSuccessProgress_shouldNotVibrate() {
initializeActivityFor(TYPE_UDFPS_OPTICAL);
@@ -346,12 +304,4 @@
return callbackCaptor.getValue();
}
-
- private class TestFingerprintEnrollSidecar extends FingerprintEnrollSidecar {
- @Nullable
- @Override
- public Context getContext() {
- return mContext;
- }
- }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java
new file mode 100644
index 0000000..0fa0918
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package com.android.settings.biometrics.fingerprint;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLooper;
+
+import java.time.Clock;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(RobolectricTestRunner.class)
+public class MessageDisplayControllerTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private static final long START_TIME = 0L;
+ private static final int HELP_ID = 0;
+ private static final String HELP_MESSAGE = "Default Help Message";
+ private static final int REMAINING = 5;
+ private static final int HELP_MINIMUM_DISPLAY_TIME = 300;
+ private static final int PROGRESS_MINIMUM_DISPLAY_TIME = 250;
+ private static final int COLLECT_TIME = 100;
+
+ private MessageDisplayController mMessageDisplayController;
+ @Mock
+ private FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+ @Mock
+ private Clock mClock;
+
+ @Before
+ public void setup() {
+ mMessageDisplayController = new MessageDisplayController(new Handler(), mEnrollmentCallback,
+ mClock,
+ HELP_MINIMUM_DISPLAY_TIME, /* progressPriorityOverHelp */
+ PROGRESS_MINIMUM_DISPLAY_TIME, /* prioritizeAcquireMessages */
+ false, false, COLLECT_TIME);
+ }
+
+ private void setMessageDisplayController(boolean progressPriorityOverHelp,
+ boolean prioritizeAcquireMessages) {
+ mMessageDisplayController = new MessageDisplayController(new Handler(), mEnrollmentCallback,
+ mClock, HELP_MINIMUM_DISPLAY_TIME, PROGRESS_MINIMUM_DISPLAY_TIME,
+ progressPriorityOverHelp, prioritizeAcquireMessages, COLLECT_TIME);
+ }
+
+ @Test
+ public void showsHelpMessageAfterCollectTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void showsProgressMessageAfterCollectTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void helpDisplayedForMinimumDisplayTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ when(mClock.millis()).thenReturn((long) (HELP_MINIMUM_DISPLAY_TIME + COLLECT_TIME));
+ ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ }
+
+ @Test
+ public void progressDisplayedForMinimumDisplayTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(PROGRESS_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ }
+
+ @Test
+ public void prioritizeHelpMessage_thenShowProgress() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + HELP_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ }
+
+ @Test
+ public void prioritizeProgressOverHelp() {
+ when(mClock.millis()).thenReturn(START_TIME);
+ setMessageDisplayController(true /* progressPriorityOverHelp */,
+ false /* prioritizeAcquireMessages */);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void prioritizeHelpMessageByCount() {
+ String newHelpMessage = "New message";
+ when(mClock.millis()).thenReturn(START_TIME);
+ setMessageDisplayController(false /* progressPriorityOverHelp */,
+ true /* prioritizeAcquireMessages */);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, newHelpMessage);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void ignoreSameProgress() {
+ int progressChange = REMAINING - 1;
+ when(mClock.millis()).thenReturn(START_TIME);
+ setMessageDisplayController(true /* progressPriorityOverHelp */,
+ false /* prioritizeAcquireMessages */);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(PROGRESS_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+ mMessageDisplayController.onEnrollmentProgress(progressChange);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME
+ + HELP_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(progressChange);
+ }
+}