diff options
30 files changed, 434 insertions, 63 deletions
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 9d363c806f5f..3af36ebb08ca 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -28,6 +28,7 @@ import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.os.UserHandle.USER_CURRENT; import static android.os.UserHandle.USER_NULL; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID; import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE; import static com.android.server.blob.BlobStoreConfig.LOGV; @@ -1915,7 +1916,7 @@ public class BlobStoreManagerService extends SystemService { mStatsManager.setPullAtomCallback( FrameworkStatsLog.BLOB_INFO, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, mStatsCallbackImpl ); } diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java index eb1848d666f0..7e110eb741dd 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java @@ -16,6 +16,7 @@ package com.android.server.alarm; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST; import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED; import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER; @@ -31,7 +32,6 @@ import android.app.StatsManager; import android.content.Context; import android.os.SystemClock; -import com.android.internal.os.BackgroundThread; import com.android.internal.util.FrameworkStatsLog; import java.util.function.Supplier; @@ -51,7 +51,7 @@ class MetricsHelper { void registerPuller(Supplier<AlarmStore> alarmStoreSupplier) { final StatsManager statsManager = mContext.getSystemService(StatsManager.class); statsManager.setPullAtomCallback(FrameworkStatsLog.PENDING_ALARM_INFO, null, - BackgroundThread.getExecutor(), (atomTag, data) -> { + DIRECT_EXECUTOR, (atomTag, data) -> { if (atomTag != FrameworkStatsLog.PENDING_ALARM_INFO) { throw new UnsupportedOperationException("Unknown tag" + atomTag); } diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index be8b2a20cfb1..65f56f68ed3f 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -486,7 +486,7 @@ public class ServiceInfo extends ComponentInfo * Here is an example: * <pre> * <uses-permission - * android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE" + * android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" * /> * <service * android:name=".MySpecialForegroundService" @@ -506,7 +506,7 @@ public class ServiceInfo extends ComponentInfo * in both platforms. * <pre> * <uses-permission - * android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE" + * android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" * android:maxSdkVersion="last_sdk_version_without_type_foo" * /> * <service diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7bdff8c5b858..c43962d5900c 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -7397,19 +7397,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } target = next; } - if (!childIsHit) { + if (!childIsHit && mFirstHoverTarget != null) { target = mFirstHoverTarget; + final ArrayList<View> preorderedList = buildTouchDispatchChildList(); while (notEmpty && target != null) { final HoverTarget next = target.next; final View hoveredView = target.child; - rect.set(hoveredView.mLeft, hoveredView.mTop, hoveredView.mRight, - hoveredView.mBottom); - matrix.mapRect(rect); - notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), - Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE); + if (!isOnTop(child, hoveredView, preorderedList)) { + rect.set(hoveredView.mLeft, hoveredView.mTop, hoveredView.mRight, + hoveredView.mBottom); + matrix.mapRect(rect); + notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), + Math.round(rect.right), Math.round(rect.bottom), + Region.Op.DIFFERENCE); + } target = next; } + if (preorderedList != null) { + preorderedList.clear(); + } } } else { TouchTarget target = mFirstTouchTarget; @@ -7422,19 +7429,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } target = next; } - if (!childIsHit) { + if (!childIsHit && mFirstTouchTarget != null) { target = mFirstTouchTarget; + final ArrayList<View> preorderedList = buildOrderedChildList(); while (notEmpty && target != null) { final TouchTarget next = target.next; final View touchedView = target.child; - rect.set(touchedView.mLeft, touchedView.mTop, touchedView.mRight, - touchedView.mBottom); - matrix.mapRect(rect); - notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), - Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE); + if (!isOnTop(child, touchedView, preorderedList)) { + rect.set(touchedView.mLeft, touchedView.mTop, touchedView.mRight, + touchedView.mBottom); + matrix.mapRect(rect); + notEmpty = region.op(Math.round(rect.left), Math.round(rect.top), + Math.round(rect.right), Math.round(rect.bottom), + Region.Op.DIFFERENCE); + } target = next; } + if (preorderedList != null) { + preorderedList.clear(); + } } } @@ -7444,6 +7458,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return notEmpty; } + /** + * Return true if the given {@code view} is drawn on top of the {@code otherView}. + * Both the {@code view} and {@code otherView} must be children of this ViewGroup. + * Otherwise, the returned value is meaningless. + */ + private boolean isOnTop(View view, View otherView, ArrayList<View> preorderedList) { + final int childrenCount = mChildrenCount; + final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); + final View[] children = mChildren; + for (int i = childrenCount - 1; i >= 0; i--) { + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + if (child == view) { + return true; + } + if (child == otherView) { + return false; + } + } + // Can't find the view and otherView in the children list. Return value is meaningless. + return false; + } private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) { final int[] locationInWindow = new int[2]; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 63e882533a4c..c990e941a11b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -14051,7 +14051,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener selectionStart, OffsetMapping.MAP_STRATEGY_CURSOR); final int line = layout.getLineForOffset(offsetTransformed); final float insertionMarkerX = - layout.getPrimaryHorizontal(offsetTransformed) + layout.getPrimaryHorizontal( + offsetTransformed, layout.shouldClampCursor(line)) + viewportToContentHorizontalOffset; final float insertionMarkerTop = layout.getLineTop(line) + viewportToContentVerticalOffset; diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f5b0711a37aa..24dbc5eaed41 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2791,7 +2791,7 @@ <!-- Base "handwriting slop" value used by ViewConfiguration as a movement threshold where stylus handwriting should begin. --> - <dimen name="config_viewConfigurationHandwritingSlop">4dp</dimen> + <dimen name="config_viewConfigurationHandwritingSlop">2dp</dimen> <!-- Base "hover slop" value used by ViewConfiguration as a movement threshold under which hover is considered "stationary". --> @@ -5348,6 +5348,10 @@ to enroll the other eligible biometric. --> <fraction name="config_biometricNotificationFrrThreshold">25%</fraction> + <!-- Whether to enable the biometric notification for dual-modality device that enrolled a + single biometric and experiences high FRR. --> + <bool name="config_biometricFrrNotificationEnabled">false</bool> + <!-- The component name for the default profile supervisor, which can be set as a profile owner even after user setup is complete. The defined component should be used for supervision purposes only. The component must be part of a system app. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c78af86f0f39..be43a4fc238d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2584,6 +2584,7 @@ <!-- Biometric FRR config --> <java-symbol type="fraction" name="config_biometricNotificationFrrThreshold" /> + <java-symbol type="bool" name="config_biometricFrrNotificationEnabled" /> <!-- Biometric FRR notification messages --> <java-symbol type="string" name="device_unlock_notification_name" /> diff --git a/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java index 60a0a2adbbbe..c210fd631f06 100644 --- a/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java +++ b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java @@ -90,22 +90,73 @@ public class ViewGroupGetChildLocalHitRegionTest { assertGetChildLocalHitRegionEmpty(R.id.view_cover_top, R.id.view_cover_bottom); } + @Test + public void testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView() { + // In this case, two views overlap with each other and the MotionEvent is injected to the + // bottom view. It verifies that the hit region of the top view won't be blocked by the + // bottom view. + testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView(/* isHover= */ true); + testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView(/* isHover= */ false); + } + + private void testGetChildLocalHitRegion_topViewIsNotBlockedByBottomView(boolean isHover) { + // In this case, two views overlap with each other and the MotionEvent is injected to the + // bottom view. It verifies that the hit region of the top view won't be blocked by the + // bottom view. + mScenarioRule.getScenario().onActivity(activity -> { + View viewTop = activity.findViewById(R.id.view_overlap_top); + View viewBottom = activity.findViewById(R.id.view_overlap_bottom); + + // The viewTop covers the left side of the viewBottom. To avoid the MotionEvent gets + // blocked by viewTop, we inject MotionEvents into viewBottom's right bottom corner. + float x = viewBottom.getWidth() - 1; + float y = viewBottom.getHeight() - 1; + injectMotionEvent(viewBottom, x, y, isHover); + + Matrix actualMatrix = new Matrix(); + Region actualRegion = new Region(0, 0, viewTop.getWidth(), viewTop.getHeight()); + boolean actualNotEmpty = viewTop.getParent() + .getChildLocalHitRegion(viewTop, actualRegion, actualMatrix, isHover); + + int[] windowLocation = new int[2]; + viewTop.getLocationInWindow(windowLocation); + Matrix expectMatrix = new Matrix(); + expectMatrix.preTranslate(-windowLocation[0], -windowLocation[1]); + // Though viewTop and viewBottom overlaps, viewTop's hit region won't be blocked by + // viewBottom. + Region expectRegion = new Region(0, 0, viewTop.getWidth(), viewTop.getHeight()); + + assertThat(actualNotEmpty).isTrue(); + assertThat(actualMatrix).isEqualTo(expectMatrix); + assertThat(actualRegion).isEqualTo(expectRegion); + }); + } + private void injectMotionEvent(View view, boolean isHover) { + float x = view.getWidth() / 2f; + float y = view.getHeight() / 2f; + injectMotionEvent(view, x, y, isHover); + } + + /** + * Inject MotionEvent into the given view, at the given location specified in the view's + * coordinates. + */ + private void injectMotionEvent(View view, float x, float y, boolean isHover) { int[] location = new int[2]; view.getLocationInWindow(location); - float x = location[0] + view.getWidth() / 2f; - float y = location[1] + view.getHeight() / 2f; + float globalX = location[0] + x; + float globalY = location[1] + y; int action = isHover ? MotionEvent.ACTION_HOVER_ENTER : MotionEvent.ACTION_DOWN; MotionEvent motionEvent = MotionEvent.obtain(/* downtime= */ 0, /* eventTime= */ 0, action, - x, y, /* pressure= */ 0, /* size= */ 0, /* metaState= */ 0, + globalX, globalY, /* pressure= */ 0, /* size= */ 0, /* metaState= */ 0, /* xPrecision= */ 1, /* yPrecision= */ 1, /* deviceId= */0, /* edgeFlags= */0); View rootView = view.getRootView(); rootView.dispatchPointerEvent(motionEvent); } - private void assertGetChildLocalHitRegion(int viewId) { assertGetChildLocalHitRegion(viewId, /* isHover= */ true); assertGetChildLocalHitRegion(viewId, /* isHover= */ false); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 5b9b53e65ff4..e2855c9e7260 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -4214,7 +4214,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final boolean previousState = mAllowFingerprintOnCurrentOccludingActivity; mAllowFingerprintOnCurrentOccludingActivity = - standardTask.topActivity != null + standardTask != null && standardTask.topActivity != null && !TextUtils.isEmpty(standardTask.topActivity.getPackageName()) && mAllowFingerprintOnOccludingActivitiesFromPackage.contains( standardTask.topActivity.getPackageName()) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt index 94b5fb2861b1..21451dc0ffdf 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt @@ -58,6 +58,7 @@ abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>( // Notification shade can be expanded but not visible (fraction: 0.0), for example // when a heads-up notification (HUN) is showing. notificationShadeVisible = event.expanded && event.fraction > 0f + notificationShadeTracking = event.tracking view.onExpansionChanged(event.fraction) updatePauseAuth() } @@ -65,6 +66,9 @@ abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>( /** If the notification shade is visible. */ var notificationShadeVisible: Boolean = false + /** If the notification shade is currently being dragged */ + var notificationShadeTracking: Boolean = false + /** * The amount of translation needed if the view currently requires the user to touch * somewhere other than the exact center of the sensor. For example, this can happen diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt index 802eea300bd4..96354c2a99ff 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.biometrics +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeExpansionStateManager @@ -39,6 +40,12 @@ class UdfpsBpViewController( override val tag = "UdfpsBpViewController" override fun shouldPauseAuth(): Boolean { - return false + // Do not auth while notification shade is being dragged + return notificationShadeTracking + } + + @VisibleForTesting + public override fun onViewAttached() { + super.onViewAttached() } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index a36870346b9a..c29f884c848d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -549,8 +549,12 @@ public class UdfpsController implements DozeReceiver, Dumpable { Log.e(TAG, "ignoring the touch injected from outside of UdfpsView"); return false; } - if (mOverlay == null) { - Log.w(TAG, "ignoring onTouch with null overlay"); + if (mOverlay == null || mOverlay.getAnimationViewController() == null) { + Log.w(TAG, "ignoring onTouch with null overlay or animation view controller"); + return false; + } + if (mOverlay.getAnimationViewController().shouldPauseAuth()) { + Log.w(TAG, "ignoring onTouch with shouldPauseAuth = true"); return false; } if (!mOverlay.matchesRequestId(requestId)) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index 656411874de5..54eba34ed55c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -479,11 +479,13 @@ constructor( if (largeScreenActive) { logInstantEvent("Large screen constraints set") header.setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID) + systemIcons.isClickable = true systemIcons.setOnClickListener { shadeCollapseAction?.run() } } else { logInstantEvent("Small screen constraints set") header.setTransition(HEADER_TRANSITION_ID) systemIcons.setOnClickListener(null) + systemIcons.isClickable = false } header.jumpToState(header.startState) updatePosition() 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 a243356c8690..e76bae5e955b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2368,10 +2368,16 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // * When phone is unlocked: we still don't want to execute hiding of the keyguard // as the animation could prepare 'fake AOD' interface (without actually // transitioning to keyguard state) and this might reset the view states + // Log for b/290627350 + Log.d(TAG, "!shouldBeKeyguard mStatusBarStateController.isKeyguardRequested() " + + mStatusBarStateController.isKeyguardRequested() + " keyguardForDozing " + + keyguardForDozing + " wakeAndUnlocking " + wakeAndUnlocking + + " isWakingAndOccluded " + isWakingAndOccluded); if (!mScreenOffAnimationController.isKeyguardHideDelayed() // If we're animating occluded, there's an activity launching over the keyguard // UI. Wait to hide it until after the animation concludes. && !mKeyguardViewMediator.isOccludeAnimationPlaying()) { + Log.d(TAG, "hideKeyguardImpl " + forceStateChange); return hideKeyguardImpl(forceStateChange); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt index 7de78a60b73e..9be3d8201053 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt @@ -23,14 +23,19 @@ import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.phone.SystemUIDialogManager +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor import org.junit.Assert.assertFalse import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit @SmallTest @@ -51,6 +56,8 @@ class UdfpsBpViewControllerTest : SysuiTestCase() { @Before fun setup() { + whenever(shadeExpansionStateManager.addExpansionListener(any())) + .thenReturn(ShadeExpansionChangeEvent(0f, false, false, 0f)) udfpsBpViewController = UdfpsBpViewController( udfpsBpView, @@ -62,7 +69,32 @@ class UdfpsBpViewControllerTest : SysuiTestCase() { } @Test - fun testShouldNeverPauseAuth() { + fun testPauseAuthWhenNotificationShadeDragging() { + udfpsBpViewController.onViewAttached() + val shadeExpansionListener = withArgCaptor { + verify(shadeExpansionStateManager).addExpansionListener(capture()) + } + + // When shade is tracking, should pause auth + shadeExpansionListener.onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = 0f, + expanded = false, + tracking = true, + dragDownPxAmount = 10f + ) + ) + assert(udfpsBpViewController.shouldPauseAuth()) + + // When shade is not tracking, don't pause auth even if expanded + shadeExpansionListener.onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = 0f, + expanded = true, + tracking = false, + dragDownPxAmount = 10f + ) + ) assertFalse(udfpsBpViewController.shouldPauseAuth()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index e56b5c7406b6..7dd88b437f17 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -207,6 +207,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private final UdfpsAnimationViewController mUdfpsKeyguardViewController = mock(UdfpsKeyguardViewControllerLegacy.class); @Mock + private UdfpsAnimationViewController mUdfpsAnimationViewController; + @Mock private SystemUIDialogManager mSystemUIDialogManager; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; @@ -267,6 +269,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mSessionTracker.getSessionId(anyInt())).thenReturn( (new InstanceIdSequence(1 << 20)).newInstanceId()); when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl); + when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsAnimationViewController); final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, @@ -1380,6 +1383,50 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test + public void onTouch_withNewTouchDetection_ignoreIfAuthPaused() throws RemoteException { + final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L, + 0L); + final TouchProcessorResult processorResultDown = + new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN, + 1 /* pointerId */, touchData); + + // Enable new touch detection. + when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true); + + // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider. + initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */); + + // Configure UdfpsView to not accept the ACTION_DOWN event + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); + + // GIVEN that auth is paused + when(mUdfpsAnimationViewController.shouldPauseAuth()).thenReturn(true); + + // GIVEN that the overlay is showing and a11y touch exploration NOT enabled + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, + BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + + verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // WHEN ACTION_DOWN is received and touch is within sensor + when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn( + processorResultDown); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); + mBiometricExecutor.runAllReady(); + downEvent.recycle(); + + // THEN the touch is ignored + verify(mInputManager, never()).pilferPointers(any()); + verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), + anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), + anyBoolean()); + } + + @Test public void onTouch_withNewTouchDetection_pilferPointer() throws RemoteException { final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L, 0L); diff --git a/services/core/java/com/android/server/LogMteState.java b/services/core/java/com/android/server/LogMteState.java index 410dd8339b30..ec0492b19f89 100644 --- a/services/core/java/com/android/server/LogMteState.java +++ b/services/core/java/com/android/server/LogMteState.java @@ -16,11 +16,12 @@ package com.android.server; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import android.app.StatsManager; import android.content.Context; import android.util.StatsEvent; -import com.android.internal.os.BackgroundThread; import com.android.internal.os.Zygote; import com.android.internal.util.FrameworkStatsLog; @@ -32,7 +33,7 @@ public class LogMteState { .setPullAtomCallback( FrameworkStatsLog.MTE_STATE, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, new StatsManager.StatsPullAtomCallback() { @Override public int onPullAtom(int atomTag, List<StatsEvent> data) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 66ea4d06d2b7..592628af2a8d 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -97,6 +97,11 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_BG_LAUNCH; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_DELEGATE; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NONE; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_FOREGROUND_SERVICE; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_SERVICE; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER; import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT; @@ -122,6 +127,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.Manifest; +import android.Manifest.permission; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -901,7 +907,10 @@ public final class ActiveServices { showFgsBgRestrictedNotificationLocked(r); logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid)) { throw new ForegroundServiceStartNotAllowedException(msg); } @@ -2066,6 +2075,7 @@ public final class ActiveServices { boolean alreadyStartedOp = false; boolean stopProcStatsOp = false; + final boolean origFgRequired = r.fgRequired; if (r.fgRequired) { if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Service called startForeground() as required: " + r); @@ -2117,6 +2127,9 @@ public final class ActiveServices { // Whether to extend the SHORT_SERVICE time out. boolean extendShortServiceTimeout = false; + // Whether setFgsRestrictionLocked() is called in here. Only used for logging. + boolean fgsRestrictionRecalculated = false; + int fgsTypeCheckCode = FGS_TYPE_POLICY_CHECK_UNKNOWN; if (!ignoreForeground) { if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_SHORT_SERVICE @@ -2182,6 +2195,7 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + fgsRestrictionRecalculated = true; if (!r.isFgsAllowedStart()) { Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: " + " BFSL DENIED."); @@ -2246,6 +2260,7 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + fgsRestrictionRecalculated = true; final String temp = "startForegroundDelayMs:" + delayMs; if (r.mInfoAllowStartForeground != null) { r.mInfoAllowStartForeground += "; " + temp; @@ -2266,6 +2281,25 @@ public final class ActiveServices { r.appInfo.uid, r.intent.getIntent(), r, r.userId, BackgroundStartPrivileges.NONE, false /* isBindService */); + fgsRestrictionRecalculated = true; + } + + // When startForeground() is called on a bound service, without having + // it started (i.e. no Context.startService() or startForegroundService() was + // called.) + // called on it, then we probably didn't call setFgsRestrictionLocked() + // in startService(). If fgsRestrictionRecalculated is false, then we + // didn't call setFgsRestrictionLocked() here either. + // + // In this situation, we call setFgsRestrictionLocked() with + // forBoundFgs = false, so we'd set the FGS allowed reason to the + // by-bindings fields, so we can put it in the log, without affecting the + // logic. + if (!fgsRestrictionRecalculated && !r.startRequested) { + setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(), + r.appInfo.uid, r.intent.getIntent(), r, r.userId, + BackgroundStartPrivileges.NONE, + false /* isBindService */, true /* forBoundFgs */); } // If the foreground service is not started from TOP process, do not allow it to @@ -2291,7 +2325,10 @@ public final class ActiveServices { ignoreForeground = true; logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)) { throw new ForegroundServiceStartNotAllowedException(msg); @@ -2331,7 +2368,10 @@ public final class ActiveServices { if (fgsTypeResult.second != null) { logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN, fgsTypeResult.first); + 0, FGS_STOP_REASON_UNKNOWN, fgsTypeResult.first, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); throw fgsTypeResult.second; } } @@ -2403,9 +2443,24 @@ public final class ActiveServices { AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); + + int fgsStartApi = FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NONE; + if (r.startRequested) { + if (origFgRequired) { + fgsStartApi = + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_FOREGROUND_SERVICE; + } else { + fgsStartApi = + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_START_SERVICE; + } + } + logFGSStateChangeLocked(r, FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, - 0, FGS_STOP_REASON_UNKNOWN, fgsTypeCheckCode); + 0, FGS_STOP_REASON_UNKNOWN, fgsTypeCheckCode, + fgsStartApi, + fgsRestrictionRecalculated + ); synchronized (mFGSLogger) { mFGSLogger.logForegroundServiceStart(r.appInfo.uid, 0, r); } @@ -2499,7 +2554,10 @@ public final class ActiveServices { r.mFgsExitTime > r.mFgsEnterTime ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, FGS_STOP_REASON_STOP_FOREGROUND, - FGS_TYPE_POLICY_CHECK_UNKNOWN); + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); synchronized (mFGSLogger) { mFGSLogger.logForegroundServiceStop(r.appInfo.uid, r); @@ -3338,7 +3396,10 @@ public final class ActiveServices { FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, nowUptime > sr.mFgsEnterTime ? (int) (nowUptime - sr.mFgsEnterTime) : 0, FGS_STOP_REASON_UNKNOWN, - FGS_TYPE_POLICY_CHECK_UNKNOWN); + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); try { sr.app.getThread().scheduleTimeoutService(sr, sr.getShortFgsInfo().getStartId()); } catch (RemoteException e) { @@ -5685,7 +5746,10 @@ public final class ActiveServices { r.mFgsExitTime > r.mFgsEnterTime ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, FGS_STOP_REASON_STOP_SERVICE, - FGS_TYPE_POLICY_CHECK_UNKNOWN); + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); synchronized (mFGSLogger) { mFGSLogger.logForegroundServiceStop(r.appInfo.uid, r); } @@ -7430,6 +7494,13 @@ public final class ActiveServices { } } + private void setFgsRestrictionLocked(String callingPackage, + int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, + BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId, + backgroundStartPrivileges, isBindService, /*forBoundFgs*/ false); + } + /** * There are two FGS restrictions: * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground @@ -7441,11 +7512,14 @@ public final class ActiveServices { * @param intent intent to start/bind service. * @param r the service to start. * @param isBindService True if it's called from bindService(). + * @param forBoundFgs set to true if it's called from Service.startForeground() for a + * service that's not started but bound. * @return true if allow, false otherwise. */ private void setFgsRestrictionLocked(String callingPackage, int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId, - BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) { + BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService, + boolean forBoundFgs) { @ReasonCode int allowWIU; @ReasonCode int allowStart; @@ -7489,9 +7563,19 @@ public final class ActiveServices { r.mAllowWIUInBindService = allowWIU; r.mAllowStartInBindService = allowStart; } else { - r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU; - r.mAllowStartForegroundNoBinding = allowStart; - + if (!forBoundFgs) { + // This is for "normal" situation. + r.mAllowWhileInUsePermissionInFgsReasonNoBinding = allowWIU; + r.mAllowStartForegroundNoBinding = allowStart; + } else { + // This logic is only for logging, so we only update the "by-binding" fields. + if (r.mAllowWIUByBindings == REASON_DENIED) { + r.mAllowWIUByBindings = allowWIU; + } + if (r.mAllowStartByBindings == REASON_DENIED) { + r.mAllowStartByBindings = allowStart; + } + } // Also do a binding client check, unless called from bindService(). if (r.mAllowWIUByBindings == REASON_DENIED) { r.mAllowWIUByBindings = @@ -8115,7 +8199,10 @@ public final class ActiveServices { */ private void logFGSStateChangeLocked(ServiceRecord r, int state, int durationMs, @FgsStopReason int fgsStopReason, - @ForegroundServicePolicyCheckCode int fgsTypeCheckCode) { + @ForegroundServicePolicyCheckCode int fgsTypeCheckCode, + int fgsStartApi, // from ForegroundServiceStateChanged.FgsStartApi + boolean fgsRestrictionRecalculated + ) { if (!ActivityManagerUtils.shouldSamplePackageForAtom( r.packageName, mAm.mConstants.mFgsAtomSampleRate)) { return; @@ -8172,7 +8259,9 @@ public final class ActiveServices { r.mAllowWIUByBindings, r.mAllowStartForegroundNoBinding, r.mAllowStartInBindService, - r.mAllowStartByBindings); + r.mAllowStartByBindings, + fgsStartApi, + fgsRestrictionRecalculated); int event = 0; if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) { @@ -8351,7 +8440,10 @@ public final class ActiveServices { } logFGSStateChangeLocked(r, FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, - 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_DELEGATE, + false /* fgsRestrictionRecalculated */ + ); // Notify the caller. if (connection != null) { mAm.mHandler.post(() -> { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1fa60fef401b..47abc1092c49 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16767,7 +16767,7 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i = 0; i < N; i++) { PendingTempAllowlist ptw = list[i]; mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid, - ptw.duration, ptw.type, true, ptw.reasonCode, ptw.tag, + ptw.duration, ptw.type, false, ptw.reasonCode, ptw.tag, ptw.callingUid); } } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 2c745ae3bf55..be123f36ebcc 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -27,6 +27,8 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.RequiresNoPermission; @@ -95,7 +97,6 @@ import android.util.StatsEvent; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; -import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.PowerProfile; import com.android.internal.os.RailStats; @@ -839,15 +840,15 @@ public final class BatteryStatsService extends IBatteryStats.Stub statsManager.setPullAtomCallback( FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), pullAtomCallback); + DIRECT_EXECUTOR, pullAtomCallback); statsManager.setPullAtomCallback( FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET_USING_POWER_PROFILE_MODEL, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), pullAtomCallback); + DIRECT_EXECUTOR, pullAtomCallback); statsManager.setPullAtomCallback( FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), pullAtomCallback); + DIRECT_EXECUTOR, pullAtomCallback); } /** StatsPullAtomCallback for pulling BatteryUsageStats data. */ diff --git a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java index f6859d1f027e..e0a71d46641a 100644 --- a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java +++ b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java @@ -27,6 +27,8 @@ import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_PHONE_CALL import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_USB; import static android.os.Process.INVALID_UID; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA; + import android.annotation.IntDef; import android.app.ActivityManager; import android.app.ActivityManager.ForegroundServiceApiType; @@ -520,7 +522,10 @@ public class ForegroundServiceTypeLoggerModule { r.mAllowWIUByBindings, r.mAllowStartForegroundNoBinding, r.mAllowStartInBindService, - r.mAllowStartByBindings); + r.mAllowStartByBindings, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false + ); } /** @@ -578,7 +583,10 @@ public class ForegroundServiceTypeLoggerModule { 0, 0, 0, - 0); + 0, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false + ); } /** diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 80d14a21cc7e..0c9cb3bd00f8 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -25,6 +25,7 @@ import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscali import static com.android.internal.R.styleable.GameModeConfig_allowGameFpsOverride; import static com.android.internal.R.styleable.GameModeConfig_supportsBatteryGameMode; import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanceGameMode; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.Manifest; import android.annotation.NonNull; @@ -2092,17 +2093,17 @@ public final class GameManagerService extends IGameManagerService.Stub { statsManager.setPullAtomCallback( FrameworkStatsLog.GAME_MODE_INFO, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, this::onPullAtom); statsManager.setPullAtomCallback( FrameworkStatsLog.GAME_MODE_CONFIGURATION, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, this::onPullAtom); statsManager.setPullAtomCallback( FrameworkStatsLog.GAME_MODE_LISTENER, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, this::onPullAtom); } diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java index 64691e0b062b..b2b6ee65761e 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java @@ -57,6 +57,7 @@ public class AuthenticationStatsCollector { @NonNull private final FaceManager mFaceManager; @NonNull private final FingerprintManager mFingerprintManager; + private final boolean mEnabled; private final float mThreshold; private final int mModality; private boolean mPersisterInitialized = false; @@ -83,6 +84,7 @@ public class AuthenticationStatsCollector { public AuthenticationStatsCollector(@NonNull Context context, int modality, @NonNull BiometricNotification biometricNotification) { mContext = context; + mEnabled = context.getResources().getBoolean(R.bool.config_biometricFrrNotificationEnabled); mThreshold = context.getResources() .getFraction(R.fraction.config_biometricNotificationFrrThreshold, 1, 1); mUserAuthenticationStatsMap = new HashMap<>(); @@ -116,6 +118,11 @@ public class AuthenticationStatsCollector { /** Update total authentication and rejected attempts. */ public void authenticate(int userId, boolean authenticated) { + // Don't collect data if the feature is disabled. + if (!mEnabled) { + return; + } + // Don't collect data for single-modality devices or user has both biometrics enrolled. if (isSingleModalityDevice() || (hasEnrolledFace(userId) && hasEnrolledFingerprint(userId))) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c24e729cbff5..e633ba6886d0 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2632,7 +2632,7 @@ public class NotificationManagerService extends SystemService { mStatsManager.setPullAtomCallback( DND_MODE_RULE, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + ConcurrentUtils.DIRECT_EXECUTOR, mPullAtomCallback ); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index f5c5867edb53..ca0c1f98fe0d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -23,6 +23,7 @@ import static android.os.UserManager.DISALLOW_USER_SWITCH; import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY; import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN_ADMIN; @@ -5234,12 +5235,12 @@ public class UserManagerService extends IUserManager.Stub { statsManager.setPullAtomCallback( FrameworkStatsLog.USER_INFO, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, this::onPullAtom); statsManager.setPullAtomCallback( FrameworkStatsLog.MULTI_USER_INFO, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, this::onPullAtom); } diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index 1a91d252c431..f425ba32ced0 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -16,6 +16,8 @@ package com.android.server.power.hint; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -37,7 +39,6 @@ import android.util.StatsEvent; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; @@ -142,7 +143,7 @@ public final class HintManagerService extends SystemService { statsManager.setPullAtomCallback( FrameworkStatsLog.ADPF_SYSTEM_COMPONENT_INFO, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, this::onPullAtom); } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 9128974fa9d3..79b2836e237d 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -1599,7 +1599,7 @@ public class StatsPullAtomService extends SystemService { mStatsManager.setPullAtomCallback( tagId, metadata, - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, mStatsCallbackImpl ); } @@ -1612,7 +1612,7 @@ public class StatsPullAtomService extends SystemService { mStatsManager.setPullAtomCallback( tagId, metadata, - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, mStatsCallbackImpl ); } @@ -1625,7 +1625,7 @@ public class StatsPullAtomService extends SystemService { mStatsManager.setPullAtomCallback( tagId, metadata, - BackgroundThread.getExecutor(), + DIRECT_EXECUTOR, mStatsCallbackImpl ); } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 3639e1b9cb47..d2d6552a0c9c 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -661,6 +661,10 @@ final class LetterboxUiController { @ScreenOrientation int overrideOrientationIfNeeded(@ScreenOrientation int candidate) { if (shouldApplyUserFullscreenOverride()) { + Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for " + + mActivityRecord + " is overridden to " + + screenOrientationToString(SCREEN_ORIENTATION_USER) + + " by user aspect ratio settings."); return SCREEN_ORIENTATION_USER; } @@ -668,6 +672,14 @@ final class LetterboxUiController { // orientation. candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate); + if (shouldApplyUserMinAspectRatioOverride() && !isFixedOrientation(candidate)) { + Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for " + + mActivityRecord + " is overridden to " + + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT) + + " by user aspect ratio settings."); + return SCREEN_ORIENTATION_PORTRAIT; + } + if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) { return candidate; } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java index fa6e7f60c1b0..ba77390d5e3f 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java @@ -87,6 +87,8 @@ public class AuthenticationStatsCollectorTest { public void setUp() { when(mContext.getResources()).thenReturn(mResources); + when(mResources.getBoolean(eq(R.bool.config_biometricFrrNotificationEnabled))) + .thenReturn(true); when(mResources.getFraction(eq(R.fraction.config_biometricNotificationFrrThreshold), anyInt(), anyInt())).thenReturn(FRR_THRESHOLD); @@ -109,7 +111,6 @@ public class AuthenticationStatsCollectorTest { 0 /* modality */, mBiometricNotification); } - @Test public void authenticate_authenticationSucceeded_mapShouldBeUpdated() { // Assert that the user doesn't exist in the map initially. @@ -341,4 +342,32 @@ public class AuthenticationStatsCollectorTest { // Assert that notification count has been updated. assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(1); } + + @Test + public void authenticate_featureDisabled_mapMustNotBeUpdated() { + // Disable the feature. + when(mResources.getBoolean(eq(R.bool.config_biometricFrrNotificationEnabled))) + .thenReturn(false); + AuthenticationStatsCollector authenticationStatsCollector = + new AuthenticationStatsCollector(mContext, 0 /* modality */, + mBiometricNotification); + + authenticationStatsCollector.setAuthenticationStatsForUser(USER_ID_1, + new AuthenticationStats(USER_ID_1, 500 /* totalAttempts */, + 400 /* rejectedAttempts */, 0 /* enrollmentNotifications */, + 0 /* modality */)); + + authenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */); + + // Assert that no notification should be sent. + verify(mBiometricNotification, never()).sendFaceEnrollNotification(any()); + verify(mBiometricNotification, never()).sendFpEnrollNotification(any()); + // Assert that data hasn't been updated. + AuthenticationStats authenticationStats = authenticationStatsCollector + .getAuthenticationStatsForUser(USER_ID_1); + assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500); + assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400); + assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0); + assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 0566f460c655..381b27b68b41 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -811,6 +811,28 @@ public class LetterboxUiControllerTest extends WindowTestsBase { /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT); } + @Test + public void testOverrideOrientationIfNeeded_userAspectRatioApplied_unspecifiedOverridden() { + spyOn(mController); + doReturn(true).when(mController).shouldApplyUserMinAspectRatioOverride(); + + assertEquals(mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT); + + // unchanged if orientation is specified + assertEquals(mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_LANDSCAPE), SCREEN_ORIENTATION_LANDSCAPE); + } + + @Test + public void testOverrideOrientationIfNeeded_userAspectRatioNotApplied_returnsUnchanged() { + spyOn(mController); + doReturn(false).when(mController).shouldApplyUserMinAspectRatioOverride(); + + assertEquals(mController.overrideOrientationIfNeeded( + /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED); + } + // shouldApplyUser...Override @Test public void testShouldApplyUserFullscreenOverride_trueProperty_returnsFalse() throws Exception { |