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

Commit b201643c authored by Automerger Merge Worker's avatar Automerger Merge Worker Committed by Android (Google) Code Review
Browse files

Merge "Merge "Add orientation listener to all biometric overlays." into sc-dev...

Merge "Merge "Add orientation listener to all biometric overlays." into sc-dev am: b1720128 am: 8b03c849" into sc-v2-dev-plus-aosp
parents fe279991 883d2f58
Loading
Loading
Loading
Loading
+14 −41
Original line number Original line Diff line number Diff line
@@ -48,10 +48,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.WindowManager;
import android.view.WindowManager;


import com.android.internal.R;
import com.android.internal.R;
@@ -72,6 +69,8 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Provider;


import kotlin.Unit;

/**
/**
 * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
 * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
 * appropriate biometric UI (e.g. BiometricDialogView).
 * appropriate biometric UI (e.g. BiometricDialogView).
@@ -107,7 +106,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
    TaskStackListener mTaskStackListener;
    TaskStackListener mTaskStackListener;
    @VisibleForTesting
    @VisibleForTesting
    IBiometricSysuiReceiver mReceiver;
    IBiometricSysuiReceiver mReceiver;
    @NonNull private final BiometricOrientationEventListener mOrientationListener;
    @VisibleForTesting
    @NonNull final BiometricOrientationEventListener mOrientationListener;
    @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
    @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
    @Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
    @Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
    @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
    @Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@@ -120,42 +120,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        }
        }
    }
    }


    private class BiometricOrientationEventListener extends OrientationEventListener {
        @Surface.Rotation private int mLastRotation;

        BiometricOrientationEventListener(Context context) {
            super(context);
            mLastRotation = context.getDisplay().getRotation();
        }

        @Override
        public void onOrientationChanged(int orientation) {
            if (orientation == ORIENTATION_UNKNOWN) {
                return;
            }

            final Display display = mContext.getDisplay();
            if (display == null) {
                return;
            }

            final int rotation = display.getRotation();
            if (mLastRotation != rotation) {
                mLastRotation = rotation;

                if (mCurrentDialog != null) {
                    mCurrentDialog.onOrientationChanged();
                }
                if (mUdfpsController != null) {
                    mUdfpsController.onOrientationChanged();
                }
                if (mSidefpsController != null) {
                    mSidefpsController.onOrientationChanged();
                }
            }
        }
    }

    @NonNull
    @NonNull
    private final IFingerprintAuthenticatorsRegisteredCallback
    private final IFingerprintAuthenticatorsRegisteredCallback
            mFingerprintAuthenticatorsRegisteredCallback =
            mFingerprintAuthenticatorsRegisteredCallback =
@@ -468,7 +432,10 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        mUdfpsControllerFactory = udfpsControllerFactory;
        mUdfpsControllerFactory = udfpsControllerFactory;
        mSidefpsControllerFactory = sidefpsControllerFactory;
        mSidefpsControllerFactory = sidefpsControllerFactory;
        mWindowManager = windowManager;
        mWindowManager = windowManager;
        mOrientationListener = new BiometricOrientationEventListener(context);
        mOrientationListener = new BiometricOrientationEventListener(context, () -> {
            onOrientationChanged();
            return Unit.INSTANCE;
        });


        mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
        mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;


@@ -790,6 +757,12 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
        }
        }
    }
    }


    private void onOrientationChanged() {
        if (mCurrentDialog != null) {
            mCurrentDialog.onOrientationChanged();
        }
    }

    protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
    protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
            int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
            int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
            boolean skipIntro, long operationId,
            boolean skipIntro, long operationId,
+60 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 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 android.content.Context
import android.view.OrientationEventListener

/**
 * An [OrientationEventListener] that invokes the [onOrientationChanged] callback whenever
 * the orientation of the device has changed in order to keep overlays for biometric sensors
 * aligned with the device's screen.
 */
class BiometricOrientationEventListener(
    private val context: Context,
    private val onOrientationChanged: () -> Unit
) : OrientationEventListener(context) {

    /** If actively listening (not available in base class). */
    var enabled: Boolean = false
        private set

    private var lastRotation = context.display?.rotation ?: ORIENTATION_UNKNOWN

    override fun onOrientationChanged(orientation: Int) {
        if (orientation == ORIENTATION_UNKNOWN) {
            return
        }

        val rotation = context.display?.rotation ?: return
        if (lastRotation != rotation) {
            lastRotation = rotation

            onOrientationChanged()
        }
    }

    override fun enable() {
        enabled = true
        super.enable()
    }

    override fun disable() {
        enabled = false
        super.disable()
    }
}
+15 −3
Original line number Original line Diff line number Diff line
@@ -41,6 +41,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor;


import javax.inject.Inject;
import javax.inject.Inject;


import kotlin.Unit;

/**
/**
 * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events.
 * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events.
 */
 */
@@ -52,6 +54,8 @@ public class SidefpsController {
    private final FingerprintManager mFingerprintManager;
    private final FingerprintManager mFingerprintManager;
    private final WindowManager mWindowManager;
    private final WindowManager mWindowManager;
    private final DelayableExecutor mFgExecutor;
    private final DelayableExecutor mFgExecutor;
    @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;

    // TODO: update mDisplayHeight and mDisplayWidth for multi-display devices
    // TODO: update mDisplayHeight and mDisplayWidth for multi-display devices
    private final int mDisplayHeight;
    private final int mDisplayHeight;
    private final int mDisplayWidth;
    private final int mDisplayWidth;
@@ -95,6 +99,10 @@ public class SidefpsController {
        mFingerprintManager = checkNotNull(fingerprintManager);
        mFingerprintManager = checkNotNull(fingerprintManager);
        mWindowManager = windowManager;
        mWindowManager = windowManager;
        mFgExecutor = fgExecutor;
        mFgExecutor = fgExecutor;
        mOrientationListener = new BiometricOrientationEventListener(context, () -> {
            onOrientationChanged();
            return Unit.INSTANCE;
        });


        mSensorProps = findFirstSidefps();
        mSensorProps = findFirstSidefps();
        checkArgument(mSensorProps != null);
        checkArgument(mSensorProps != null);
@@ -119,14 +127,15 @@ public class SidefpsController {
        mFingerprintManager.setSidefpsController(mSidefpsControllerImpl);
        mFingerprintManager.setSidefpsController(mSidefpsControllerImpl);
    }
    }


    void show() {
    private void show() {
        mView = (SidefpsView) mInflater.inflate(R.layout.sidefps_view, null, false);
        mView = (SidefpsView) mInflater.inflate(R.layout.sidefps_view, null, false);
        mView.setSensorProperties(mSensorProps);
        mView.setSensorProperties(mSensorProps);
        mWindowManager.addView(mView, computeLayoutParams());
        mWindowManager.addView(mView, computeLayoutParams());


        mOrientationListener.enable();
    }
    }


    void hide() {
    private void hide() {
        if (mView != null) {
        if (mView != null) {
            mWindowManager.removeView(mView);
            mWindowManager.removeView(mView);
            mView.setOnTouchListener(null);
            mView.setOnTouchListener(null);
@@ -135,13 +144,16 @@ public class SidefpsController {
        } else {
        } else {
            Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
            Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
        }
        }

        mOrientationListener.disable();
    }
    }


    void onOrientationChanged() {
    private void onOrientationChanged() {
        // If mView is null or if view is hidden, then return.
        // If mView is null or if view is hidden, then return.
        if (mView == null || !mIsVisible) {
        if (mView == null || !mIsVisible) {
            return;
            return;
        }
        }

        // If the overlay needs to be displayed with a new configuration, destroy the current
        // If the overlay needs to be displayed with a new configuration, destroy the current
        // overlay, and re-create and show the overlay with the updated LayoutParams.
        // overlay, and re-create and show the overlay with the updated LayoutParams.
        hide();
        hide();
+12 −1
Original line number Original line Diff line number Diff line
@@ -79,6 +79,8 @@ import java.util.Optional;


import javax.inject.Inject;
import javax.inject.Inject;


import kotlin.Unit;

/**
/**
 * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
 * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
 * and coordinates triggering of the high-brightness mode (HBM).
 * and coordinates triggering of the high-brightness mode (HBM).
@@ -118,6 +120,7 @@ public class UdfpsController implements DozeReceiver {
    @NonNull private final AccessibilityManager mAccessibilityManager;
    @NonNull private final AccessibilityManager mAccessibilityManager;
    @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
    @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
    @Nullable private final UdfpsHbmProvider mHbmProvider;
    @Nullable private final UdfpsHbmProvider mHbmProvider;
    @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
    // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
    // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
    // sensors, this, in addition to a lot of the code here, will be updated.
    // sensors, this, in addition to a lot of the code here, will be updated.
    @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
    @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -511,6 +514,10 @@ public class UdfpsController implements DozeReceiver {
        mHbmProvider = hbmProvider.orElse(null);
        mHbmProvider = hbmProvider.orElse(null);
        screenLifecycle.addObserver(mScreenObserver);
        screenLifecycle.addObserver(mScreenObserver);
        mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
        mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
        mOrientationListener = new BiometricOrientationEventListener(context, () -> {
            onOrientationChanged();
            return Unit.INSTANCE;
        });


        mSensorProps = findFirstUdfps();
        mSensorProps = findFirstUdfps();
        // At least one UDFPS sensor exists
        // At least one UDFPS sensor exists
@@ -650,7 +657,7 @@ public class UdfpsController implements DozeReceiver {
        return mCoreLayoutParams;
        return mCoreLayoutParams;
    }
    }


    void onOrientationChanged() {
    private void onOrientationChanged() {
        // When the configuration changes it's almost always necessary to destroy and re-create
        // When the configuration changes it's almost always necessary to destroy and re-create
        // the overlay's window to pass it the new LayoutParams.
        // the overlay's window to pass it the new LayoutParams.
        // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
        // Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
@@ -668,6 +675,7 @@ public class UdfpsController implements DozeReceiver {
        if (mView == null) {
        if (mView == null) {
            try {
            try {
                Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
                Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);

                mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
                mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
                mOnFingerDown = false;
                mOnFingerDown = false;
                mView.setSensorProperties(mSensorProps);
                mView.setSensorProperties(mSensorProps);
@@ -675,6 +683,7 @@ public class UdfpsController implements DozeReceiver {
                UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
                UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
                animation.init();
                animation.init();
                mView.setAnimationViewController(animation);
                mView.setAnimationViewController(animation);
                mOrientationListener.enable();


                // This view overlaps the sensor area, so prevent it from being selectable
                // This view overlaps the sensor area, so prevent it from being selectable
                // during a11y.
                // during a11y.
@@ -768,6 +777,8 @@ public class UdfpsController implements DozeReceiver {
        } else {
        } else {
            Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
            Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
        }
        }

        mOrientationListener.disable();
    }
    }


    /**
    /**
+15 −1
Original line number Original line Diff line number Diff line
@@ -20,7 +20,9 @@ import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;


import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;


import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -55,12 +57,13 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableContext;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.WindowManager;
import android.view.WindowManager;


import androidx.test.filters.SmallTest;

import com.android.internal.R;
import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue;
@@ -539,6 +542,17 @@ public class AuthControllerTest extends SysuiTestCase {
        verify(mUdfpsController).onAodInterrupt(eq(pos), eq(pos), eq(majorMinor), eq(majorMinor));
        verify(mUdfpsController).onAodInterrupt(eq(pos), eq(pos), eq(majorMinor), eq(majorMinor));
    }
    }


    @Test
    public void testSubscribesToOrientationChangesWhenShowingDialog() {
        assertFalse(mAuthController.mOrientationListener.getEnabled());

        showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
        assertTrue(mAuthController.mOrientationListener.getEnabled());

        mAuthController.hideAuthenticationDialog();
        assertFalse(mAuthController.mOrientationListener.getEnabled());
    }

    // Helpers
    // Helpers


    private void showDialog(int[] sensorIds, boolean credentialAllowed) {
    private void showDialog(int[] sensorIds, boolean credentialAllowed) {
Loading