Enable start haptic for udfps by default

When the user's touch first enters the udfps area, play the
keyboard pressed (click) haptic feedback.

Test: manual, atest UdfpsControllerTest
Fixes: 187535630
Bug: 185124905
Change-Id: I2e5231e74dbbc2617ba9f0f04127827fd14078e9
This commit is contained in:
Beverly
2021-05-10 12:54:45 -04:00
committed by Beverly Tai
parent 0d88f8065d
commit 271709856b
2 changed files with 61 additions and 22 deletions

View File

@@ -105,7 +105,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull private final DumpManager mDumpManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
@NonNull private final Vibrator mVibrator;
@Nullable private final Vibrator mVibrator;
@NonNull private final Handler mMainHandler;
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final PowerManager mPowerManager;
@@ -135,7 +135,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private boolean mScreenOn;
private Runnable mAodInterruptRunnable;
private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
@VisibleForTesting
static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
@@ -144,7 +145,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK);
private final VibrationEffect mEffectTextureTick =
VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
@VisibleForTesting
final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
private final VibrationEffect mEffectHeavy =
VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
private final VibrationEffect mDoubleClick =
@@ -152,6 +154,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private final Runnable mAcquiredVibration = new Runnable() {
@Override
public void run() {
if (mVibrator == null) {
return;
}
String effect = Settings.Global.getString(mContext.getContentResolver(),
"udfps_acquired_type");
mVibrator.vibrate(getVibration(effect, mEffectTick), VIBRATION_SONIFICATION_ATTRIBUTES);
@@ -389,24 +394,28 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
// TODO: this should eventually be removed after ux testing
final ContentResolver contentResolver = mContext.getContentResolver();
int startEnabled = Settings.Global.getInt(contentResolver,
"udfps_start", 0);
if (startEnabled > 0) {
String startEffectSetting = Settings.Global.getString(
contentResolver, "udfps_start_type");
mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick),
VIBRATION_SONIFICATION_ATTRIBUTES);
if (mVibrator != null) {
final ContentResolver contentResolver =
mContext.getContentResolver();
int startEnabled = Settings.Global.getInt(contentResolver,
"udfps_start", 1);
if (startEnabled > 0) {
String startEffectSetting = Settings.Global.getString(
contentResolver, "udfps_start_type");
mVibrator.vibrate(getVibration(startEffectSetting,
mEffectClick), VIBRATION_SONIFICATION_ATTRIBUTES);
}
int acquiredEnabled = Settings.Global.getInt(contentResolver,
"udfps_acquired", 0);
if (acquiredEnabled > 0) {
int delay = Settings.Global.getInt(contentResolver,
"udfps_acquired_delay", 500);
mMainHandler.removeCallbacks(mAcquiredVibration);
mMainHandler.postDelayed(mAcquiredVibration, delay);
}
}
int acquiredEnabled = Settings.Global.getInt(contentResolver,
"udfps_acquired", 0);
if (acquiredEnabled > 0) {
int delay = Settings.Global.getInt(contentResolver,
"udfps_acquired_delay", 500);
mMainHandler.removeCallbacks(mAcquiredVibration);
mMainHandler.postDelayed(mAcquiredVibration, delay);
}
handled = true;
} else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
Log.v(TAG, "onTouch | finger move: " + touchInfo);
@@ -456,11 +465,12 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull FalsingManager falsingManager,
@NonNull PowerManager powerManager,
@NonNull AccessibilityManager accessibilityManager,
@NonNull ScreenLifecycle screenLifecycle) {
@NonNull ScreenLifecycle screenLifecycle,
@Nullable Vibrator vibrator) {
mContext = context;
// TODO (b/185124905): inject main handler and vibrator once done prototyping
mMainHandler = new Handler(Looper.getMainLooper());
mVibrator = context.getSystemService(Vibrator.class);
mVibrator = vibrator;
mInflater = inflater;
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
// fingerprint manager should never be null.

View File

@@ -35,6 +35,7 @@ import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
@@ -114,6 +115,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
private AccessibilityManager mAccessibilityManager;
@Mock
private ScreenLifecycle mScreenLifecycle;
@Mock
private Vibrator mVibrator;
private FakeExecutor mFgExecutor;
@@ -170,7 +173,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFalsingManager,
mPowerManager,
mAccessibilityManager,
mScreenLifecycle);
mScreenLifecycle,
mVibrator);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -302,4 +306,29 @@ public class UdfpsControllerTest extends SysuiTestCase {
// THEN no illumination because screen is off
verify(mUdfpsView, never()).startIllumination(any());
}
@Test
public void playHapticOnTouchUdfpsArea() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
downEvent.recycle();
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN click haptic is played
verify(mVibrator).vibrate(mUdfpsController.mEffectClick,
UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES);
}
}