summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--core/api/test-current.txt8
-rw-r--r--core/java/android/app/ForegroundServiceTypePolicy.java8
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java29
-rw-r--r--core/java/android/hardware/location/IContextHubService.aidl4
-rw-r--r--core/jni/android_hardware_display_DisplayViewport.cpp3
-rw-r--r--core/jni/android_view_MotionEvent.cpp7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java63
-rw-r--r--libs/hwui/hwui/BlurDrawLooper.cpp1
-rw-r--r--libs/hwui/jni/MaskFilter.cpp1
-rw-r--r--libs/input/MouseCursorController.cpp19
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt170
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt149
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt160
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt167
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt154
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt139
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt43
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt33
-rw-r--r--services/core/java/com/android/server/BootReceiver.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java51
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java47
-rw-r--r--services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp4
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java440
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java38
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java1
61 files changed, 1857 insertions, 567 deletions
diff --git a/Android.bp b/Android.bp
index cd55dcf999d8..c0a2abb02292 100644
--- a/Android.bp
+++ b/Android.bp
@@ -205,7 +205,7 @@ java_library {
"android.hardware.contexthub-V1.0-java",
"android.hardware.contexthub-V1.1-java",
"android.hardware.contexthub-V1.2-java",
- "android.hardware.contexthub-V1-java",
+ "android.hardware.contexthub-V2-java",
"android.hardware.gnss-V1.0-java",
"android.hardware.gnss-V2.1-java",
"android.hardware.health-V1.0-java-constants",
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 7d85fafe9e9c..002032ae10c3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1316,6 +1316,14 @@ package android.hardware.lights {
}
+package android.hardware.location {
+
+ public final class ContextHubManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public long[] getPreloadedNanoAppIds(@NonNull android.hardware.location.ContextHubInfo);
+ }
+
+}
+
package android.hardware.soundtrigger {
public class KeyphraseEnrollmentInfo {
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 63fdc2e1b686..332aaddef950 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -58,6 +58,7 @@ import android.hardware.usb.UsbManager;
import android.healthconnect.HealthConnectManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.permission.PermissionCheckerManager;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -880,11 +881,12 @@ public abstract class ForegroundServiceTypePolicy {
int checkPermission(@NonNull Context context, @NonNull String name, int callerUid,
int callerPid, String packageName, boolean allowWhileInUse) {
// Simple case, check if it's already granted.
- if (PermissionChecker.checkPermissionForPreflight(context, name,
- callerPid, callerUid, packageName) == PERMISSION_GRANTED) {
+ @PackageManager.PermissionResult int result;
+ if ((result = PermissionChecker.checkPermissionForPreflight(context, name,
+ callerPid, callerUid, packageName)) == PERMISSION_GRANTED) {
return PERMISSION_GRANTED;
}
- if (allowWhileInUse) {
+ if (allowWhileInUse && result == PermissionCheckerManager.PERMISSION_SOFT_DENIED) {
// Check its appops
final int opCode = AppOpsManager.permissionToOpCode(name);
final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index b54da6c6eaea..ac23af4396de 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -24,6 +24,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.PendingIntent;
import android.content.Context;
@@ -966,6 +967,34 @@ public final class ContextHubManager {
}
/**
+ * Queries for the list of preloaded nanoapp IDs on the system.
+ *
+ * @param hubInfo The Context Hub to query a list of nanoapp IDs from.
+ *
+ * @return The list of 64-bit IDs of the preloaded nanoapps.
+ *
+ * @throws NullPointerException if hubInfo is null
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ @NonNull public long[] getPreloadedNanoAppIds(@NonNull ContextHubInfo hubInfo) {
+ Objects.requireNonNull(hubInfo, "hubInfo cannot be null");
+
+ long[] nanoappIds = null;
+ try {
+ nanoappIds = mService.getPreloadedNanoAppIds(hubInfo);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ if (nanoappIds == null) {
+ nanoappIds = new long[0];
+ }
+ return nanoappIds;
+ }
+
+ /**
* Unregister a callback for receive messages from the context hub.
*
* @see Callback
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index ced75c4d0247..490267f36b7d 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -109,4 +109,8 @@ interface IContextHubService {
// Queries for a list of nanoapps
@EnforcePermission("ACCESS_CONTEXT_HUB")
void queryNanoApps(int contextHubId, in IContextHubTransactionCallback transactionCallback);
+
+ // Queries for a list of preloaded nanoapps
+ @EnforcePermission("ACCESS_CONTEXT_HUB")
+ long[] getPreloadedNanoAppIds(in ContextHubInfo hubInfo);
}
diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp
index 03432e9ce746..7f630cb27972 100644
--- a/core/jni/android_hardware_display_DisplayViewport.cpp
+++ b/core/jni/android_hardware_display_DisplayViewport.cpp
@@ -61,7 +61,8 @@ status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject
viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId);
viewport->isActive = env->GetBooleanField(viewportObj, gDisplayViewportClassInfo.isActive);
- viewport->orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
+ jint orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
+ viewport->orientation = static_cast<ui::Rotation>(orientation);
viewport->deviceWidth = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceWidth);
viewport->deviceHeight = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceHeight);
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 80df0ead4bcd..403c5836d9dd 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -763,7 +763,12 @@ static void android_view_MotionEvent_nativeScale(jlong nativePtr, jfloat scale)
static jint android_view_MotionEvent_nativeGetSurfaceRotation(jlong nativePtr) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return jint(event->getSurfaceRotation());
+ auto rotation = event->getSurfaceRotation();
+ if (rotation) {
+ return static_cast<jint>(rotation.value());
+ } else {
+ return -1;
+ }
}
// ----------------------------------------------------------------------------
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 17d7f5d0d567..5376ae372de2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -97,6 +97,8 @@ public class PipBoundsState {
private int mShelfHeight;
/** Whether the user has resized the PIP manually. */
private boolean mHasUserResizedPip;
+ /** Whether the user has moved the PIP manually. */
+ private boolean mHasUserMovedPip;
/**
* Areas defined by currently visible apps that they prefer to keep clear from overlays such as
* the PiP. Restricted areas may only move the PiP a limited amount from its anchor position.
@@ -279,6 +281,7 @@ public class PipBoundsState {
if (changed) {
clearReentryState();
setHasUserResizedPip(false);
+ setHasUserMovedPip(false);
}
}
@@ -442,6 +445,16 @@ public class PipBoundsState {
mHasUserResizedPip = hasUserResizedPip;
}
+ /** Returns whether the user has moved the PIP. */
+ public boolean hasUserMovedPip() {
+ return mHasUserMovedPip;
+ }
+
+ /** Set whether the user has moved the PIP. */
+ public void setHasUserMovedPip(boolean hasUserMovedPip) {
+ mHasUserMovedPip = hasUserMovedPip;
+ }
+
/**
* Registers a callback when the minimal size of PIP that is set by the app changes.
*/
@@ -577,6 +590,8 @@ public class PipBoundsState {
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
+ pw.println(innerPrefix + "mHasUserMovedPip=" + mHasUserMovedPip);
+ pw.println(innerPrefix + "mHasUserResizedPip=" + mHasUserResizedPip);
if (mPipReentryState == null) {
pw.println(innerPrefix + "mPipReentryState=null");
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index 84071e08d472..690505e03fce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.pip.phone;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.SystemProperties;
import android.util.ArraySet;
import android.view.Gravity;
@@ -34,6 +35,10 @@ import java.util.Set;
*/
public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
+ private boolean mKeepClearAreaGravityEnabled =
+ SystemProperties.getBoolean(
+ "persist.wm.debug.enable_pip_keep_clear_algorithm_gravity", false);
+
protected int mKeepClearAreasPadding;
public PhonePipKeepClearAlgorithm(Context context) {
@@ -53,31 +58,36 @@ public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
Rect startingBounds = pipBoundsState.getBounds().isEmpty()
? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
: pipBoundsState.getBounds();
- float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
- int verticalGravity = Gravity.BOTTOM;
- int horizontalGravity;
- if (snapFraction >= 0.5f && snapFraction < 2.5f) {
- horizontalGravity = Gravity.RIGHT;
- } else {
- horizontalGravity = Gravity.LEFT;
- }
- // push the bounds based on the gravity
Rect insets = new Rect();
pipBoundsAlgorithm.getInsetBounds(insets);
if (pipBoundsState.isImeShowing()) {
insets.bottom -= pipBoundsState.getImeHeight();
}
- Rect pushedBounds = new Rect(startingBounds);
- if (verticalGravity == Gravity.BOTTOM) {
- pushedBounds.offsetTo(pushedBounds.left,
- insets.bottom - pushedBounds.height());
- }
- if (horizontalGravity == Gravity.RIGHT) {
- pushedBounds.offsetTo(insets.right - pushedBounds.width(), pushedBounds.top);
- } else {
- pushedBounds.offsetTo(insets.left, pushedBounds.top);
+ Rect pipBounds = new Rect(startingBounds);
+
+ // move PiP towards corner if user hasn't moved it manually or the flag is on
+ if (mKeepClearAreaGravityEnabled
+ || (!pipBoundsState.hasUserMovedPip() && !pipBoundsState.hasUserResizedPip())) {
+ float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
+ int verticalGravity = Gravity.BOTTOM;
+ int horizontalGravity;
+ if (snapFraction >= 0.5f && snapFraction < 2.5f) {
+ horizontalGravity = Gravity.RIGHT;
+ } else {
+ horizontalGravity = Gravity.LEFT;
+ }
+ if (verticalGravity == Gravity.BOTTOM) {
+ pipBounds.offsetTo(pipBounds.left,
+ insets.bottom - pipBounds.height());
+ }
+ if (horizontalGravity == Gravity.RIGHT) {
+ pipBounds.offsetTo(insets.right - pipBounds.width(), pipBounds.top);
+ } else {
+ pipBounds.offsetTo(insets.left, pipBounds.top);
+ }
}
- return findUnoccludedPosition(pushedBounds, pipBoundsState.getRestrictedKeepClearAreas(),
+
+ return findUnoccludedPosition(pipBounds, pipBoundsState.getRestrictedKeepClearAreas(),
pipBoundsState.getUnrestrictedKeepClearAreas(), insets);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index a9a97beb9180..83bc7c0e6e7d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -875,6 +875,8 @@ public class PipTouchHandler {
}
if (touchState.isDragging()) {
+ mPipBoundsState.setHasUserMovedPip(true);
+
// Move the pinned stack freely
final PointF lastDelta = touchState.getLastTouchDelta();
float lastX = mStartPosition.x + mDelta.x;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 7ecb3f3f6355..92154968855f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -251,7 +251,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
}
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
- final int captionWidth = loadDimensionPixelSize(resources, params.mCaptionWidthId);
+ final int captionWidth = params.mCaptionWidthId == Resources.ID_NULL
+ ? taskBounds.width()
+ : loadDimensionPixelSize(resources, params.mCaptionWidthId);
startT.setPosition(
mCaptionContainerSurface,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 15181b1549f5..dd9ab9899e13 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -113,6 +113,12 @@ public class WindowDecorationTests extends ShellTestCase {
mMockSurfaceControlFinishT = createMockSurfaceControlTransaction();
mMockSurfaceControlAddWindowT = createMockSurfaceControlTransaction();
+ mRelayoutParams.mLayoutResId = 0;
+ mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
+ // Caption should have fixed width except in testLayoutResultCalculation_fullWidthCaption()
+ mRelayoutParams.mCaptionWidthId = R.dimen.test_freeform_decor_caption_width;
+ mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
+
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
.create(any(), any(), any());
}
@@ -435,6 +441,58 @@ public class WindowDecorationTests extends ShellTestCase {
assertThat(additionalWindow.mWindowSurface).isNull();
}
+ @Test
+ public void testLayoutResultCalculation_fullWidthCaption() {
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+
+ final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder decorContainerSurfaceBuilder =
+ createMockSurfaceControlBuilder(decorContainerSurface);
+ mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
+ final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
+ createMockSurfaceControlBuilder(taskBackgroundSurface);
+ mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);
+ final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder captionContainerSurfaceBuilder =
+ createMockSurfaceControlBuilder(captionContainerSurface);
+ mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mMockSurfaceControlTransactions.add(t);
+ final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+ new ActivityManager.TaskDescription.Builder()
+ .setBackgroundColor(Color.YELLOW);
+ final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .setTaskDescriptionBuilder(taskDescriptionBuilder)
+ .setBounds(TASK_BOUNDS)
+ .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
+ .setVisible(true)
+ .build();
+ taskInfo.isFocused = true;
+ taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
+ mRelayoutParams.setOutsets(
+ R.dimen.test_window_decor_left_outset,
+ R.dimen.test_window_decor_top_outset,
+ R.dimen.test_window_decor_right_outset,
+ R.dimen.test_window_decor_bottom_outset);
+ final SurfaceControl taskSurface = mock(SurfaceControl.class);
+ final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+ mRelayoutParams.mCaptionWidthId = Resources.ID_NULL;
+ windowDecor.relayout(taskInfo);
+
+ verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
+ verify(captionContainerSurfaceBuilder).setContainerLayer();
+ verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
+ // Width of the captionContainerSurface should match the width of TASK_BOUNDS
+ verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
+ verify(mMockSurfaceControlStartT).show(captionContainerSurface);
+ }
+
private TestWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
return new TestWindowDecoration(InstrumentationRegistry.getInstrumentation().getContext(),
@@ -490,11 +548,6 @@ public class WindowDecorationTests extends ShellTestCase {
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
- mRelayoutParams.mLayoutResId = 0;
- mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
- mRelayoutParams.mCaptionWidthId = R.dimen.test_freeform_decor_caption_width;
- mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
-
relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
mMockWindowContainerTransaction, mMockView, mRelayoutResult);
}
diff --git a/libs/hwui/hwui/BlurDrawLooper.cpp b/libs/hwui/hwui/BlurDrawLooper.cpp
index d4b0198d015d..8b52551fc107 100644
--- a/libs/hwui/hwui/BlurDrawLooper.cpp
+++ b/libs/hwui/hwui/BlurDrawLooper.cpp
@@ -15,6 +15,7 @@
*/
#include "BlurDrawLooper.h"
+#include <SkBlurTypes.h>
#include <SkColorSpace.h>
#include <SkMaskFilter.h>
diff --git a/libs/hwui/jni/MaskFilter.cpp b/libs/hwui/jni/MaskFilter.cpp
index 5383032e0f77..048ce025ce27 100644
--- a/libs/hwui/jni/MaskFilter.cpp
+++ b/libs/hwui/jni/MaskFilter.cpp
@@ -2,6 +2,7 @@
#include "SkMaskFilter.h"
#include "SkBlurMask.h"
#include "SkBlurMaskFilter.h"
+#include "SkBlurTypes.h"
#include "SkTableMaskFilter.h"
static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 0e7b7ff4319d..a83516791f33 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -199,8 +199,7 @@ static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, i
width = viewport.deviceWidth;
height = viewport.deviceHeight;
- if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
- viewport.orientation == DISPLAY_ORIENTATION_270) {
+ if (viewport.orientation == ui::ROTATION_90 || viewport.orientation == ui::ROTATION_270) {
std::swap(width, height);
}
}
@@ -244,38 +243,42 @@ void MouseCursorController::setDisplayViewport(const DisplayViewport& viewport,
// Undo the previous rotation.
switch (oldViewport.orientation) {
- case DISPLAY_ORIENTATION_90:
+ case ui::ROTATION_90:
temp = x;
x = oldViewport.deviceHeight - y;
y = temp;
break;
- case DISPLAY_ORIENTATION_180:
+ case ui::ROTATION_180:
x = oldViewport.deviceWidth - x;
y = oldViewport.deviceHeight - y;
break;
- case DISPLAY_ORIENTATION_270:
+ case ui::ROTATION_270:
temp = x;
x = y;
y = oldViewport.deviceWidth - temp;
break;
+ case ui::ROTATION_0:
+ break;
}
// Perform the new rotation.
switch (viewport.orientation) {
- case DISPLAY_ORIENTATION_90:
+ case ui::ROTATION_90:
temp = x;
x = y;
y = viewport.deviceHeight - temp;
break;
- case DISPLAY_ORIENTATION_180:
+ case ui::ROTATION_180:
x = viewport.deviceWidth - x;
y = viewport.deviceHeight - y;
break;
- case DISPLAY_ORIENTATION_270:
+ case ui::ROTATION_270:
temp = x;
x = viewport.deviceWidth - y;
y = temp;
break;
+ case ui::ROTATION_0:
+ break;
}
// Apply offsets to convert from the pixel center to the pixel top-left corner position
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
index 43bfa74119b3..0e2d23b04a4f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
@@ -195,8 +195,16 @@ class RemoteTransitionAdapter {
val out = ArrayList<RemoteAnimationTarget>()
for (i in info.changes.indices) {
val change = info.changes[i]
- val changeIsWallpaper = change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0
- if (wallpapers != changeIsWallpaper) continue
+ if (change.hasFlags(TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
+ // For embedded container, when the parent Task is also in the transition, we
+ // should only animate the parent Task.
+ if (change.parent != null) continue
+ // For embedded container without parent, we should only animate if it fills
+ // the Task. Otherwise we may animate only partial of the Task.
+ if (!change.hasFlags(TransitionInfo.FLAG_FILLS_TASK)) continue
+ }
+ // Check if it is wallpaper
+ if (wallpapers != change.hasFlags(TransitionInfo.FLAG_IS_WALLPAPER)) continue
out.add(createTarget(change, info.changes.size - i, info, t))
if (leashMap != null) {
leashMap[change.leash] = out[out.size - 1].leash
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a7519cf713d5..db2239b7e680 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -623,6 +623,10 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
getFingerprintSensorLocationInNaturalOrientation(),
mCachedDisplayInfo);
}
+
+ for (final Callback cb : mCallbacks) {
+ cb.onFingerprintLocationChanged();
+ }
}
/**
@@ -644,6 +648,10 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
mCachedDisplayInfo
);
}
+
+ for (final Callback cb : mCallbacks) {
+ cb.onFaceSensorLocationChanged();
+ }
}
/**
@@ -1325,8 +1333,24 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
default void onBiometricPromptDismissed() {}
/**
- * The location in pixels can change due to resolution changes.
+ * Called when the location of the fingerprint sensor changes. The location in pixels can
+ * change due to resolution changes.
+ */
+ default void onFingerprintLocationChanged() {}
+
+ /**
+ * Called when the location of the under display fingerprint sensor changes. The location in
+ * pixels can change due to resolution changes.
+ *
+ * On devices with UDFPS, this is always called alongside
+ * {@link #onFingerprintLocationChanged}.
*/
default void onUdfpsLocationChanged() {}
+
+ /**
+ * Called when the location of the face unlock sensor (typically the front facing camera)
+ * changes. The location in pixels can change due to resolution changes.
+ */
+ default void onFaceSensorLocationChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 6ac54feeb935..d561cd7af7f0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -29,6 +29,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.CircleReveal
@@ -71,7 +73,8 @@ class AuthRippleController @Inject constructor(
private val biometricUnlockController: BiometricUnlockController,
private val udfpsControllerProvider: Provider<UdfpsController>,
private val statusBarStateController: StatusBarStateController,
- rippleView: AuthRippleView?
+ private val featureFlags: FeatureFlags,
+ rippleView: AuthRippleView?
) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
WakefulnessLifecycle.Observer {
@@ -159,12 +162,17 @@ class AuthRippleController @Inject constructor(
private fun showUnlockedRipple() {
notificationShadeWindowController.setForcePluginOpen(true, this)
- val lightRevealScrim = centralSurfaces.lightRevealScrim
- if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) {
- circleReveal?.let {
- lightRevealScrim?.revealAmount = 0f
- lightRevealScrim?.revealEffect = it
- startLightRevealScrimOnKeyguardFadingAway = true
+
+ // This code path is not used if the KeyguardTransitionRepository is managing the light
+ // reveal scrim.
+ if (!featureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+ val lightRevealScrim = centralSurfaces.lightRevealScrim
+ if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) {
+ circleReveal?.let {
+ lightRevealScrim?.revealAmount = 0f
+ lightRevealScrim?.revealEffect = it
+ startLightRevealScrimOnKeyguardFadingAway = true
+ }
}
}
@@ -177,6 +185,10 @@ class AuthRippleController @Inject constructor(
}
override fun onKeyguardFadingAwayChanged() {
+ if (featureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+ return
+ }
+
if (keyguardStateController.isKeyguardFadingAway) {
val lightRevealScrim = centralSurfaces.lightRevealScrim
if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 1c3dd451a1d3..ed214302fdec 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -135,7 +135,7 @@ constructor(
WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
PixelFormat.TRANSLUCENT
)
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 7d9fdfa225de..8019b569068a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -164,6 +164,13 @@ object Flags {
// TODO(b/256513609): Tracking Bug
@JvmField val ACTIVE_UNLOCK_CHIPBAR = releasedFlag(217, "active_unlock_chipbar")
+ /**
+ * Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
+ * new KeyguardTransitionRepository.
+ */
+ @JvmField
+ val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = true)
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 796f2b44effc..148792ba779b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -16,8 +16,11 @@
package com.android.systemui.keyguard.data.repository
+import android.graphics.Point
+import android.hardware.biometrics.BiometricSourceType
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.Position
@@ -27,8 +30,8 @@ import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback
import com.android.systemui.doze.DozeTransitionListener
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -88,8 +91,8 @@ interface KeyguardRepository {
* enter to conserve battery when the device is locked and inactive.
*
* Note that it is possible for the system to be transitioning into doze while this flow still
- * returns `false`. In order to account for that, observers should also use the [dozeAmount]
- * flow to check if it's greater than `0`
+ * returns `false`. In order to account for that, observers should also use the
+ * [linearDozeAmount] flow to check if it's greater than `0`
*/
val isDozing: Flow<Boolean>
@@ -111,7 +114,7 @@ interface KeyguardRepository {
* happens during an animation/transition into doze mode. An observer would be wise to account
* for both flows if needed.
*/
- val dozeAmount: Flow<Float>
+ val linearDozeAmount: Flow<Float>
/** Doze state information, as it transitions */
val dozeTransitionModel: Flow<DozeTransitionModel>
@@ -120,11 +123,20 @@ interface KeyguardRepository {
val statusBarState: Flow<StatusBarState>
/** Observable for device wake/sleep state */
- val wakefulnessState: Flow<WakefulnessModel>
+ val wakefulness: Flow<WakefulnessModel>
/** Observable for biometric unlock modes */
val biometricUnlockState: Flow<BiometricUnlockModel>
+ /** Approximate location on the screen of the fingerprint sensor. */
+ val fingerprintSensorLocation: Flow<Point?>
+
+ /** Approximate location on the screen of the face unlock sensor/front facing camera. */
+ val faceSensorLocation: Flow<Point?>
+
+ /** Source of the most recent biometric unlock, such as fingerprint or face. */
+ val biometricUnlockSource: Flow<BiometricUnlockSource?>
+
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -163,6 +175,7 @@ constructor(
private val keyguardStateController: KeyguardStateController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val dozeTransitionListener: DozeTransitionListener,
+ private val authController: AuthController,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -281,11 +294,11 @@ constructor(
}
.distinctUntilChanged()
- override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
+ override val linearDozeAmount: Flow<Float> = conflatedCallbackFlow {
val callback =
object : StatusBarStateController.StateListener {
override fun onDozeAmountChanged(linear: Float, eased: Float) {
- trySendWithFailureLogging(eased, TAG, "updated dozeAmount")
+ trySendWithFailureLogging(linear, TAG, "updated dozeAmount")
}
}
@@ -348,56 +361,137 @@ constructor(
awaitClose { statusBarStateController.removeCallback(callback) }
}
- override val wakefulnessState: Flow<WakefulnessModel> = conflatedCallbackFlow {
+ override val biometricUnlockState: Flow<BiometricUnlockModel> = conflatedCallbackFlow {
+ fun dispatchUpdate() {
+ trySendWithFailureLogging(
+ biometricModeIntToObject(biometricUnlockController.mode),
+ TAG,
+ "biometric mode"
+ )
+ }
+
val callback =
+ object : BiometricUnlockController.BiometricModeListener {
+ override fun onModeChanged(@WakeAndUnlockMode mode: Int) {
+ dispatchUpdate()
+ }
+
+ override fun onResetMode() {
+ dispatchUpdate()
+ }
+ }
+
+ biometricUnlockController.addBiometricModeListener(callback)
+ dispatchUpdate()
+
+ awaitClose { biometricUnlockController.removeBiometricModeListener(callback) }
+ }
+
+ override val wakefulness: Flow<WakefulnessModel> = conflatedCallbackFlow {
+ val observer =
object : WakefulnessLifecycle.Observer {
override fun onStartedWakingUp() {
- trySendWithFailureLogging(
- WakefulnessModel.STARTING_TO_WAKE,
- TAG,
- "Wakefulness: starting to wake"
- )
+ dispatchNewState()
}
+
override fun onFinishedWakingUp() {
- trySendWithFailureLogging(WakefulnessModel.AWAKE, TAG, "Wakefulness: awake")
+ dispatchNewState()
+ }
+
+ override fun onPostFinishedWakingUp() {
+ dispatchNewState()
}
+
override fun onStartedGoingToSleep() {
+ dispatchNewState()
+ }
+
+ override fun onFinishedGoingToSleep() {
+ dispatchNewState()
+ }
+
+ private fun dispatchNewState() {
trySendWithFailureLogging(
- WakefulnessModel.STARTING_TO_SLEEP,
+ WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
TAG,
- "Wakefulness: starting to sleep"
+ "updated wakefulness state"
)
}
- override fun onFinishedGoingToSleep() {
- trySendWithFailureLogging(WakefulnessModel.ASLEEP, TAG, "Wakefulness: asleep")
- }
}
- wakefulnessLifecycle.addObserver(callback)
+
+ wakefulnessLifecycle.addObserver(observer)
trySendWithFailureLogging(
- wakefulnessIntToObject(wakefulnessLifecycle.getWakefulness()),
+ WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
TAG,
"initial wakefulness state"
)
- awaitClose { wakefulnessLifecycle.removeObserver(callback) }
+ awaitClose { wakefulnessLifecycle.removeObserver(observer) }
}
- override val biometricUnlockState: Flow<BiometricUnlockModel> = conflatedCallbackFlow {
+ override val fingerprintSensorLocation: Flow<Point?> = conflatedCallbackFlow {
+ fun sendFpLocation() {
+ trySendWithFailureLogging(
+ authController.fingerprintSensorLocation,
+ TAG,
+ "AuthController.Callback#onFingerprintLocationChanged"
+ )
+ }
+
val callback =
- object : BiometricUnlockController.BiometricModeListener {
- override fun onModeChanged(@WakeAndUnlockMode mode: Int) {
- trySendWithFailureLogging(biometricModeIntToObject(mode), TAG, "biometric mode")
+ object : AuthController.Callback {
+ override fun onFingerprintLocationChanged() {
+ sendFpLocation()
}
}
- biometricUnlockController.addBiometricModeListener(callback)
- trySendWithFailureLogging(
- biometricModeIntToObject(biometricUnlockController.getMode()),
- TAG,
- "initial biometric mode"
- )
+ authController.addCallback(callback)
+ sendFpLocation()
- awaitClose { biometricUnlockController.removeBiometricModeListener(callback) }
+ awaitClose { authController.removeCallback(callback) }
+ }
+
+ override val faceSensorLocation: Flow<Point?> = conflatedCallbackFlow {
+ fun sendSensorLocation() {
+ trySendWithFailureLogging(
+ authController.faceSensorLocation,
+ TAG,
+ "AuthController.Callback#onFingerprintLocationChanged"
+ )
+ }
+
+ val callback =
+ object : AuthController.Callback {
+ override fun onFaceSensorLocationChanged() {
+ sendSensorLocation()
+ }
+ }
+
+ authController.addCallback(callback)
+ sendSensorLocation()
+
+ awaitClose { authController.removeCallback(callback) }
+ }
+
+ override val biometricUnlockSource: Flow<BiometricUnlockSource?> = conflatedCallbackFlow {
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricAuthenticated(
+ userId: Int,
+ biometricSourceType: BiometricSourceType?,
+ isStrongBiometric: Boolean
+ ) {
+ trySendWithFailureLogging(
+ BiometricUnlockSource.fromBiometricSourceType(biometricSourceType),
+ TAG,
+ "onBiometricAuthenticated"
+ )
+ }
+ }
+
+ keyguardUpdateMonitor.registerCallback(callback)
+ trySendWithFailureLogging(null, TAG, "initial value")
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
override fun setAnimateDozingTransitions(animate: Boolean) {
@@ -423,16 +517,6 @@ constructor(
}
}
- private fun wakefulnessIntToObject(@Wakefulness value: Int): WakefulnessModel {
- return when (value) {
- 0 -> WakefulnessModel.ASLEEP
- 1 -> WakefulnessModel.STARTING_TO_WAKE
- 2 -> WakefulnessModel.AWAKE
- 3 -> WakefulnessModel.STARTING_TO_SLEEP
- else -> throw IllegalArgumentException("Invalid Wakefulness value: $value")
- }
- }
-
private fun biometricModeIntToObject(@WakeAndUnlockMode value: Int): BiometricUnlockModel {
return when (value) {
0 -> BiometricUnlockModel.NONE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 0c725208e22d..26f853f3ad1c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -27,4 +27,7 @@ interface KeyguardRepositoryModule {
fun keyguardTransitionRepository(
impl: KeyguardTransitionRepositoryImpl
): KeyguardTransitionRepository
+
+ @Binds
+ fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
new file mode 100644
index 000000000000..a17481a9978b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.keyguard.data.repository
+
+import android.content.Context
+import android.graphics.Point
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.statusbar.CircleReveal
+import com.android.systemui.statusbar.LiftReveal
+import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.statusbar.PowerButtonReveal
+import javax.inject.Inject
+import kotlin.math.max
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+val DEFAULT_REVEAL_EFFECT = LiftReveal
+
+/**
+ * Encapsulates state relevant to the light reveal scrim, the view used to reveal/hide screen
+ * contents during transitions between AOD and lockscreen/unlocked.
+ */
+interface LightRevealScrimRepository {
+
+ /**
+ * The reveal effect that should be used for the next lock/unlock. We switch between either the
+ * biometric unlock effect (if wake and unlocking) or the non-biometric effect, and position it
+ * at the current screen position of the appropriate sensor.
+ */
+ val revealEffect: Flow<LightRevealEffect>
+}
+
+@SysUISingleton
+class LightRevealScrimRepositoryImpl
+@Inject
+constructor(
+ keyguardRepository: KeyguardRepository,
+ val context: Context,
+) : LightRevealScrimRepository {
+
+ /** The reveal effect used if the device was locked/unlocked via the power button. */
+ private val powerButtonReveal =
+ PowerButtonReveal(
+ context.resources
+ .getDimensionPixelSize(R.dimen.physical_power_button_center_screen_location_y)
+ .toFloat()
+ )
+
+ /**
+ * Reveal effect to use for a fingerprint unlock. This is reconstructed if the fingerprint
+ * sensor location on the screen (in pixels) changes due to configuration changes.
+ */
+ private val fingerprintRevealEffect: Flow<LightRevealEffect?> =
+ keyguardRepository.fingerprintSensorLocation.map {
+ it?.let { constructCircleRevealFromPoint(it) }
+ }
+
+ /**
+ * Reveal effect to use for a face unlock. This is reconstructed if the face sensor/front camera
+ * location on the screen (in pixels) changes due to configuration changes.
+ */
+ private val faceRevealEffect: Flow<LightRevealEffect?> =
+ keyguardRepository.faceSensorLocation.map { it?.let { constructCircleRevealFromPoint(it) } }
+
+ /**
+ * The reveal effect we'll use for the next biometric unlock animation. We switch between the
+ * fingerprint/face unlock effect flows depending on the biometric unlock source.
+ */
+ private val biometricRevealEffect: Flow<LightRevealEffect?> =
+ keyguardRepository.biometricUnlockSource.flatMapLatest { source ->
+ when (source) {
+ BiometricUnlockSource.FINGERPRINT_SENSOR -> fingerprintRevealEffect
+ BiometricUnlockSource.FACE_SENSOR -> faceRevealEffect
+ else -> flowOf(null)
+ }
+ }
+
+ /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */
+ private val nonBiometricRevealEffect: Flow<LightRevealEffect?> =
+ keyguardRepository.wakefulness.map { wakefulnessModel ->
+ val wakingUpFromPowerButton =
+ wakefulnessModel.isWakingUpOrAwake &&
+ wakefulnessModel.lastWakeReason == WakeSleepReason.POWER_BUTTON
+ val sleepingFromPowerButton =
+ !wakefulnessModel.isWakingUpOrAwake &&
+ wakefulnessModel.lastSleepReason == WakeSleepReason.POWER_BUTTON
+
+ if (wakingUpFromPowerButton || sleepingFromPowerButton) {
+ powerButtonReveal
+ } else {
+ LiftReveal
+ }
+ }
+
+ override val revealEffect =
+ combine(
+ keyguardRepository.biometricUnlockState,
+ biometricRevealEffect,
+ nonBiometricRevealEffect
+ ) { biometricUnlockState, biometricReveal, nonBiometricReveal ->
+
+ // Use the biometric reveal for any flavor of wake and unlocking.
+ when (biometricUnlockState) {
+ BiometricUnlockModel.WAKE_AND_UNLOCK,
+ BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING,
+ BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM -> biometricReveal
+ else -> nonBiometricReveal
+ }
+ ?: DEFAULT_REVEAL_EFFECT
+ }
+ .distinctUntilChanged()
+
+ private fun constructCircleRevealFromPoint(point: Point): LightRevealEffect {
+ return with(point) {
+ CircleReveal(
+ x,
+ y,
+ startRadius = 0,
+ endRadius =
+ max(max(x, context.display.width - x), max(y, context.display.height - y)),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
index 2dbacd5d3c69..9b193533805e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
@@ -27,7 +27,6 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
index 9e2b7241ade2..e34981eabcac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
@@ -42,7 +42,7 @@ constructor(
override fun start() {
scope.launch {
- keyguardInteractor.wakefulnessState
+ keyguardInteractor.wakefulnessModel
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
.collect { pair ->
val (wakefulnessState, keyguardState) = pair
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
index 0e2a54c57bdb..483041a1b236 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
@@ -23,11 +23,10 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
-import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@SysUISingleton
@@ -42,13 +41,13 @@ constructor(
override fun start() {
scope.launch {
- keyguardInteractor.wakefulnessState
+ keyguardInteractor.wakefulnessModel
.sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
.collect { pair ->
val (wakefulnessState, keyguardState) = pair
if (
keyguardState == KeyguardState.GONE &&
- wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP
+ wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 7cfd117d8eb4..6912e1d3558e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
+import android.graphics.Point
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
@@ -41,7 +42,7 @@ constructor(
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
* all.
*/
- val dozeAmount: Flow<Float> = repository.dozeAmount
+ val dozeAmount: Flow<Float> = repository.linearDozeAmount
/** Whether the system is in doze mode. */
val isDozing: Flow<Boolean> = repository.isDozing
/** Doze transition information. */
@@ -58,7 +59,7 @@ constructor(
/** Whether the bouncer is showing or not. */
val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
/** The device wake/sleep state */
- val wakefulnessState: Flow<WakefulnessModel> = repository.wakefulnessState
+ val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
/** Observable for the [StatusBarState] */
val statusBarState: Flow<StatusBarState> = repository.statusBarState
/**
@@ -67,10 +68,15 @@ constructor(
*/
val biometricUnlockState: Flow<BiometricUnlockModel> = repository.biometricUnlockState
+ /** The approximate location on the screen of the fingerprint sensor, if one is available. */
+ val fingerprintSensorLocation: Flow<Point?> = repository.fingerprintSensorLocation
+
+ /** The approximate location on the screen of the face unlock sensor, if one is available. */
+ val faceSensorLocation: Flow<Point?> = repository.faceSensorLocation
+
fun dozeTransitionTo(state: DozeStateModel): Flow<DozeTransitionModel> {
return dozeTransitionModel.filter { it.to == state }
}
-
fun isKeyguardShowing(): Boolean {
return repository.isKeyguardShowing()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 58a8093d49d2..e30e7f6ece11 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -37,7 +37,7 @@ constructor(
fun start() {
scope.launch {
- keyguardInteractor.wakefulnessState.collect { logger.v("WakefulnessState", it) }
+ keyguardInteractor.wakefulnessModel.collect { logger.v("WakefulnessModel", it) }
}
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
new file mode 100644
index 000000000000..6e25200bc2f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class LightRevealScrimInteractor
+@Inject
+constructor(
+ transitionRepository: KeyguardTransitionRepository,
+ transitionInteractor: KeyguardTransitionInteractor,
+ lightRevealScrimRepository: LightRevealScrimRepository,
+) {
+
+ /**
+ * Whenever a keyguard transition starts, sample the latest reveal effect from the repository
+ * and use that for the starting transition.
+ *
+ * We can't simply use the nextRevealEffect since the effect may change midway through a
+ * transition, but we don't want to change effects part way through. For example, if we're using
+ * a CircleReveal to animate a biometric unlock, but the biometric unlock mode changes to NONE
+ * from WAKE_AND_UNLOCK before the unlock animation ends, we don't want to end up switching to a
+ * LiftReveal.
+ */
+ val lightRevealEffect: Flow<LightRevealEffect> =
+ transitionInteractor.startedKeyguardTransitionStep.sample(
+ lightRevealScrimRepository.revealEffect
+ )
+
+ /**
+ * The reveal amount to use for the light reveal scrim, which is derived from the keyguard
+ * transition steps.
+ */
+ val revealAmount: Flow<Float> =
+ transitionRepository.transitions
+ // Only listen to transitions that change the reveal amount.
+ .filter { willTransitionAffectRevealAmount(it) }
+ // Use the transition amount as the reveal amount, inverting it if we're transitioning
+ // to a non-revealed (hidden) state.
+ .map { step -> if (willBeRevealedInState(step.to)) step.value else 1f - step.value }
+
+ companion object {
+
+ /**
+ * Whether the transition requires a change in the reveal amount of the light reveal scrim.
+ * If not, we don't care about the transition and don't need to listen to it.
+ */
+ fun willTransitionAffectRevealAmount(transition: TransitionStep): Boolean {
+ return willBeRevealedInState(transition.from) != willBeRevealedInState(transition.to)
+ }
+
+ /**
+ * Whether the light reveal scrim will be fully revealed (revealAmount = 1.0f) in the given
+ * state after the transition is complete. If false, scrim will be fully hidden.
+ */
+ fun willBeRevealedInState(state: KeyguardState): Boolean {
+ return when (state) {
+ KeyguardState.OFF -> false
+ KeyguardState.DOZING -> false
+ KeyguardState.AOD -> false
+ KeyguardState.DREAMING -> true
+ KeyguardState.BOUNCER -> true
+ KeyguardState.LOCKSCREEN -> true
+ KeyguardState.GONE -> true
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
index 3bb8241257cc..3218f9699f35 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
@@ -25,7 +25,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
-import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample
import java.util.UUID
@@ -58,22 +58,26 @@ constructor(
keyguardInteractor.isBouncerShowing
.sample(
combine(
- keyguardInteractor.wakefulnessState,
+ keyguardInteractor.wakefulnessModel,
keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ) { a, b ->
- Pair(a, b)
- },
- { a, bc -> Triple(a, bc.first, bc.second) }
- )
- .collect { triple ->
- val (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) = triple
+ ) { wakefulnessModel, transitionStep ->
+ Pair(wakefulnessModel, transitionStep)
+ }
+ ) { bouncerShowing, wakefulnessAndTransition ->
+ Triple(
+ bouncerShowing,
+ wakefulnessAndTransition.first,
+ wakefulnessAndTransition.second
+ )
+ }
+ .collect { (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) ->
if (
!isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.BOUNCER
) {
val to =
if (
- wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP ||
- wakefulnessState == WakefulnessModel.ASLEEP
+ wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
+ wakefulnessState.state == WakefulnessState.ASLEEP
) {
KeyguardState.AOD
} else {
@@ -100,14 +104,17 @@ constructor(
combine(
keyguardTransitionInteractor.finishedKeyguardState,
keyguardInteractor.statusBarState,
- ) { a, b ->
- Pair(a, b)
- },
- { a, bc -> Triple(a, bc.first, bc.second) }
- )
- .collect { triple ->
- val (shadeModel, keyguardState, statusBarState) = triple
-
+ ) { finishedKeyguardState, statusBarState ->
+ Pair(finishedKeyguardState, statusBarState)
+ }
+ ) { shadeModel, keyguardStateAndStatusBarState ->
+ Triple(
+ shadeModel,
+ keyguardStateAndStatusBarState.first,
+ keyguardStateAndStatusBarState.second
+ )
+ }
+ .collect { (shadeModel, keyguardState, statusBarState) ->
val id = transitionId
if (id != null) {
// An existing `id` means a transition is started, and calls to
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt
new file mode 100644
index 000000000000..b403416c572c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.keyguard.shared.model
+
+import android.hardware.biometrics.BiometricSourceType
+
+/** Biometric unlock sensor sources, which we use to play sensor-specific animations. */
+enum class BiometricUnlockSource {
+ /** The unlock was initiated by a fingerprint sensor authentication. */
+ FINGERPRINT_SENSOR,
+
+ /** The unlock was initiated by the front-facing camera or a nearby sensor. */
+ FACE_SENSOR;
+
+ companion object {
+ fun fromBiometricSourceType(type: BiometricSourceType?): BiometricUnlockSource? {
+ return when (type) {
+ BiometricSourceType.FINGERPRINT -> FINGERPRINT_SENSOR
+ BiometricSourceType.FACE -> FACE_SENSOR
+ BiometricSourceType.IRIS -> FACE_SENSOR
+ else -> null
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
new file mode 100644
index 000000000000..b32597d5cff0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.keyguard.shared.model
+
+import android.os.PowerManager
+
+/** The reason we're waking up or going to sleep, such as pressing the power button. */
+enum class WakeSleepReason {
+ /** The physical power button was pressed to wake up or sleep the device. */
+ POWER_BUTTON,
+
+ /** Something else happened to wake up or sleep the device. */
+ OTHER;
+
+ companion object {
+ fun fromPowerManagerWakeReason(reason: Int): WakeSleepReason {
+ return when (reason) {
+ PowerManager.WAKE_REASON_POWER_BUTTON -> POWER_BUTTON
+ else -> OTHER
+ }
+ }
+
+ fun fromPowerManagerSleepReason(reason: Int): WakeSleepReason {
+ return when (reason) {
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON -> POWER_BUTTON
+ else -> OTHER
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
index 92040f4f0348..03dee0045c10 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -15,24 +15,34 @@
*/
package com.android.systemui.keyguard.shared.model
-/** Model device wakefulness states. */
-enum class WakefulnessModel {
- /** The device is asleep and not interactive. */
- ASLEEP,
- /** Received a signal that the device is beginning to wake up. */
- STARTING_TO_WAKE,
- /** Device is now fully awake and interactive. */
- AWAKE,
- /** Signal that the device is now going to sleep. */
- STARTING_TO_SLEEP;
+import com.android.systemui.keyguard.WakefulnessLifecycle
+/** Model device wakefulness states. */
+data class WakefulnessModel(
+ val state: WakefulnessState,
+ val isWakingUpOrAwake: Boolean,
+ val lastWakeReason: WakeSleepReason,
+ val lastSleepReason: WakeSleepReason,
+) {
companion object {
fun isSleepingOrStartingToSleep(model: WakefulnessModel): Boolean {
- return model == ASLEEP || model == STARTING_TO_SLEEP
+ return model.state == WakefulnessState.ASLEEP ||
+ model.state == WakefulnessState.STARTING_TO_SLEEP
}
fun isWakingOrStartingToWake(model: WakefulnessModel): Boolean {
- return model == AWAKE || model == STARTING_TO_WAKE
+ return model.state == WakefulnessState.AWAKE ||
+ model.state == WakefulnessState.STARTING_TO_WAKE
+ }
+
+ fun fromWakefulnessLifecycle(wakefulnessLifecycle: WakefulnessLifecycle): WakefulnessModel {
+ return WakefulnessModel(
+ WakefulnessState.fromWakefulnessLifecycleInt(wakefulnessLifecycle.wakefulness),
+ wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING ||
+ wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE,
+ WakeSleepReason.fromPowerManagerWakeReason(wakefulnessLifecycle.lastWakeReason),
+ WakeSleepReason.fromPowerManagerSleepReason(wakefulnessLifecycle.lastSleepReason),
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt
new file mode 100644
index 000000000000..6791d88f16d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.keyguard.shared.model
+
+import com.android.systemui.keyguard.WakefulnessLifecycle
+
+enum class WakefulnessState {
+ /** The device is asleep and not interactive. */
+ ASLEEP,
+ /** Received a signal that the device is beginning to wake up. */
+ STARTING_TO_WAKE,
+ /** Device is now fully awake and interactive. */
+ AWAKE,
+ /** Signal that the device is now going to sleep. */
+ STARTING_TO_SLEEP;
+
+ companion object {
+ fun fromWakefulnessLifecycleInt(
+ @WakefulnessLifecycle.Wakefulness value: Int
+ ): WakefulnessState {
+ return when (value) {
+ WakefulnessLifecycle.WAKEFULNESS_ASLEEP -> ASLEEP
+ WakefulnessLifecycle.WAKEFULNESS_WAKING -> STARTING_TO_WAKE
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE -> AWAKE
+ WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP -> STARTING_TO_SLEEP
+ else -> throw IllegalArgumentException("Invalid Wakefulness value: $value")
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
new file mode 100644
index 000000000000..f1da8826a22c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.keyguard.ui.binder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.LightRevealScrim
+import kotlinx.coroutines.launch
+
+object LightRevealScrimViewBinder {
+ @JvmStatic
+ fun bind(revealScrim: LightRevealScrim, viewModel: LightRevealScrimViewModel) {
+ revealScrim.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch {
+ viewModel.revealAmount.collect { amount -> revealScrim.revealAmount = amount }
+ }
+
+ launch {
+ viewModel.lightRevealEffect.collect { effect ->
+ revealScrim.revealEffect = effect
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt
new file mode 100644
index 000000000000..a46d441613ac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.domain.interactor.LightRevealScrimInteractor
+import com.android.systemui.statusbar.LightRevealEffect
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Models UI state for the light reveal scrim, which is used during screen on and off animations to
+ * draw a gradient that reveals/hides the contents of the screen.
+ */
+class LightRevealScrimViewModel @Inject constructor(interactor: LightRevealScrimInteractor) {
+ val lightRevealEffect: Flow<LightRevealEffect> = interactor.lightRevealEffect
+ val revealAmount: Flow<Float> = interactor.revealAmount
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 21e64e28ff19..827ac789073a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -458,7 +458,9 @@ public class MediaControlPanel {
if (mMediaViewHolder == null) {
return;
}
- Trace.beginSection("MediaControlPanel#bindPlayer<" + key + ">");
+ if (Trace.isEnabled()) {
+ Trace.traceBegin(Trace.TRACE_TAG_APP, "MediaControlPanel#bindPlayer<" + key + ">");
+ }
mKey = key;
mMediaData = data;
MediaSession.Token token = data.getToken();
@@ -1179,8 +1181,10 @@ public class MediaControlPanel {
return;
}
- Trace.beginSection(
- "MediaControlPanel#bindRecommendation<" + data.getPackageName() + ">");
+ if (Trace.isEnabled()) {
+ Trace.traceBegin(Trace.TRACE_TAG_APP,
+ "MediaControlPanel#bindRecommendation<" + data.getPackageName() + ">");
+ }
mRecommendationData = data;
mSmartspaceId = SmallHash.hash(data.getTargetId());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
index 966ab4c61b50..afdadeb74e23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
@@ -51,7 +51,9 @@ public abstract class Pluggable<This> {
*/
public final void invalidateList(@Nullable String reason) {
if (mListener != null) {
- Trace.beginSection("Pluggable<" + mName + ">.invalidateList");
+ if (Trace.isEnabled()) {
+ Trace.traceBegin(Trace.TRACE_TAG_APP, "Pluggable<" + mName + ">.invalidateList");
+ }
mListener.onPluggableInvalidated((This) this, reason);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 34e62ce321e0..03057a44ef90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -496,7 +496,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
&& mPendingAuthenticated.userId == KeyguardUpdateMonitor.getCurrentUser();
}
- public int getMode() {
+ public @WakeAndUnlockMode int getMode() {
return mMode;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 16112578de66..d027ed055c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -158,6 +158,8 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder;
+import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -474,6 +476,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private final OngoingCallController mOngoingCallController;
private final StatusBarSignalPolicy mStatusBarSignalPolicy;
private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
+ private final Lazy<LightRevealScrimViewModel> mLightRevealScrimViewModelLazy;
/** Controller for the Shade. */
@VisibleForTesting
@@ -740,7 +743,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
DeviceStateManager deviceStateManager,
WiredChargingRippleController wiredChargingRippleController,
IDreamManager dreamManager,
- Lazy<CameraLauncher> cameraLauncherLazy) {
+ Lazy<CameraLauncher> cameraLauncherLazy,
+ Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy) {
mContext = context;
mNotificationsController = notificationsController;
mFragmentService = fragmentService;
@@ -854,6 +858,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
deviceStateManager.registerCallback(mMainExecutor,
new FoldStateListener(mContext, this::onFoldedStateChanged));
wiredChargingRippleController.registerCallbacks();
+
+ mLightRevealScrimViewModelLazy = lightRevealScrimViewModelLazy;
}
@Override
@@ -983,6 +989,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override
public void onKeyguardGoingAwayChanged() {
+ if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+ // This code path is not used if the KeyguardTransitionRepository is managing
+ // the lightreveal scrim.
+ return;
+ }
+
// The light reveal scrim should always be fully revealed by the time the keyguard
// is done going away. Double check that this is true.
if (!mKeyguardStateController.isKeyguardGoingAway()) {
@@ -1219,6 +1231,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront);
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
+
+ if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+ LightRevealScrimViewBinder.bind(
+ mLightRevealScrim, mLightRevealScrimViewModelLazy.get());
+ }
+
mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> {
Runnable updateOpaqueness = () -> {
mNotificationShadeWindowController.setLightRevealScrimOpaque(
@@ -3289,6 +3307,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
return;
}
+ if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+ return;
+ }
+
final boolean wakingUpFromPowerButton = wakingUp
&& !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)
&& mWakefulnessLifecycle.getLastWakeReason()
@@ -4053,7 +4075,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
return;
}
- mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
+ if (!mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+ mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
+ }
}
@Override
@@ -4234,6 +4258,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override
public void onDozeAmountChanged(float linear, float eased) {
if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
+ && !mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
&& !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index 0910ea36b7ff..37115ad53880 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -19,6 +19,8 @@ package com.android.systemui.user.ui.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.Text
import com.android.systemui.common.ui.drawable.CircularDrawable
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.user.domain.interactor.GuestUserInteractor
@@ -144,7 +146,12 @@ private constructor(
): UserViewModel {
return UserViewModel(
viewKey = model.id,
- name = model.name,
+ name =
+ if (model.isGuest && model.isSelected) {
+ Text.Resource(R.string.guest_exit_quick_settings_button)
+ } else {
+ model.name
+ },
image = CircularDrawable(model.image),
isSelectionMarkerVisible = model.isSelected,
alpha =
diff --git a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
index 5b16ae999aa3..b311318fb111 100644
--- a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
@@ -22,11 +22,22 @@ import android.os.Trace
* Run a block within a [Trace] section.
* Calls [Trace.beginSection] before and [Trace.endSection] after the passed block.
*/
-inline fun <T> traceSection(tag: String, block: () -> T): T {
- Trace.beginSection(tag)
- try {
- return block()
- } finally {
- Trace.endSection()
+inline fun <T> traceSection(tag: String, block: () -> T): T =
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
+ Trace.traceBegin(Trace.TRACE_TAG_APP, tag)
+ try {
+ block()
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_APP)
+ }
+ } else {
+ block()
+ }
+
+class TraceUtils {
+ companion object {
+ inline fun traceRunnable(tag: String, crossinline block: () -> Unit): Runnable {
+ return Runnable { traceSection(tag) { block() } }
+ }
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index eb8c823ffe1c..b765ab3c5eac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -26,6 +26,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.LightRevealScrim
@@ -77,6 +78,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController>
@Mock private lateinit var udfpsController: UdfpsController
@Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var featureFlags: FeatureFlags
@Mock private lateinit var lightRevealScrim: LightRevealScrim
@Mock private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
@@ -106,6 +108,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
biometricUnlockController,
udfpsControllerProvider,
statusBarStateController,
+ featureFlags,
rippleView
)
controller.init()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index e7d5632c7087..3c40835fe59d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -47,6 +47,7 @@ import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
import android.view.WindowMetrics
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
@@ -423,6 +424,21 @@ class SideFpsControllerTest : SysuiTestCase() {
}
@Test
+ fun testLayoutParams_isKeyguardDialogType() =
+ testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
+ sideFpsController.overlayOffsets = sensorLocation
+ sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ executor.runAllReady()
+
+ verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
+
+ val lpType = overlayViewParamsCaptor.value.type
+
+ assertThat((lpType and TYPE_KEYGUARD_DIALOG) != 0).isTrue()
+ }
+
+ @Test
fun testLayoutParams_hasNoMoveAnimationWindowFlag() =
testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
sideFpsController.overlayOffsets = sensorLocation
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 13fc9fcf834b..5deac1924ab7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -16,10 +16,13 @@
package com.android.systemui.keyguard.data.repository
+import android.graphics.Point
+import android.hardware.biometrics.BiometricSourceType
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.shared.model.Position
import com.android.systemui.doze.DozeHost
import com.android.systemui.doze.DozeMachine
@@ -27,9 +30,11 @@ import com.android.systemui.doze.DozeTransitionCallback
import com.android.systemui.doze.DozeTransitionListener
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -57,9 +62,10 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var dozeHost: DozeHost
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
- @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
@Mock private lateinit var dozeTransitionListener: DozeTransitionListener
+ @Mock private lateinit var authController: AuthController
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
private lateinit var underTest: KeyguardRepositoryImpl
@@ -76,6 +82,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
keyguardStateController,
keyguardUpdateMonitor,
dozeTransitionListener,
+ authController,
)
}
@@ -198,7 +205,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
fun dozeAmount() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
- val job = underTest.dozeAmount.onEach(values::add).launchIn(this)
+ val job = underTest.linearDozeAmount.onEach(values::add).launchIn(this)
val captor = argumentCaptor<StatusBarStateController.StateListener>()
verify(statusBarStateController).addCallback(captor.capture())
@@ -207,7 +214,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
captor.value.onDozeAmountChanged(0.498f, 0.5f)
captor.value.onDozeAmountChanged(0.661f, 0.65f)
- assertThat(values).isEqualTo(listOf(0f, 0.4f, 0.5f, 0.65f))
+ assertThat(values).isEqualTo(listOf(0f, 0.433f, 0.498f, 0.661f))
job.cancel()
verify(statusBarStateController).removeCallback(captor.value)
@@ -217,25 +224,36 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
fun wakefulness() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<WakefulnessModel>()
- val job = underTest.wakefulnessState.onEach(values::add).launchIn(this)
+ val job = underTest.wakefulness.onEach(values::add).launchIn(this)
val captor = argumentCaptor<WakefulnessLifecycle.Observer>()
verify(wakefulnessLifecycle).addObserver(captor.capture())
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_WAKING)
captor.value.onStartedWakingUp()
+
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE)
captor.value.onFinishedWakingUp()
+
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP)
captor.value.onStartedGoingToSleep()
+
+ whenever(wakefulnessLifecycle.wakefulness)
+ .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP)
captor.value.onFinishedGoingToSleep()
- assertThat(values)
+ assertThat(values.map { it.state })
.isEqualTo(
listOf(
// Initial value will be ASLEEP
- WakefulnessModel.ASLEEP,
- WakefulnessModel.STARTING_TO_WAKE,
- WakefulnessModel.AWAKE,
- WakefulnessModel.STARTING_TO_SLEEP,
- WakefulnessModel.ASLEEP,
+ WakefulnessState.ASLEEP,
+ WakefulnessState.STARTING_TO_WAKE,
+ WakefulnessState.AWAKE,
+ WakefulnessState.STARTING_TO_SLEEP,
+ WakefulnessState.ASLEEP,
)
)
@@ -329,14 +347,20 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
val captor = argumentCaptor<BiometricUnlockController.BiometricModeListener>()
verify(biometricUnlockController).addBiometricModeListener(captor.capture())
- captor.value.onModeChanged(BiometricUnlockController.MODE_NONE)
- captor.value.onModeChanged(BiometricUnlockController.MODE_WAKE_AND_UNLOCK)
- captor.value.onModeChanged(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING)
- captor.value.onModeChanged(BiometricUnlockController.MODE_SHOW_BOUNCER)
- captor.value.onModeChanged(BiometricUnlockController.MODE_ONLY_WAKE)
- captor.value.onModeChanged(BiometricUnlockController.MODE_UNLOCK_COLLAPSING)
- captor.value.onModeChanged(BiometricUnlockController.MODE_DISMISS_BOUNCER)
- captor.value.onModeChanged(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM)
+ listOf(
+ BiometricUnlockController.MODE_NONE,
+ BiometricUnlockController.MODE_WAKE_AND_UNLOCK,
+ BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING,
+ BiometricUnlockController.MODE_SHOW_BOUNCER,
+ BiometricUnlockController.MODE_ONLY_WAKE,
+ BiometricUnlockController.MODE_UNLOCK_COLLAPSING,
+ BiometricUnlockController.MODE_DISMISS_BOUNCER,
+ BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM,
+ )
+ .forEach {
+ whenever(biometricUnlockController.mode).thenReturn(it)
+ captor.value.onModeChanged(it)
+ }
assertThat(values)
.isEqualTo(
@@ -420,4 +444,104 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
job.cancel()
verify(dozeTransitionListener).removeCallback(listener)
}
+
+ @Test
+ fun fingerprintSensorLocation() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Point?>()
+ val job = underTest.fingerprintSensorLocation.onEach(values::add).launchIn(this)
+
+ val captor = argumentCaptor<AuthController.Callback>()
+ verify(authController).addCallback(captor.capture())
+
+ // An initial, null value should be initially emitted so that flows combined with this
+ // one
+ // emit values immediately. The sensor location is expected to be nullable, so anyone
+ // consuming it should handle that properly.
+ assertThat(values).isEqualTo(listOf(null))
+
+ listOf(Point(500, 500), Point(0, 0), null, Point(250, 250))
+ .onEach {
+ whenever(authController.fingerprintSensorLocation).thenReturn(it)
+ captor.value.onFingerprintLocationChanged()
+ }
+ .also { dispatchedSensorLocations ->
+ assertThat(values).isEqualTo(listOf(null) + dispatchedSensorLocations)
+ }
+
+ job.cancel()
+ }
+
+ @Test
+ fun faceSensorLocation() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Point?>()
+ val job = underTest.faceSensorLocation.onEach(values::add).launchIn(this)
+
+ val captor = argumentCaptor<AuthController.Callback>()
+ verify(authController).addCallback(captor.capture())
+
+ // An initial, null value should be initially emitted so that flows combined with this
+ // one
+ // emit values immediately. The sensor location is expected to be nullable, so anyone
+ // consuming it should handle that properly.
+ assertThat(values).isEqualTo(listOf(null))
+
+ listOf(
+ Point(500, 500),
+ Point(0, 0),
+ null,
+ Point(250, 250),
+ )
+ .onEach {
+ whenever(authController.faceSensorLocation).thenReturn(it)
+ captor.value.onFaceSensorLocationChanged()
+ }
+ .also { dispatchedSensorLocations ->
+ assertThat(values).isEqualTo(listOf(null) + dispatchedSensorLocations)
+ }
+
+ job.cancel()
+ }
+
+ @Test
+ fun biometricUnlockSource() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<BiometricUnlockSource?>()
+ val job = underTest.biometricUnlockSource.onEach(values::add).launchIn(this)
+
+ val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+
+ // An initial, null value should be initially emitted so that flows combined with this
+ // one
+ // emit values immediately. The biometric unlock source is expected to be nullable, so
+ // anyone consuming it should handle that properly.
+ assertThat(values).isEqualTo(listOf(null))
+
+ listOf(
+ BiometricSourceType.FINGERPRINT,
+ BiometricSourceType.IRIS,
+ null,
+ BiometricSourceType.FACE,
+ BiometricSourceType.FINGERPRINT,
+ )
+ .onEach { biometricSourceType ->
+ captor.value.onBiometricAuthenticated(0, biometricSourceType, false)
+ }
+
+ assertThat(values)
+ .isEqualTo(
+ listOf(
+ null,
+ BiometricUnlockSource.FINGERPRINT_SENSOR,
+ BiometricUnlockSource.FACE_SENSOR,
+ null,
+ BiometricUnlockSource.FACE_SENSOR,
+ BiometricUnlockSource.FINGERPRINT_SENSOR,
+ )
+ )
+
+ job.cancel()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
new file mode 100644
index 000000000000..d2db910ad443
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -0,0 +1,167 @@
+/*
+ * 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.keyguard.data.repository
+
+import android.graphics.Point
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.statusbar.CircleReveal
+import com.android.systemui.statusbar.LightRevealEffect
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LightRevealScrimRepositoryTest : SysuiTestCase() {
+ private lateinit var fakeKeyguardRepository: FakeKeyguardRepository
+ private lateinit var underTest: LightRevealScrimRepositoryImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ fakeKeyguardRepository = FakeKeyguardRepository()
+ underTest = LightRevealScrimRepositoryImpl(fakeKeyguardRepository, context)
+ }
+
+ @Test
+ fun `nextRevealEffect - effect switches between default and biometric with no dupes`() =
+ runTest {
+ val values = mutableListOf<LightRevealEffect>()
+ val job = launch { underTest.revealEffect.collect { values.add(it) } }
+
+ // We should initially emit the default reveal effect.
+ runCurrent()
+ values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT })
+
+ // The source and sensor locations are still null, so we should still be using the
+ // default reveal despite a biometric unlock.
+ fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+
+ runCurrent()
+ values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+
+ // We got a source but still have no sensor locations, so should be sticking with
+ // the default effect.
+ fakeKeyguardRepository.setBiometricUnlockSource(
+ BiometricUnlockSource.FINGERPRINT_SENSOR
+ )
+
+ runCurrent()
+ values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+
+ // We got a location for the face sensor, but we unlocked with fingerprint.
+ val faceLocation = Point(250, 0)
+ fakeKeyguardRepository.setFaceSensorLocation(faceLocation)
+
+ runCurrent()
+ values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+
+ // Now we have fingerprint sensor locations, and wake and unlock via fingerprint.
+ val fingerprintLocation = Point(500, 500)
+ fakeKeyguardRepository.setFingerprintSensorLocation(fingerprintLocation)
+ fakeKeyguardRepository.setBiometricUnlockSource(
+ BiometricUnlockSource.FINGERPRINT_SENSOR
+ )
+ fakeKeyguardRepository.setBiometricUnlockState(
+ BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING
+ )
+
+ // We should now have switched to the circle reveal, at the fingerprint location.
+ runCurrent()
+ values.assertEffectsMatchPredicates(
+ { it == DEFAULT_REVEAL_EFFECT },
+ {
+ it is CircleReveal &&
+ it.centerX == fingerprintLocation.x &&
+ it.centerY == fingerprintLocation.y
+ },
+ )
+
+ // Subsequent wake and unlocks should not emit duplicate, identical CircleReveals.
+ val valuesPrevSize = values.size
+ fakeKeyguardRepository.setBiometricUnlockState(
+ BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING
+ )
+ fakeKeyguardRepository.setBiometricUnlockState(
+ BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
+ )
+ assertEquals(valuesPrevSize, values.size)
+
+ // Non-biometric unlock, we should return to the default reveal.
+ fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.NONE)
+
+ runCurrent()
+ values.assertEffectsMatchPredicates(
+ { it == DEFAULT_REVEAL_EFFECT },
+ {
+ it is CircleReveal &&
+ it.centerX == fingerprintLocation.x &&
+ it.centerY == fingerprintLocation.y
+ },
+ { it == DEFAULT_REVEAL_EFFECT },
+ )
+
+ // We already have a face location, so switching to face source should update the
+ // CircleReveal.
+ fakeKeyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FACE_SENSOR)
+ runCurrent()
+ fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+ runCurrent()
+
+ values.assertEffectsMatchPredicates(
+ { it == DEFAULT_REVEAL_EFFECT },
+ {
+ it is CircleReveal &&
+ it.centerX == fingerprintLocation.x &&
+ it.centerY == fingerprintLocation.y
+ },
+ { it == DEFAULT_REVEAL_EFFECT },
+ {
+ it is CircleReveal &&
+ it.centerX == faceLocation.x &&
+ it.centerY == faceLocation.y
+ },
+ )
+
+ job.cancel()
+ }
+
+ /**
+ * Asserts that the list of LightRevealEffects satisfies the list of predicates, in order, with
+ * no leftover elements.
+ */
+ private fun List<LightRevealEffect>.assertEffectsMatchPredicates(
+ vararg predicates: (LightRevealEffect) -> Boolean
+ ) {
+ println(this)
+ assertEquals(predicates.size, this.size)
+
+ assertFalse(
+ zip(predicates) { effect, predicate -> predicate(effect) }.any { matched -> !matched }
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
new file mode 100644
index 000000000000..31662145dfbe
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.statusbar.LightRevealScrim
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LightRevealScrimInteractorTest : SysuiTestCase() {
+ private val fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository()
+ private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository()
+
+ private val keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(fakeKeyguardTransitionRepository)
+
+ private lateinit var underTest: LightRevealScrimInteractor
+
+ private val reveal1 =
+ object : LightRevealEffect {
+ override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {}
+ }
+
+ private val reveal2 =
+ object : LightRevealEffect {
+ override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {}
+ }
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest =
+ LightRevealScrimInteractor(
+ fakeKeyguardTransitionRepository,
+ keyguardTransitionInteractor,
+ fakeLightRevealScrimRepository
+ )
+ }
+
+ @Test
+ fun `lightRevealEffect - does not change during keyguard transition`() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<LightRevealEffect>()
+ val job = underTest.lightRevealEffect.onEach(values::add).launchIn(this)
+
+ fakeLightRevealScrimRepository.setRevealEffect(reveal1)
+
+ // The reveal effect shouldn't emit anything until a keyguard transition starts.
+ assertEquals(values.size, 0)
+
+ // Once it starts, it should emit reveal1.
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(transitionState = TransitionState.STARTED)
+ )
+ assertEquals(values, listOf(reveal1))
+
+ // Until the next transition starts, reveal2 should not be emitted.
+ fakeLightRevealScrimRepository.setRevealEffect(reveal2)
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(transitionState = TransitionState.RUNNING)
+ )
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(transitionState = TransitionState.FINISHED)
+ )
+ assertEquals(values, listOf(reveal1))
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(transitionState = TransitionState.STARTED)
+ )
+ assertEquals(values, listOf(reveal1, reveal2))
+
+ job.cancel()
+ }
+
+ @Test
+ fun `revealAmount - inverted when appropriate`() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+ val job = underTest.revealAmount.onEach(values::add).launchIn(this)
+
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ value = 0.3f
+ )
+ )
+
+ assertEquals(values, listOf(0.3f))
+
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.AOD,
+ value = 0.3f
+ )
+ )
+
+ assertEquals(values, listOf(0.3f, 0.7f))
+
+ job.cancel()
+ }
+
+ @Test
+ fun `revealAmount - ignores transitions that do not affect reveal amount`() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+ val job = underTest.revealAmount.onEach(values::add).launchIn(this)
+
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.DOZING, to = KeyguardState.AOD, value = 0.3f)
+ )
+
+ assertEquals(values, emptyList<Float>())
+
+ fakeKeyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.AOD, to = KeyguardState.DOZING, value = 0.3f)
+ )
+
+ assertEquals(values, emptyList<Float>())
+
+ job.cancel()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index ed84e4268c90..521e51846834 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -106,6 +106,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.PluginDependencyProvider;
@@ -212,6 +213,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
@Mock private NotificationPanelView mNotificationPanelView;
@Mock private IStatusBarService mBarService;
@Mock private IDreamManager mDreamManager;
+ @Mock private LightRevealScrimViewModel mLightRevealScrimViewModel;
@Mock private ScrimController mScrimController;
@Mock private DozeScrimController mDozeScrimController;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@@ -497,7 +499,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
mDeviceStateManager,
mWiredChargingRippleController,
mDreamManager,
- mCameraLauncherLazy) {
+ mCameraLauncherLazy,
+ () -> mLightRevealScrimViewModel) {
@Override
protected ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 4b6bdac46a3d..784a26bb371b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -47,18 +47,14 @@ import com.android.systemui.user.shared.model.UserActionModel
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestDispatcher
-import kotlinx.coroutines.test.TestResult
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -89,7 +85,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
private lateinit var testDispatcher: TestDispatcher
private lateinit var testScope: TestScope
- private lateinit var injectedScope: CoroutineScope
@Before
fun setUp() {
@@ -104,7 +99,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
testDispatcher = UnconfinedTestDispatcher()
testScope = TestScope(testDispatcher)
- injectedScope = CoroutineScope(testScope.coroutineContext + SupervisorJob())
userRepository = FakeUserRepository()
runBlocking {
userRepository.setSettings(
@@ -118,14 +112,14 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
powerRepository = FakePowerRepository()
val refreshUsersScheduler =
RefreshUsersScheduler(
- applicationScope = injectedScope,
+ applicationScope = testScope.backgroundScope,
mainDispatcher = testDispatcher,
repository = userRepository,
)
val guestUserInteractor =
GuestUserInteractor(
applicationContext = context,
- applicationScope = injectedScope,
+ applicationScope = testScope.backgroundScope,
mainDispatcher = testDispatcher,
backgroundDispatcher = testDispatcher,
manager = manager,
@@ -154,7 +148,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
},
manager = manager,
- applicationScope = injectedScope,
+ applicationScope = testScope.backgroundScope,
telephonyInteractor =
TelephonyInteractor(
repository = FakeTelephonyRepository(),
@@ -175,7 +169,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun users() = selfCancelingTest {
+ fun users() = testScope.runTest {
val userInfos =
listOf(
UserInfo(
@@ -210,26 +204,26 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
assertUserViewModel(
viewModel = userViewModels.last()[0],
viewKey = 0,
- name = "zero",
+ name = Text.Loaded("zero"),
isSelectionMarkerVisible = true,
)
assertUserViewModel(
viewModel = userViewModels.last()[1],
viewKey = 1,
- name = "one",
+ name = Text.Loaded("one"),
isSelectionMarkerVisible = false,
)
assertUserViewModel(
viewModel = userViewModels.last()[2],
viewKey = 2,
- name = "two",
+ name = Text.Loaded("two"),
isSelectionMarkerVisible = false,
)
job.cancel()
}
@Test
- fun `maximumUserColumns - few users`() = selfCancelingTest {
+ fun `maximumUserColumns - few users`() = testScope.runTest {
setUsers(count = 2)
val values = mutableListOf<Int>()
val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
@@ -240,7 +234,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `maximumUserColumns - many users`() = selfCancelingTest {
+ fun `maximumUserColumns - many users`() = testScope.runTest {
setUsers(count = 5)
val values = mutableListOf<Int>()
val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
@@ -250,7 +244,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `isOpenMenuButtonVisible - has actions - true`() = selfCancelingTest {
+ fun `isOpenMenuButtonVisible - has actions - true`() = testScope.runTest {
setUsers(2)
val isVisible = mutableListOf<Boolean>()
@@ -261,7 +255,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `isOpenMenuButtonVisible - no actions - false`() = selfCancelingTest {
+ fun `isOpenMenuButtonVisible - no actions - false`() = testScope.runTest {
val userInfos = setUsers(2)
userRepository.setSelectedUserInfo(userInfos[1])
keyguardRepository.setKeyguardShowing(true)
@@ -275,7 +269,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun menu() = selfCancelingTest {
+ fun menu() = testScope.runTest {
val isMenuVisible = mutableListOf<Boolean>()
val job = launch(testDispatcher) { underTest.isMenuVisible.toList(isMenuVisible) }
assertThat(isMenuVisible.last()).isFalse()
@@ -290,7 +284,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `menu actions`() = selfCancelingTest {
+ fun `menu actions`() = testScope.runTest {
setUsers(2)
val actions = mutableListOf<List<UserActionViewModel>>()
val job = launch(testDispatcher) { underTest.menu.toList(actions) }
@@ -309,7 +303,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `isFinishRequested - finishes when user is switched`() = selfCancelingTest {
+ fun `isFinishRequested - finishes when user is switched`() = testScope.runTest {
val userInfos = setUsers(count = 2)
val isFinishRequested = mutableListOf<Boolean>()
val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
@@ -323,7 +317,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `isFinishRequested - finishes when the screen turns off`() = selfCancelingTest {
+ fun `isFinishRequested - finishes when the screen turns off`() = testScope.runTest {
setUsers(count = 2)
powerRepository.setInteractive(true)
val isFinishRequested = mutableListOf<Boolean>()
@@ -338,7 +332,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
}
@Test
- fun `isFinishRequested - finishes when cancel button is clicked`() = selfCancelingTest {
+ fun `isFinishRequested - finishes when cancel button is clicked`() = testScope.runTest {
setUsers(count = 2)
powerRepository.setInteractive(true)
val isFinishRequested = mutableListOf<Boolean>()
@@ -356,6 +350,93 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun `guest selected -- name is exit guest`() = testScope.runTest {
+ val userInfos =
+ listOf(
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ UserInfo(
+ /* id= */ 1,
+ /* name= */ "one",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_GUEST,
+ ),
+ )
+
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[1])
+
+ val userViewModels = mutableListOf<List<UserViewModel>>()
+ val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
+
+ assertThat(userViewModels.last()).hasSize(2)
+ assertUserViewModel(
+ viewModel = userViewModels.last()[0],
+ viewKey = 0,
+ name = Text.Loaded("zero"),
+ isSelectionMarkerVisible = false,
+ )
+ assertUserViewModel(
+ viewModel = userViewModels.last()[1],
+ viewKey = 1,
+ name = Text.Resource(
+ com.android.settingslib.R.string.guest_exit_quick_settings_button
+ ),
+ isSelectionMarkerVisible = true,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `guest not selected -- name is guest`() = testScope.runTest {
+ val userInfos =
+ listOf(
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ UserInfo(
+ /* id= */ 1,
+ /* name= */ "one",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_GUEST,
+ ),
+ )
+
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
+ runCurrent()
+
+ val userViewModels = mutableListOf<List<UserViewModel>>()
+ val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
+
+ assertThat(userViewModels.last()).hasSize(2)
+ assertUserViewModel(
+ viewModel = userViewModels.last()[0],
+ viewKey = 0,
+ name = Text.Loaded("zero"),
+ isSelectionMarkerVisible = true,
+ )
+ assertUserViewModel(
+ viewModel = userViewModels.last()[1],
+ viewKey = 1,
+ name = Text.Loaded("one"),
+ isSelectionMarkerVisible = false,
+ )
+ job.cancel()
+ }
+
private suspend fun setUsers(count: Int): List<UserInfo> {
val userInfos =
(0 until count).map { index ->
@@ -384,26 +465,18 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
private fun assertUserViewModel(
viewModel: UserViewModel?,
viewKey: Int,
- name: String,
+ name: Text,
isSelectionMarkerVisible: Boolean,
) {
checkNotNull(viewModel)
assertThat(viewModel.viewKey).isEqualTo(viewKey)
- assertThat(viewModel.name).isEqualTo(Text.Loaded(name))
+ assertThat(viewModel.name).isEqualTo(name)
assertThat(viewModel.isSelectionMarkerVisible).isEqualTo(isSelectionMarkerVisible)
assertThat(viewModel.alpha)
.isEqualTo(LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA)
assertThat(viewModel.onClicked).isNotNull()
}
- private fun selfCancelingTest(
- block: suspend TestScope.() -> Unit,
- ): TestResult =
- testScope.runTest {
- block()
- injectedScope.coroutineContext[Job.Key]?.cancelAndJoin()
- }
-
companion object {
private const val SUPERVISED_USER_CREATION_PACKAGE = "com.some.package"
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index 52e0c982cae0..ad086ff9c664 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -22,12 +22,12 @@ import android.content.IntentFilter
import android.os.Handler
import android.os.Looper
import android.os.UserHandle
-import android.util.ArraySet
import android.util.Log
import com.android.systemui.SysuiTestableContext
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserTracker
+import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executor
class FakeBroadcastDispatcher(
@@ -50,7 +50,7 @@ class FakeBroadcastDispatcher(
PendingRemovalStore(logger)
) {
- val registeredReceivers = ArraySet<BroadcastReceiver>()
+ val registeredReceivers: MutableSet<BroadcastReceiver> = ConcurrentHashMap.newKeySet()
override fun registerReceiverWithHandler(
receiver: BroadcastReceiver,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 36016678fb91..5c2a915e81b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -17,11 +17,15 @@
package com.android.systemui.keyguard.data.repository
+import android.graphics.Point
import com.android.systemui.common.shared.model.Position
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -49,7 +53,7 @@ class FakeKeyguardRepository : KeyguardRepository {
override val isDreaming: Flow<Boolean> = _isDreaming
private val _dozeAmount = MutableStateFlow(0f)
- override val dozeAmount: Flow<Float> = _dozeAmount
+ override val linearDozeAmount: Flow<Float> = _dozeAmount
private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
override val statusBarState: Flow<StatusBarState> = _statusBarState
@@ -57,8 +61,16 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _dozeTransitionModel = MutableStateFlow(DozeTransitionModel())
override val dozeTransitionModel: Flow<DozeTransitionModel> = _dozeTransitionModel
- private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP)
- override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState
+ private val _wakefulnessModel =
+ MutableStateFlow(
+ WakefulnessModel(
+ WakefulnessState.ASLEEP,
+ false,
+ WakeSleepReason.OTHER,
+ WakeSleepReason.OTHER
+ )
+ )
+ override val wakefulness: Flow<WakefulnessModel> = _wakefulnessModel
private val _isUdfpsSupported = MutableStateFlow(false)
@@ -71,6 +83,15 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _biometricUnlockState = MutableStateFlow(BiometricUnlockModel.NONE)
override val biometricUnlockState: Flow<BiometricUnlockModel> = _biometricUnlockState
+ private val _fingerprintSensorLocation = MutableStateFlow<Point?>(null)
+ override val fingerprintSensorLocation: Flow<Point?> = _fingerprintSensorLocation
+
+ private val _faceSensorLocation = MutableStateFlow<Point?>(null)
+ override val faceSensorLocation: Flow<Point?> = _faceSensorLocation
+
+ private val _biometricUnlockSource = MutableStateFlow<BiometricUnlockSource?>(null)
+ override val biometricUnlockSource: Flow<BiometricUnlockSource?> = _biometricUnlockSource
+
override fun isKeyguardShowing(): Boolean {
return _isKeyguardShowing.value
}
@@ -99,6 +120,22 @@ class FakeKeyguardRepository : KeyguardRepository {
_dozeAmount.value = dozeAmount
}
+ fun setBiometricUnlockState(state: BiometricUnlockModel) {
+ _biometricUnlockState.tryEmit(state)
+ }
+
+ fun setBiometricUnlockSource(source: BiometricUnlockSource?) {
+ _biometricUnlockSource.tryEmit(source)
+ }
+
+ fun setFaceSensorLocation(location: Point?) {
+ _faceSensorLocation.tryEmit(location)
+ }
+
+ fun setFingerprintSensorLocation(location: Point?) {
+ _fingerprintSensorLocation.tryEmit(location)
+ }
+
override fun isUdfpsSupported(): Boolean {
return _isUdfpsSupported.value
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
new file mode 100644
index 000000000000..7c22604dc546
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.keyguard.data.repository
+
+import com.android.systemui.statusbar.LightRevealEffect
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Fake implementation of [LightRevealScrimRepository] */
+class FakeLightRevealScrimRepository : LightRevealScrimRepository {
+
+ private val _revealEffect: MutableStateFlow<LightRevealEffect> =
+ MutableStateFlow(DEFAULT_REVEAL_EFFECT)
+ override val revealEffect = _revealEffect
+
+ fun setRevealEffect(effect: LightRevealEffect) {
+ _revealEffect.tryEmit(effect)
+ }
+}
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 551ffff2921b..84c033cbdf0e 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -341,7 +341,8 @@ public class BootReceiver extends BroadcastReceiver {
// non-proto tombstones, even though proto tombstones do not support including the counter
// of events dropped since rate limiting activated yet.
DropboxRateLimiter.RateLimitResult rateLimitResult =
- sDropboxRateLimiter.shouldRateLimit(TAG_TOMBSTONE, processName);
+ sDropboxRateLimiter.shouldRateLimit(
+ proto ? TAG_TOMBSTONE_PROTO : TAG_TOMBSTONE, processName);
if (rateLimitResult.shouldRateLimit()) return;
HashMap<String, Long> timestamps = readTimestamps();
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 40e7c5062a77..1c510cce1bb7 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -49,7 +49,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.provider.Settings;
-import android.sysprop.DisplayProperties;
+import android.sysprop.SurfaceFlingerProperties;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.Pair;
@@ -138,8 +138,7 @@ public class DisplayModeDirector {
private boolean mAlwaysRespectAppRequest;
- // TODO(b/241447632): remove the flag once SF changes are ready
- private final boolean mRenderFrameRateIsPhysicalRefreshRate;
+ private final boolean mSupportsFrameRateOverride;
/**
* The allowed refresh rate switching type. This is used by SurfaceFlinger.
@@ -176,7 +175,7 @@ public class DisplayModeDirector {
mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
mDeviceConfigDisplaySettings);
mAlwaysRespectAppRequest = false;
- mRenderFrameRateIsPhysicalRefreshRate = injector.renderFrameRateIsPhysicalRefreshRate();
+ mSupportsFrameRateOverride = injector.supportsFrameRateOverride();
}
/**
@@ -238,21 +237,6 @@ public class DisplayModeDirector {
}
}
- if (mRenderFrameRateIsPhysicalRefreshRate) {
- for (int i = 0; i < votes.size(); i++) {
-
- Vote vote = votes.valueAt(i);
- vote.refreshRateRanges.physical.min = Math.max(vote.refreshRateRanges.physical.min,
- vote.refreshRateRanges.render.min);
- vote.refreshRateRanges.physical.max = Math.min(vote.refreshRateRanges.physical.max,
- vote.refreshRateRanges.render.max);
- vote.refreshRateRanges.render.min = Math.max(vote.refreshRateRanges.physical.min,
- vote.refreshRateRanges.render.min);
- vote.refreshRateRanges.render.max = Math.min(vote.refreshRateRanges.physical.max,
- vote.refreshRateRanges.render.max);
- }
- }
-
return votes;
}
@@ -541,8 +525,7 @@ public class DisplayModeDirector {
}
}
- if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE
- || mRenderFrameRateIsPhysicalRefreshRate) {
+ if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
primarySummary.minRenderFrameRate = primarySummary.minPhysicalRefreshRate;
primarySummary.maxRenderFrameRate = primarySummary.maxPhysicalRefreshRate;
appRequestSummary.minRenderFrameRate = appRequestSummary.minPhysicalRefreshRate;
@@ -612,6 +595,22 @@ public class DisplayModeDirector {
continue;
}
+ // The physical refresh rate must be in the render frame rate range, unless
+ // frame rate override is supported.
+ if (!mSupportsFrameRateOverride) {
+ if (physicalRefreshRate < (summary.minRenderFrameRate - FLOAT_TOLERANCE)
+ || physicalRefreshRate > (summary.maxRenderFrameRate + FLOAT_TOLERANCE)) {
+ if (mLoggingEnabled) {
+ Slog.w(TAG, "Discarding mode " + mode.getModeId()
+ + ", outside render rate bounds"
+ + ": minPhysicalRefreshRate=" + summary.minPhysicalRefreshRate
+ + ", maxPhysicalRefreshRate=" + summary.maxPhysicalRefreshRate
+ + ", modeRefreshRate=" + physicalRefreshRate);
+ }
+ continue;
+ }
+ }
+
// Check whether the render frame rate range is achievable by the mode's physical
// refresh rate, meaning that if a divisor of the physical refresh rate is in range
// of the render frame rate.
@@ -2979,7 +2978,7 @@ public class DisplayModeDirector {
IThermalService getThermalService();
- boolean renderFrameRateIsPhysicalRefreshRate();
+ boolean supportsFrameRateOverride();
}
@VisibleForTesting
@@ -3034,9 +3033,11 @@ public class DisplayModeDirector {
}
@Override
- public boolean renderFrameRateIsPhysicalRefreshRate() {
- return DisplayProperties
- .debug_render_frame_rate_is_physical_refresh_rate().orElse(true);
+ public boolean supportsFrameRateOverride() {
+ return SurfaceFlingerProperties.enable_frame_rate_override().orElse(false)
+ && !SurfaceFlingerProperties.frame_rate_override_for_native_rates()
+ .orElse(true)
+ && SurfaceFlingerProperties.frame_rate_override_global().orElse(false);
}
private DisplayManager getDisplayManager() {
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 90245b5ebda9..7f6c2d6ececc 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -73,6 +73,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -147,7 +148,6 @@ public class ContextHubService extends IContextHubService.Stub {
private final ScheduledThreadPoolExecutor mDailyMetricTimer =
new ScheduledThreadPoolExecutor(1);
-
// The period of the recurring time
private static final int PERIOD_METRIC_QUERY_DAYS = 1;
@@ -363,11 +363,13 @@ public class ContextHubService extends IContextHubService.Stub {
*/
private void initDefaultClientMap() {
HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
- for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
+ for (Map.Entry<Integer, ContextHubInfo> entry: mContextHubIdToInfoMap.entrySet()) {
+ int contextHubId = entry.getKey();
+ ContextHubInfo contextHubInfo = entry.getValue();
+
mLastRestartTimestampMap.put(contextHubId,
new AtomicLong(SystemClock.elapsedRealtimeNanos()));
- ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
IContextHubClient client = mClientManager.registerClient(
contextHubInfo, createDefaultClientCallback(contextHubId),
/* attributionTag= */ null, mTransactionManager, mContext.getPackageName());
@@ -1133,6 +1135,26 @@ public class ContextHubService extends IContextHubService.Stub {
mTransactionManager.addTransaction(transaction);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+ /**
+ * Queries for a list of preloaded nanoapp IDs from the specified Context Hub.
+ *
+ * @param hubInfo The Context Hub to query a list of nanoapps from.
+ * @return The list of 64-bit IDs of the preloaded nanoapps.
+ * @throws NullPointerException if hubInfo is null
+ */
+ @Override
+ public long[] getPreloadedNanoAppIds(ContextHubInfo hubInfo) throws RemoteException {
+ super.getPreloadedNanoAppIds_enforcePermission();
+ Objects.requireNonNull(hubInfo, "hubInfo cannot be null");
+
+ long[] nanoappIds = mContextHubWrapper.getPreloadedNanoappIds();
+ if (nanoappIds == null) {
+ return new long[0];
+ }
+ return nanoappIds;
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -1160,6 +1182,10 @@ public class ContextHubService extends IContextHubService.Stub {
mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> pw.println(info));
pw.println("");
+ pw.println("=================== PRELOADED NANOAPPS ====================");
+ dumpPreloadedNanoapps(pw);
+
+ pw.println("");
pw.println("=================== CLIENTS ====================");
pw.println(mClientManager);
@@ -1201,6 +1227,21 @@ public class ContextHubService extends IContextHubService.Stub {
proto.flush();
}
+ /**
+ * Dumps preloaded nanoapps to the console
+ */
+ private void dumpPreloadedNanoapps(PrintWriter pw) {
+ if (mContextHubWrapper == null) {
+ return;
+ }
+
+ long[] preloadedNanoappIds = mContextHubWrapper.getPreloadedNanoappIds();
+ for (long preloadedNanoappId: preloadedNanoappIds) {
+ pw.print("ID: 0x");
+ pw.println(Long.toHexString(preloadedNanoappId));
+ }
+ }
+
private void checkPermissions() {
ContextHubServiceUtil.checkPermissions(mContext);
}
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 48152b40aaf6..f55ae6e8aed4 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -359,6 +359,14 @@ public abstract class IContextHubWrapper {
public abstract int queryNanoapps(int contextHubId) throws RemoteException;
/**
+ * Provides the list of preloaded nanoapp IDs on the system. The output of this API must
+ * not change.
+ *
+ * @return The list of preloaded nanoapp IDs
+ */
+ public abstract long[] getPreloadedNanoappIds();
+
+ /**
* Registers a callback with the Context Hub.
*
* @param contextHubId The ID of the Context Hub to register the callback with.
@@ -683,6 +691,20 @@ public abstract class IContextHubWrapper {
}
}
+ public long[] getPreloadedNanoappIds() {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return null;
+ }
+
+ try {
+ return hub.getPreloadedNanoappIds();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while getting preloaded nanoapp IDs: " + e.getMessage());
+ return null;
+ }
+ }
+
public void registerExistingCallback(int contextHubId) {
android.hardware.contexthub.IContextHub hub = getHub();
if (hub == null) {
@@ -863,6 +885,10 @@ public abstract class IContextHubWrapper {
mHub.queryApps(contextHubId));
}
+ public long[] getPreloadedNanoappIds() {
+ return new long[0];
+ }
+
public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
mHidlCallbackMap.put(contextHubId,
new ContextHubWrapperHidlCallback(contextHubId, callback));
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 19409b1f3636..73759d3a3362 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4927,7 +4927,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// animation on the keyguard but seeing the IME window that originally on the app
// which behinds the keyguard.
final WindowState imeInputTarget = getImeInputTarget();
- if (imeInputTarget != null && !(imeInputTarget.isDrawn() || imeInputTarget.isVisible())) {
+ if (imeInputTarget != null
+ && !(imeInputTarget.isDrawn() || imeInputTarget.isVisibleRequested())) {
return false;
}
return mDisplayContent.forAllImeWindows(callback, traverseTopToBottom);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 5d0551b4b54c..969056e7c8b4 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -310,7 +310,7 @@ public:
const InputDeviceIdentifier& identifier) override;
std::string getDeviceAlias(const InputDeviceIdentifier& identifier) override;
TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
- int32_t surfaceRotation) override;
+ ui::Rotation surfaceRotation) override;
TouchAffineTransformation getTouchAffineTransformation(JNIEnv* env, jfloatArray matrixArr);
void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
@@ -1153,7 +1153,7 @@ TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
}
TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
- const std::string& inputDeviceDescriptor, int32_t surfaceRotation) {
+ const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation) {
JNIEnv* env = jniEnv();
ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.c_str()));
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 71f3d15e76fb..d1ae9ffb18ac 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -200,12 +200,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testDisplayModeVoting(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testDisplayModeVoting() {
// With no votes present, DisplayModeDirector should allow any refresh rate.
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
DesiredDisplayModeSpecs modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
@@ -242,12 +237,7 @@ public class DisplayModeDirectorTest {
.isEqualTo((float) (minFps + i));
assertThat(modeSpecs.primary.physical.max)
.isEqualTo((float) (maxFps - i));
- if (frameRateIsRefreshRate) {
- assertThat(modeSpecs.primary.render.min)
- .isEqualTo((float) (minFps + i));
- } else {
- assertThat(modeSpecs.primary.render.min).isZero();
- }
+ assertThat(modeSpecs.primary.render.min).isZero();
assertThat(modeSpecs.primary.render.max)
.isEqualTo((float) (maxFps - i));
if (priority >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF) {
@@ -255,12 +245,7 @@ public class DisplayModeDirectorTest {
.isEqualTo((float) (minFps + i));
assertThat(modeSpecs.appRequest.physical.max)
.isEqualTo((float) (maxFps - i));
- if (frameRateIsRefreshRate) {
- assertThat(modeSpecs.appRequest.render.min).isEqualTo(
- (float) (minFps + i));
- } else {
- assertThat(modeSpecs.appRequest.render.min).isZero();
- }
+ assertThat(modeSpecs.appRequest.render.min).isZero();
assertThat(modeSpecs.appRequest.render.max).isEqualTo(
(float) (maxFps - i));
} else {
@@ -292,12 +277,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testVotingWithFloatingPointErrors(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testVotingWithFloatingPointErrors() {
DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -318,12 +298,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testFlickerHasLowerPriorityThanUserAndRangeIsSingle(
- boolean frameRateIsRefreshRate) {
+ public void testFlickerHasLowerPriorityThanUserAndRangeIsSingle() {
assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE
< Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE
@@ -332,7 +307,6 @@ public class DisplayModeDirectorTest {
assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH
> Vote.PRIORITY_LOW_POWER_MODE);
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
Display.Mode[] modes = new Display.Mode[4];
modes[0] = new Display.Mode(
/*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -408,17 +382,12 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testLPMHasHigherPriorityThanUser(boolean frameRateIsRefreshRate) {
+ public void testLPMHasHigherPriorityThanUser() {
assertTrue(Vote.PRIORITY_LOW_POWER_MODE
> Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
assertTrue(Vote.PRIORITY_LOW_POWER_MODE
> Vote.PRIORITY_APP_REQUEST_SIZE);
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
Display.Mode[] modes = new Display.Mode[4];
modes[0] = new Display.Mode(
/*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -443,11 +412,7 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.baseModeId).isEqualTo(2);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -462,11 +427,7 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.baseModeId).isEqualTo(4);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(90);
@@ -481,11 +442,7 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.baseModeId).isEqualTo(2);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -500,21 +457,13 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.baseModeId).isEqualTo(4);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(90);
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestRefreshRateRange(boolean frameRateIsRefreshRate) {
+ public void testAppRequestRefreshRateRange() {
// Confirm that the app request range doesn't include flicker or min refresh rate settings,
// but does include everything else.
assertTrue(
@@ -525,7 +474,6 @@ public class DisplayModeDirectorTest {
assertTrue(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE
>= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
Display.Mode[] modes = new Display.Mode[3];
modes[0] = new Display.Mode(
/*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
@@ -582,12 +530,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testSpecsFromRefreshRateSettings(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testSpecsFromRefreshRateSettings() {
// Confirm that, with varying settings for min, peak, and default refresh rate,
// DesiredDisplayModeSpecs is calculated correctly.
float[] refreshRates = {30.f, 60.f, 90.f, 120.f, 150.f};
@@ -607,27 +550,12 @@ public class DisplayModeDirectorTest {
RefreshRateRanges frameRateAll = new RefreshRateRanges(rangeAll, rangeAll);
RefreshRateRanges frameRate90toInf = new RefreshRateRanges(range90toInf, range90toInf);
- RefreshRateRanges frameRate0to60;
- RefreshRateRanges frameRate0to90;
- RefreshRateRanges frameRate0to120;
- RefreshRateRanges frameRate60to90;
- RefreshRateRanges frameRate90to90;
- RefreshRateRanges frameRate90to120;
- if (frameRateIsRefreshRate) {
- frameRate0to60 = new RefreshRateRanges(range0to60, range0to60);
- frameRate0to90 = new RefreshRateRanges(range0to90, range0to90);
- frameRate0to120 = new RefreshRateRanges(range0to120, range0to120);
- frameRate60to90 = new RefreshRateRanges(range60to90, range60to90);
- frameRate90to90 = new RefreshRateRanges(range90to90, range90to90);
- frameRate90to120 = new RefreshRateRanges(range90to120, range90to120);
- } else {
- frameRate0to60 = new RefreshRateRanges(rangeAll, range0to60);
- frameRate0to90 = new RefreshRateRanges(rangeAll, range0to90);
- frameRate0to120 = new RefreshRateRanges(rangeAll, range0to120);
- frameRate60to90 = new RefreshRateRanges(range60toInf, range60to90);
- frameRate90to90 = new RefreshRateRanges(range90toInf, range90to90);
- frameRate90to120 = new RefreshRateRanges(range90toInf, range90to120);
- }
+ RefreshRateRanges frameRate0to60 = new RefreshRateRanges(rangeAll, range0to60);
+ RefreshRateRanges frameRate0to90 = new RefreshRateRanges(rangeAll, range0to90);
+ RefreshRateRanges frameRate0to120 = new RefreshRateRanges(rangeAll, range0to120);
+ RefreshRateRanges frameRate60to90 = new RefreshRateRanges(range60toInf, range60to90);
+ RefreshRateRanges frameRate90to90 = new RefreshRateRanges(range90toInf, range90to90);
+ RefreshRateRanges frameRate90to120 = new RefreshRateRanges(range90toInf, range90to120);
verifySpecsWithRefreshRateSettings(director, 0, 0, 0, frameRateAll, frameRateAll);
verifySpecsWithRefreshRateSettings(director, 0, 0, 90, frameRate0to90, frameRateAll);
@@ -657,12 +585,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testBrightnessObserverCallWithRefreshRateSettings(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testBrightnessObserverCallWithRefreshRateSettings() {
// Confirm that, with varying settings for min, peak, and default refresh rate, we make the
// correct call to the brightness observer.
float[] refreshRates = {60.f, 90.f, 120.f};
@@ -677,12 +600,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testVotingWithAlwaysRespectAppRequest(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testVotingWithAlwaysRespectAppRequest() {
Display.Mode[] modes = new Display.Mode[3];
modes[0] = new Display.Mode(
/*modeId=*/50, /*width=*/1000, /*height=*/1000, 50);
@@ -711,11 +629,7 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(60);
@@ -734,23 +648,14 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(60);
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testVotingWithSwitchingTypeNone(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testVotingWithSwitchingTypeNone() {
DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -765,20 +670,11 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(
- 60);
- } else {
- assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(30);
@@ -800,12 +696,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testVotingWithSwitchingTypeRenderFrameRateOnly(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testVotingWithSwitchingTypeRenderFrameRateOnly() {
DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -820,20 +711,11 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(
- 60);
- } else {
- assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(30);
@@ -846,20 +728,11 @@ public class DisplayModeDirectorTest {
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(30);
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(30);
- } else {
- assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
- }
+ assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(30);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(30);
- assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(30);
- } else {
- assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
- assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
- }
+ assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
+ assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(30);
}
@@ -887,12 +760,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testDefaultDisplayModeIsSelectedIfAvailable(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testDefaultDisplayModeIsSelectedIfAvailable() {
final float[] refreshRates = new float[]{24f, 25f, 30f, 60f, 90f};
final int defaultModeId = 3;
DisplayModeDirector director = createDirectorFromRefreshRateArray(
@@ -1173,17 +1041,12 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestMinRefreshRate(boolean frameRateIsRefreshRate) {
+ public void testAppRequestMinRefreshRate() {
// Confirm that the app min request range doesn't include flicker or min refresh rate
// settings but does include everything else.
assertTrue(Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE
>= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
Display.Mode[] modes = new Display.Mode[3];
modes[0] = new Display.Mode(
/*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
@@ -1225,11 +1088,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestMaxRefreshRate(boolean frameRateIsRefreshRate) {
+ public void testAppRequestMaxRefreshRate() {
// Confirm that the app max request range doesn't include flicker or min refresh rate
// settings but does include everything else.
assertTrue(Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE
@@ -1243,7 +1102,6 @@ public class DisplayModeDirectorTest {
modes[2] = new Display.Mode(
/*modeId=*/90, /*width=*/1000, /*height=*/1000, 90);
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
DisplayModeDirector director = createDirectorFromModeArray(modes, modes[1]);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1254,19 +1112,11 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.render.min).isZero();
- }
+ assertThat(desiredSpecs.primary.render.min).isZero();
assertThat(desiredSpecs.primary.render.max).isAtMost(60);
assertThat(desiredSpecs.appRequest.physical.min).isAtMost(60f);
assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.render.min).isAtMost(60f);
- } else {
- assertThat(desiredSpecs.appRequest.render.min).isZero();
- }
+ assertThat(desiredSpecs.appRequest.render.min).isZero();
assertThat(desiredSpecs.appRequest.render.max).isAtLeast(90f);
votes.put(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
@@ -1288,30 +1138,16 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(75);
assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(75);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(75);
- } else {
- assertThat(desiredSpecs.primary.render.min).isZero();
- }
+ assertThat(desiredSpecs.primary.render.min).isZero();
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(75);
assertThat(desiredSpecs.appRequest.physical.min).isZero();
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(
- 75);
- } else {
- assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
- }
+ assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
assertThat(desiredSpecs.appRequest.render.min).isZero();
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(75);
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestObserver_modeId(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testAppRequestObserver_modeId() {
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 0, 0);
@@ -1373,12 +1209,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestObserver_minRefreshRate(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testAppRequestObserver_minRefreshRate() {
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 60, 0);
Vote appRequestRefreshRate =
@@ -1391,15 +1222,9 @@ public class DisplayModeDirectorTest {
Vote appRequestRefreshRateRange =
director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
assertNotNull(appRequestRefreshRateRange);
- if (frameRateIsRefreshRate) {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min)
- .isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max).isAtLeast(90);
- } else {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- }
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+ .isPositiveInfinity();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
.isWithin(FLOAT_TOLERANCE).of(60);
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max).isAtLeast(90);
@@ -1417,15 +1242,9 @@ public class DisplayModeDirectorTest {
appRequestRefreshRateRange =
director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
assertNotNull(appRequestRefreshRateRange);
- if (frameRateIsRefreshRate) {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isWithin(
- FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max).isAtLeast(90);
- } else {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- }
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+ .isPositiveInfinity();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
.isWithin(FLOAT_TOLERANCE).of(90);
@@ -1435,12 +1254,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestObserver_maxRefreshRate(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testAppRequestObserver_maxRefreshRate() {
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 0, 90);
Vote appRequestRefreshRate =
@@ -1454,13 +1268,8 @@ public class DisplayModeDirectorTest {
director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
assertNotNull(appRequestRefreshRateRange);
assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- if (frameRateIsRefreshRate) {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isWithin(FLOAT_TOLERANCE).of(90);
- } else {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- }
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+ .isPositiveInfinity();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min).isZero();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
@@ -1480,13 +1289,8 @@ public class DisplayModeDirectorTest {
director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
assertNotNull(appRequestRefreshRateRange);
assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- if (frameRateIsRefreshRate) {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- }
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+ .isPositiveInfinity();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min).isZero();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
@@ -1512,12 +1316,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestObserver_modeIdAndRefreshRateRange(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testAppRequestObserver_modeIdAndRefreshRateRange() {
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 90, 90);
@@ -1547,16 +1346,9 @@ public class DisplayModeDirectorTest {
Vote appRequestRefreshRateRange =
director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
assertNotNull(appRequestRefreshRateRange);
- if (frameRateIsRefreshRate) {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min)
- .isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isWithin(FLOAT_TOLERANCE).of(90);
- } else {
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
- assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
- .isPositiveInfinity();
- }
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
+ assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+ .isPositiveInfinity();
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
.isWithin(FLOAT_TOLERANCE).of(90);
assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
@@ -1566,12 +1358,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testAppRequestsIsTheDefaultMode(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testAppRequestsIsTheDefaultMode() {
Display.Mode[] modes = new Display.Mode[2];
modes[0] = new Display.Mode(
/*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -1600,12 +1387,7 @@ public class DisplayModeDirectorTest {
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testDisableRefreshRateSwitchingVote(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testDisableRefreshRateSwitchingVote() {
DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1650,8 +1432,8 @@ public class DisplayModeDirectorTest {
"true",
"false"
})
- public void testBaseModeIdInPrimaryRange(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testBaseModeIdInPrimaryRange(boolean supportsFrameRateOverride) {
+ when(mInjector.supportsFrameRateOverride()).thenReturn(supportsFrameRateOverride);
DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1662,12 +1444,12 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(desiredSpecs.baseModeId).isEqualTo(50);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+ if (supportsFrameRateOverride) {
assertThat(desiredSpecs.baseModeId).isEqualTo(70);
+ } else {
+ assertThat(desiredSpecs.baseModeId).isEqualTo(50);
+
}
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -1679,11 +1461,7 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.baseModeId).isEqualTo(55);
@@ -1697,12 +1475,11 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
- assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+ if (supportsFrameRateOverride) {
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(52);
+ } else {
+ assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
}
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
assertThat(desiredSpecs.baseModeId).isEqualTo(55);
@@ -1716,23 +1493,14 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(58);
- } else {
- assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
- }
+ assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(58);
assertThat(desiredSpecs.baseModeId).isEqualTo(55);
}
@Test
- @Parameters({
- "true",
- "false"
- })
- public void testStaleAppVote(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testStaleAppVote() {
Display.Mode[] modes = new Display.Mode[4];
modes[0] = new Display.Mode(
/*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -1782,8 +1550,8 @@ public class DisplayModeDirectorTest {
"true",
"false"
})
- public void testRefreshRateIsSubsetOfFrameRate(boolean frameRateIsRefreshRate) {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+ public void testRefreshRateIsSubsetOfFrameRate(boolean supportsFrameRateOverride) {
+ when(mInjector.supportsFrameRateOverride()).thenReturn(supportsFrameRateOverride);
DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1795,11 +1563,7 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
- } else {
- assertThat(desiredSpecs.appRequest.render.min).isZero();
- }
+ assertThat(desiredSpecs.appRequest.render.min).isZero();
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
votes.clear();
@@ -1810,13 +1574,11 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(
- 120);
- } else {
- assertThat(desiredSpecs.appRequest.render.min).isZero();
+ assertThat(desiredSpecs.appRequest.render.min).isZero();
+ if (supportsFrameRateOverride) {
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+ } else {
+ assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
}
votes.clear();
@@ -1827,13 +1589,12 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(
- 120);
- } else {
+ if (supportsFrameRateOverride) {
assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+ } else {
+ assertThat(desiredSpecs.appRequest.render.min).isZero();
+ assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
}
votes.clear();
@@ -1844,17 +1605,12 @@ public class DisplayModeDirectorTest {
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
- if (frameRateIsRefreshRate) {
- assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
- } else {
- assertThat(desiredSpecs.appRequest.render.min).isZero();
- }
+ assertThat(desiredSpecs.appRequest.render.min).isZero();
assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
}
@Test
public void testRenderFrameRateIsAchievableByPhysicalRefreshRate() {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(false);
DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1872,8 +1628,34 @@ public class DisplayModeDirectorTest {
}
@Test
+ @Parameters({
+ "true",
+ "false"
+ })
+ public void testRenderFrameRateIncludesPhysicalRefreshRate(boolean supportsFrameRateOverride) {
+ when(mInjector.supportsFrameRateOverride()).thenReturn(supportsFrameRateOverride);
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRenderFrameRates(0, 60));
+ votes.put(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+ Vote.forRenderFrameRates(0, 30));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.appRequest.physical.min).isZero();
+ assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
+ assertThat(desiredSpecs.appRequest.render.min).isZero();
+ if (supportsFrameRateOverride) {
+ assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(30);
+ } else {
+ assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+ }
+ }
+
+ @Test
public void testRenderFrameRateIsDroppedIfLowerPriorityThenBaseModeRefreshRate() {
- when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(false);
DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -2692,7 +2474,7 @@ public class DisplayModeDirectorTest {
}
@Override
- public boolean renderFrameRateIsPhysicalRefreshRate() {
+ public boolean supportsFrameRateOverride() {
return true;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index c898119ea991..cdb264222a7e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -443,6 +443,44 @@ public class InsetsStateControllerTest extends WindowTestsBase {
}
@Test
+ public void testUpdateAboveInsetsState_imeTargetOnScreenBehavior() {
+ final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
+ final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, imeToken, "ime");
+ final WindowState app = createTestWindow("app");
+
+ getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
+ ime.getControllableInsetProvider().setServerVisible(true);
+
+ app.mActivityRecord.setVisibility(true);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.updateImeInputAndControlTarget(app);
+
+ app.setRequestedVisibleTypes(ime(), ime());
+ getController().onInsetsModified(app);
+ assertTrue(ime.getControllableInsetProvider().getSource().isVisible());
+
+ getController().updateAboveInsetsState(true /* notifyInsetsChange */);
+ assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
+ verify(app, atLeastOnce()).notifyInsetsChanged();
+
+ // Expect the app will still get IME insets even when the app was invisible.
+ // (i.e. app invisible after locking the device)
+ app.mActivityRecord.setVisible(false);
+ app.setHasSurface(false);
+ getController().updateAboveInsetsState(true /* notifyInsetsChange */);
+ assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
+ verify(app, atLeastOnce()).notifyInsetsChanged();
+
+ // Expect the app will get IME insets when the app is requesting visible.
+ // (i.e. app is going to visible when unlocking the device)
+ app.mActivityRecord.setVisibility(true);
+ assertTrue(app.isVisibleRequested());
+ getController().updateAboveInsetsState(true /* notifyInsetsChange */);
+ assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
+ verify(app, atLeastOnce()).notifyInsetsChanged();
+ }
+
+ @Test
public void testDispatchGlobalInsets() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindowContainer(navBar, null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index c548dc3aebd5..eb26415c2b21 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -772,6 +772,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
// Simulating now win1 is being covered by the lockscreen which has no surface,
// and then launching an activity win2 with the remote animation
win1.mHasSurface = false;
+ win1.mActivityRecord.setVisibility(false);
mDisplayContent.mOpeningApps.add(win2.mActivityRecord);
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
win2.mActivityRecord, new Point(50, 100), null,