Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f079495a authored by Austin Delgado's avatar Austin Delgado Committed by Android (Google) Code Review
Browse files

Merge "Move UdfpsDisplayMode to AOSP" into tm-qpr-dev

parents 46b33d3f 61db48b3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -294,6 +294,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
                }
            });
            mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation);
            mUdfpsController.setUdfpsDisplayMode(new UdfpsDisplayMode(mContext, mExecution,
                    this));
            mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect();
        }

+5 −3
Original line number Diff line number Diff line
@@ -123,7 +123,6 @@ public class UdfpsController implements DozeReceiver {
    @NonNull private final PowerManager mPowerManager;
    @NonNull private final AccessibilityManager mAccessibilityManager;
    @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
    @Nullable private final UdfpsDisplayModeProvider mUdfpsDisplayMode;
    @NonNull private final ConfigurationController mConfigurationController;
    @NonNull private final SystemClock mSystemClock;
    @NonNull private final UnlockedScreenOffAnimationController
@@ -139,6 +138,7 @@ public class UdfpsController implements DozeReceiver {
    // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this.
    @Nullable private Runnable mAuthControllerUpdateUdfpsLocation;
    @Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider;
    @Nullable private UdfpsDisplayMode mUdfpsDisplayMode;

    // Tracks the velocity of a touch to help filter out the touches that move too fast.
    @Nullable private VelocityTracker mVelocityTracker;
@@ -319,6 +319,10 @@ public class UdfpsController implements DozeReceiver {
        mAuthControllerUpdateUdfpsLocation = r;
    }

    public void setUdfpsDisplayMode(UdfpsDisplayMode udfpsDisplayMode) {
        mUdfpsDisplayMode = udfpsDisplayMode;
    }

    /**
     * Calculate the pointer speed given a velocity tracker and the pointer id.
     * This assumes that the velocity tracker has already been passed all relevant motion events.
@@ -594,7 +598,6 @@ public class UdfpsController implements DozeReceiver {
            @NonNull VibratorHelper vibrator,
            @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
            @NonNull UdfpsShell udfpsShell,
            @NonNull Optional<UdfpsDisplayModeProvider> udfpsDisplayMode,
            @NonNull KeyguardStateController keyguardStateController,
            @NonNull DisplayManager displayManager,
            @Main Handler mainHandler,
@@ -626,7 +629,6 @@ public class UdfpsController implements DozeReceiver {
        mPowerManager = powerManager;
        mAccessibilityManager = accessibilityManager;
        mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
        mUdfpsDisplayMode = udfpsDisplayMode.orElse(null);
        screenLifecycle.addObserver(mScreenObserver);
        mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
        mConfigurationController = configurationController;
+88 −0
Original line number Diff line number Diff line
package com.android.systemui.biometrics

import android.content.Context
import android.os.RemoteException
import android.os.Trace
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.concurrency.Execution
import javax.inject.Inject

private const val TAG = "UdfpsDisplayMode"

/**
 * UdfpsDisplayMode that encapsulates pixel-specific code, such as enabling the high-brightness mode
 * (HBM) in a display-specific way and freezing the display's refresh rate.
 */
@SysUISingleton
class UdfpsDisplayMode
@Inject
constructor(
    private val context: Context,
    private val execution: Execution,
    private val authController: AuthController
) : UdfpsDisplayModeProvider {

    // The request is reset to null after it's processed.
    private var currentRequest: Request? = null

    override fun enable(onEnabled: Runnable?) {
        execution.isMainThread()
        Log.v(TAG, "enable")

        if (currentRequest != null) {
            Log.e(TAG, "enable | already requested")
            return
        }
        if (authController.udfpsHbmListener == null) {
            Log.e(TAG, "enable | mDisplayManagerCallback is null")
            return
        }

        Trace.beginSection("UdfpsDisplayMode.enable")

        // Track this request in one object.
        val request = Request(context.displayId)
        currentRequest = request

        try {
            // This method is a misnomer. It has nothing to do with HBM, its purpose is to set
            // the appropriate display refresh rate.
            authController.udfpsHbmListener!!.onHbmEnabled(request.displayId)
            Log.v(TAG, "enable | requested optimal refresh rate for UDFPS")
        } catch (e: RemoteException) {
            Log.e(TAG, "enable", e)
        }

        onEnabled?.run() ?: Log.w(TAG, "enable | onEnabled is null")
        Trace.endSection()
    }

    override fun disable(onDisabled: Runnable?) {
        execution.isMainThread()
        Log.v(TAG, "disable")

        val request = currentRequest
        if (request == null) {
            Log.w(TAG, "disable | already disabled")
            return
        }

        Trace.beginSection("UdfpsDisplayMode.disable")

        try {
            // Allow DisplayManager to unset the UDFPS refresh rate.
            authController.udfpsHbmListener!!.onHbmDisabled(request.displayId)
            Log.v(TAG, "disable | removed the UDFPS refresh rate request")
        } catch (e: RemoteException) {
            Log.e(TAG, "disable", e)
        }

        currentRequest = null
        onDisabled?.run() ?: Log.w(TAG, "disable | onDisabled is null")
        Trace.endSection()
    }
}

/** Tracks a request to enable the UDFPS mode. */
private data class Request(val displayId: Int)
+3 −1
Original line number Diff line number Diff line
@@ -169,6 +169,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
    @Mock
    private LatencyTracker mLatencyTracker;
    private FakeExecutor mFgExecutor;
    @Mock
    private UdfpsDisplayMode mUdfpsDisplayMode;

    // Stuff for configuring mocks
    @Mock
@@ -258,7 +260,6 @@ public class UdfpsControllerTest extends SysuiTestCase {
                mVibrator,
                mUdfpsHapticsSimulator,
                mUdfpsShell,
                Optional.of(mDisplayModeProvider),
                mKeyguardStateController,
                mDisplayManager,
                mHandler,
@@ -275,6 +276,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
        verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
        mScreenObserver = mScreenObserverCaptor.getValue();
        mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, new UdfpsOverlayParams());
        mUdfpsController.setUdfpsDisplayMode(mUdfpsDisplayMode);
    }

    @Test
+132 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.biometrics;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecution;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
public class UdfpsDisplayModeTest extends SysuiTestCase {
    private static final int DISPLAY_ID = 0;

    @Mock
    private AuthController mAuthController;
    @Mock
    private IUdfpsHbmListener mDisplayCallback;
    @Mock
    private Runnable mOnEnabled;
    @Mock
    private Runnable mOnDisabled;

    private final FakeExecution mExecution = new FakeExecution();
    private UdfpsDisplayMode mHbmController;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        // Force mContext to always return DISPLAY_ID
        Context contextSpy = spy(mContext);
        when(contextSpy.getDisplayId()).thenReturn(DISPLAY_ID);

        // Set up mocks.
        when(mAuthController.getUdfpsHbmListener()).thenReturn(mDisplayCallback);

        // Create a real controller with mock dependencies.
        mHbmController = new UdfpsDisplayMode(contextSpy, mExecution, mAuthController);
    }

    @Test
    public void roundTrip() throws RemoteException {
        // Enable the UDFPS mode.
        mHbmController.enable(mOnEnabled);

        // Should set the appropriate refresh rate for UDFPS and notify the caller.
        verify(mDisplayCallback).onHbmEnabled(eq(DISPLAY_ID));
        verify(mOnEnabled).run();

        // Disable the UDFPS mode.
        mHbmController.disable(mOnDisabled);

        // Should unset the refresh rate and notify the caller.
        verify(mOnDisabled).run();
        verify(mDisplayCallback).onHbmDisabled(eq(DISPLAY_ID));
    }

    @Test
    public void mustNotEnableMoreThanOnce() throws RemoteException {
        // First request to enable the UDFPS mode.
        mHbmController.enable(mOnEnabled);

        // Should set the appropriate refresh rate for UDFPS and notify the caller.
        verify(mDisplayCallback).onHbmEnabled(eq(DISPLAY_ID));
        verify(mOnEnabled).run();

        // Second request to enable the UDFPS mode, while it's still enabled.
        mHbmController.enable(mOnEnabled);

        // Should ignore the second request.
        verifyNoMoreInteractions(mDisplayCallback);
        verifyNoMoreInteractions(mOnEnabled);
    }

    @Test
    public void mustNotDisableMoreThanOnce() throws RemoteException {
        // Disable the UDFPS mode.
        mHbmController.enable(mOnEnabled);

        // Should set the appropriate refresh rate for UDFPS and notify the caller.
        verify(mDisplayCallback).onHbmEnabled(eq(DISPLAY_ID));
        verify(mOnEnabled).run();

        // First request to disable the UDFPS mode.
        mHbmController.disable(mOnDisabled);

        // Should unset the refresh rate and notify the caller.
        verify(mOnDisabled).run();
        verify(mDisplayCallback).onHbmDisabled(eq(DISPLAY_ID));

        // Second request to disable the UDFPS mode, when it's already disabled.
        mHbmController.disable(mOnDisabled);

        // Should ignore the second request.
        verifyNoMoreInteractions(mOnDisabled);
        verifyNoMoreInteractions(mDisplayCallback);
    }
}