Merge "Update TEST_MAPPING for ravenwood" into main
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 32c40df..ea9bb39 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -46,7 +46,6 @@
import android.os.WorkSource;
import android.util.ArraySet;
import android.util.Pair;
-import android.util.StatsEvent;
import com.android.internal.os.TimeoutRecord;
@@ -1224,7 +1223,8 @@
* @return The stats event for the cached apps high watermark since last pull.
*/
@NonNull
- public abstract StatsEvent getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull);
+ // TODO: restore to android.util.StatsEvent once Ravenwood includes Mainline stubs
+ public abstract Object getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull);
/**
* Internal method for clearing app data, with the extra param that is used to indicate restore.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 11660f9..7e07e1f 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -853,6 +853,7 @@
args.argi2 = pid;
args.argi3 = Long.hashCode(Thread.currentThread().getId());
args.argi4 = THREAD_PRIORITY_DEFAULT;
+ args.arg1 = Boolean.TRUE; // backgroundOk
return args;
});
}
@@ -1105,6 +1106,11 @@
final SomeArgs args =
Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
if (args.argi3 == tid) {
+ boolean backgroundOk = (args.arg1 == Boolean.TRUE);
+ if (priority >= THREAD_PRIORITY_BACKGROUND && !backgroundOk) {
+ throw new IllegalArgumentException(
+ "Priority " + priority + " blocked by setCanSelfBackground()");
+ }
args.argi4 = priority;
} else {
throw new UnsupportedOperationException(
@@ -1119,8 +1125,16 @@
*
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native void setCanSelfBackground(boolean backgroundOk);
+ /** @hide */
+ public static final void setCanSelfBackground$ravenwood(boolean backgroundOk) {
+ final SomeArgs args =
+ Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
+ args.arg1 = Boolean.valueOf(backgroundOk);
+ }
+
/**
* Sets the scheduling group for a thread.
* @hide
diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java
index 9c632ea..2a10918 100644
--- a/core/java/com/android/server/LocalServices.java
+++ b/core/java/com/android/server/LocalServices.java
@@ -29,6 +29,7 @@
*
* {@hide}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class LocalServices {
private LocalServices() {}
@@ -69,4 +70,14 @@
sLocalServiceObjects.remove(type);
}
}
+
+ /**
+ * Remove all known service instances, must be only used in tests.
+ */
+ @VisibleForTesting
+ public static void removeAllServicesForTest() {
+ synchronized (sLocalServiceObjects) {
+ sLocalServiceObjects.clear();
+ }
+ }
}
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml
index 6979825..e4befc2 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml
@@ -70,6 +70,7 @@
<style name="SettingsSwitchPreferenceCompat.SettingsLib" parent="@style/Preference.SwitchPreferenceCompat.Material">
<item name="layout">@layout/settingslib_preference</item>
+ <item name="singleLineTitle">false</item>
<item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item>
</style>
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index ba80a8d..1a653c3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -34,9 +34,9 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
@@ -66,6 +66,7 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
@@ -97,7 +98,7 @@
fun BouncerContent(
viewModel: BouncerViewModel,
dialogFactory: BouncerDialogFactory,
- modifier: Modifier
+ modifier: Modifier = Modifier,
) {
val isFullScreenUserSwitcherEnabled = viewModel.isUserSwitcherVisible
val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState()
@@ -142,6 +143,7 @@
viewModel: BouncerViewModel,
dialogFactory: BouncerDialogFactory,
modifier: Modifier = Modifier,
+ layout: BouncerSceneLayout = BouncerSceneLayout.STANDARD,
outputOnly: Boolean = false,
) {
val foldPosture: FoldPosture by foldPosture()
@@ -161,6 +163,7 @@
FoldSplittable(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ layout = layout,
outputOnly = outputOnly,
isSplit = false,
)
@@ -170,6 +173,7 @@
FoldSplittable(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ layout = layout,
outputOnly = outputOnly,
isSplit = true,
)
@@ -193,6 +197,7 @@
private fun SceneScope.FoldSplittable(
viewModel: BouncerViewModel,
dialogFactory: BouncerDialogFactory,
+ layout: BouncerSceneLayout,
outputOnly: Boolean,
isSplit: Boolean,
modifier: Modifier = Modifier,
@@ -210,13 +215,21 @@
// Content above the fold, when split on a foldable device in a "table top" posture:
Box(
modifier =
- Modifier.element(SceneElements.AboveFold).fillMaxWidth().thenIf(isSplit) {
- Modifier.weight(splitRatio)
- },
+ Modifier.element(SceneElements.AboveFold)
+ .fillMaxWidth()
+ .then(
+ if (isSplit) {
+ Modifier.weight(splitRatio)
+ } else if (outputOnly) {
+ Modifier.fillMaxHeight()
+ } else {
+ Modifier
+ }
+ ),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth().padding(top = 92.dp),
+ modifier = Modifier.fillMaxWidth().padding(top = layout.topPadding),
) {
Crossfade(
targetState = message,
@@ -230,11 +243,23 @@
)
}
- Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp))
+ if (!outputOnly) {
+ Spacer(Modifier.height(layout.spacingBetweenMessageAndEnteredInput))
+ UserInputArea(
+ viewModel = viewModel,
+ visibility = UserInputAreaVisibility.OUTPUT_ONLY,
+ layout = layout,
+ )
+ }
+ }
+
+ if (outputOnly) {
UserInputArea(
viewModel = viewModel,
visibility = UserInputAreaVisibility.OUTPUT_ONLY,
+ layout = layout,
+ modifier = Modifier.align(Alignment.Center),
)
}
}
@@ -242,25 +267,32 @@
// Content below the fold, when split on a foldable device in a "table top" posture:
Box(
modifier =
- Modifier.element(SceneElements.BelowFold).fillMaxWidth().thenIf(isSplit) {
- Modifier.weight(1 - splitRatio)
- },
+ Modifier.element(SceneElements.BelowFold)
+ .fillMaxWidth()
+ .weight(
+ if (isSplit) {
+ 1 - splitRatio
+ } else {
+ 1f
+ }
+ ),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxSize()
) {
if (!outputOnly) {
Box(Modifier.weight(1f)) {
UserInputArea(
viewModel = viewModel,
visibility = UserInputAreaVisibility.INPUT_ONLY,
- modifier = Modifier.align(Alignment.Center),
+ layout = layout,
+ modifier = Modifier.align(Alignment.BottomCenter),
)
}
}
- Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp))
+ Spacer(Modifier.height(48.dp))
val actionButtonModifier = Modifier.height(56.dp)
@@ -275,7 +307,7 @@
}
}
- Spacer(Modifier.height(48.dp))
+ Spacer(Modifier.height(layout.bottomPadding))
}
}
@@ -311,6 +343,7 @@
private fun UserInputArea(
viewModel: BouncerViewModel,
visibility: UserInputAreaVisibility,
+ layout: BouncerSceneLayout,
modifier: Modifier = Modifier,
) {
val authMethodViewModel: AuthMethodBouncerViewModel? by
@@ -327,6 +360,7 @@
UserInputAreaVisibility.INPUT_ONLY ->
PinPad(
viewModel = nonNullViewModel,
+ layout = layout,
modifier = modifier,
)
}
@@ -341,7 +375,8 @@
if (visibility == UserInputAreaVisibility.INPUT_ONLY) {
PatternBouncer(
viewModel = nonNullViewModel,
- modifier = modifier.aspectRatio(1f, matchHeightConstraintsFirst = false)
+ layout = layout,
+ modifier = modifier.aspectRatio(1f, matchHeightConstraintsFirst = false),
)
}
else -> Unit
@@ -449,7 +484,7 @@
}
/**
- * Renders the dropdown menu that displays the actual users and/or user actions that can be
+ * Renders the dropdowm menu that displays the actual users and/or user actions that can be
* selected.
*/
@Composable
@@ -519,6 +554,7 @@
StandardLayout(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ layout = BouncerSceneLayout.SPLIT,
outputOnly = true,
modifier = startContentModifier,
)
@@ -527,10 +563,12 @@
UserInputArea(
viewModel = viewModel,
visibility = UserInputAreaVisibility.INPUT_ONLY,
+ layout = BouncerSceneLayout.SPLIT,
modifier = endContentModifier,
)
},
- modifier = modifier
+ layout = BouncerSceneLayout.SPLIT,
+ modifier = modifier,
)
}
@@ -542,6 +580,7 @@
private fun SwappableLayout(
startContent: @Composable (Modifier) -> Unit,
endContent: @Composable (Modifier) -> Unit,
+ layout: BouncerSceneLayout,
modifier: Modifier = Modifier,
) {
val layoutDirection = LocalLayoutDirection.current
@@ -597,7 +636,7 @@
alpha = animatedAlpha(animatedOffset)
}
) {
- endContent(Modifier.widthIn(max = 400.dp).align(Alignment.BottomCenter))
+ endContent(Modifier.align(layout.swappableEndContentAlignment).widthIn(max = 400.dp))
}
}
}
@@ -635,9 +674,11 @@
StandardLayout(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ layout = BouncerSceneLayout.SIDE_BY_SIDE,
modifier = endContentModifier,
)
},
+ layout = BouncerSceneLayout.SIDE_BY_SIDE,
modifier = modifier,
)
}
@@ -663,6 +704,7 @@
StandardLayout(
viewModel = viewModel,
dialogFactory = dialogFactory,
+ layout = BouncerSceneLayout.STACKED,
modifier = Modifier.fillMaxWidth().weight(1f),
)
}
@@ -732,3 +774,48 @@
private val SceneTransitions = transitions {
from(SceneKeys.ContiguousSceneKey, to = SceneKeys.SplitSceneKey) { spec = tween() }
}
+
+/** Whether a more compact size should be used for various spacing dimensions. */
+internal val BouncerSceneLayout.isUseCompactSize: Boolean
+ get() =
+ when (this) {
+ BouncerSceneLayout.SIDE_BY_SIDE -> true
+ BouncerSceneLayout.SPLIT -> true
+ else -> false
+ }
+
+/** Amount of space to place between the message and the entered input UI elements, in dips. */
+private val BouncerSceneLayout.spacingBetweenMessageAndEnteredInput: Dp
+ get() =
+ when {
+ this == BouncerSceneLayout.STACKED -> 24.dp
+ isUseCompactSize -> 96.dp
+ else -> 128.dp
+ }
+
+/** Amount of space to place above the topmost UI element, in dips. */
+private val BouncerSceneLayout.topPadding: Dp
+ get() =
+ if (this == BouncerSceneLayout.SPLIT) {
+ 40.dp
+ } else {
+ 92.dp
+ }
+
+/** Amount of space to place below the bottommost UI element, in dips. */
+private val BouncerSceneLayout.bottomPadding: Dp
+ get() =
+ if (this == BouncerSceneLayout.SPLIT) {
+ 40.dp
+ } else {
+ 48.dp
+ }
+
+/** The in-a-box alignment for the content on the "end" side of a swappable layout. */
+private val BouncerSceneLayout.swappableEndContentAlignment: Alignment
+ get() =
+ if (this == BouncerSceneLayout.SPLIT) {
+ Alignment.Center
+ } else {
+ Alignment.BottomCenter
+ }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index eb06889..2799959 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -18,8 +18,6 @@
import android.view.ViewTreeObserver
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.LocalTextStyle
@@ -31,7 +29,6 @@
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -64,10 +61,6 @@
focusRequester.requestFocus()
}
}
- val (isTextFieldFocused, onTextFieldFocusChanged) = remember { mutableStateOf(false) }
- LaunchedEffect(isTextFieldFocused) {
- viewModel.onTextFieldFocusChanged(isFocused = isTextFieldFocused)
- }
val password: String by viewModel.password.collectAsState()
val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
@@ -113,7 +106,7 @@
),
modifier =
Modifier.focusRequester(focusRequester)
- .onFocusChanged { onTextFieldFocusChanged(it.isFocused) }
+ .onFocusChanged { viewModel.onTextFieldFocusChanged(it.isFocused) }
.drawBehind {
drawLine(
color = color,
@@ -123,8 +116,6 @@
)
},
)
-
- Spacer(Modifier.height(100.dp))
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index ff1cbd6..a4b1955 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -48,6 +48,7 @@
import com.android.compose.animation.Easings
import com.android.compose.modifiers.thenIf
import com.android.internal.R
+import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternDotViewModel
import kotlin.math.min
@@ -64,6 +65,7 @@
@Composable
internal fun PatternBouncer(
viewModel: PatternBouncerViewModel,
+ layout: BouncerSceneLayout,
modifier: Modifier = Modifier,
) {
DisposableEffect(Unit) {
@@ -190,6 +192,8 @@
// This is the position of the input pointer.
var inputPosition: Offset? by remember { mutableStateOf(null) }
var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
+ var offset: Offset by remember { mutableStateOf(Offset.Zero) }
+ var scale: Float by remember { mutableStateOf(1f) }
Canvas(
modifier
@@ -224,21 +228,42 @@
},
) { change, _ ->
inputPosition = change.position
- viewModel.onDrag(
- xPx = change.position.x,
- yPx = change.position.y,
- containerSizePx = size.width,
- )
+ change.position.minus(offset).div(scale).let {
+ viewModel.onDrag(
+ xPx = it.x,
+ yPx = it.y,
+ containerSizePx = size.width,
+ )
+ }
}
}
}
) {
gridCoordinates?.let { nonNullCoordinates ->
val containerSize = nonNullCoordinates.size
+ if (containerSize.width <= 0 || containerSize.height <= 0) {
+ return@let
+ }
+
val horizontalSpacing = containerSize.width.toFloat() / colCount
val verticalSpacing = containerSize.height.toFloat() / rowCount
val spacing = min(horizontalSpacing, verticalSpacing)
- val verticalOffset = containerSize.height - spacing * rowCount
+ val horizontalOffset =
+ offset(
+ availableSize = containerSize.width,
+ spacingPerDot = spacing,
+ dotCount = colCount,
+ isCentered = true,
+ )
+ val verticalOffset =
+ offset(
+ availableSize = containerSize.height,
+ spacingPerDot = spacing,
+ dotCount = rowCount,
+ isCentered = layout.isCenteredVertically,
+ )
+ offset = Offset(horizontalOffset, verticalOffset)
+ scale = (colCount * spacing) / containerSize.width
if (isAnimationEnabled) {
// Draw lines between dots.
@@ -248,8 +273,9 @@
val lineFadeOutAnimationProgress =
lineFadeOutAnimatables[previousDot]!!.value
val startLerp = 1 - lineFadeOutAnimationProgress
- val from = pixelOffset(previousDot, spacing, verticalOffset)
- val to = pixelOffset(dot, spacing, verticalOffset)
+ val from =
+ pixelOffset(previousDot, spacing, horizontalOffset, verticalOffset)
+ val to = pixelOffset(dot, spacing, horizontalOffset, verticalOffset)
val lerpedFrom =
Offset(
x = from.x + (to.x - from.x) * startLerp,
@@ -270,7 +296,7 @@
// position.
inputPosition?.let { lineEnd ->
currentDot?.let { dot ->
- val from = pixelOffset(dot, spacing, verticalOffset)
+ val from = pixelOffset(dot, spacing, horizontalOffset, verticalOffset)
val lineLength =
sqrt((from.y - lineEnd.y).pow(2) + (from.x - lineEnd.x).pow(2))
drawLine(
@@ -288,7 +314,7 @@
// Draw each dot on the grid.
dots.forEach { dot ->
drawCircle(
- center = pixelOffset(dot, spacing, verticalOffset),
+ center = pixelOffset(dot, spacing, horizontalOffset, verticalOffset),
color = dotColor,
radius = dotRadius * (dotScalingAnimatables[dot]?.value ?: 1f),
)
@@ -301,10 +327,11 @@
private fun pixelOffset(
dot: PatternDotViewModel,
spacing: Float,
+ horizontalOffset: Float,
verticalOffset: Float,
): Offset {
return Offset(
- x = dot.x * spacing + spacing / 2,
+ x = dot.x * spacing + spacing / 2 + horizontalOffset,
y = dot.y * spacing + spacing / 2 + verticalOffset,
)
}
@@ -371,6 +398,35 @@
}
}
+/**
+ * Returns the amount of offset along the axis, in pixels, that should be applied to all dots.
+ *
+ * @param availableSize The size of the container, along the axis of interest.
+ * @param spacingPerDot The amount of pixels that each dot should take (including the area around
+ * that dot).
+ * @param dotCount The number of dots along the axis (e.g. if the axis of interest is the
+ * horizontal/x axis, this is the number of columns in the dot grid).
+ * @param isCentered Whether the dots should be centered along the axis of interest; if `false`, the
+ * dots will be pushed towards to end/bottom of the axis.
+ */
+private fun offset(
+ availableSize: Int,
+ spacingPerDot: Float,
+ dotCount: Int,
+ isCentered: Boolean = false,
+): Float {
+ val default = availableSize - spacingPerDot * dotCount
+ return if (isCentered) {
+ default / 2
+ } else {
+ default
+ }
+}
+
+/** Whether the UI should be centered vertically. */
+private val BouncerSceneLayout.isCenteredVertically: Boolean
+ get() = this == BouncerSceneLayout.SPLIT
+
private const val DOT_DIAMETER_DP = 16
private const val SELECTED_DOT_DIAMETER_DP = 24
private const val SELECTED_DOT_REACTION_ANIMATION_DURATION_MS = 83
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 59617c9..8f5d9f4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -52,6 +52,7 @@
import com.android.compose.animation.Easings
import com.android.compose.grid.VerticalGrid
import com.android.compose.modifiers.thenIf
+import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
import com.android.systemui.bouncer.ui.viewmodel.ActionButtonAppearance
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.common.shared.model.ContentDescription
@@ -65,9 +66,11 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+/** Renders the PIN button pad. */
@Composable
fun PinPad(
viewModel: PinBouncerViewModel,
+ layout: BouncerSceneLayout,
modifier: Modifier = Modifier,
) {
DisposableEffect(Unit) {
@@ -92,9 +95,9 @@
}
VerticalGrid(
- columns = 3,
- verticalSpacing = 12.dp,
- horizontalSpacing = 20.dp,
+ columns = columns,
+ verticalSpacing = layout.verticalSpacing,
+ horizontalSpacing = calculateHorizontalSpacingBetweenColumns(layout.gridWidth),
modifier = modifier,
) {
repeat(9) { index ->
@@ -254,7 +257,7 @@
val cornerRadius: Dp by
animateDpAsState(
- if (isAnimationEnabled && isPressed) 24.dp else pinButtonSize / 2,
+ if (isAnimationEnabled && isPressed) 24.dp else pinButtonMaxSize / 2,
label = "PinButton round corners",
animationSpec = tween(animDurationMillis, easing = animEasing)
)
@@ -284,7 +287,7 @@
contentAlignment = Alignment.Center,
modifier =
modifier
- .sizeIn(maxWidth = pinButtonSize, maxHeight = pinButtonSize)
+ .sizeIn(maxWidth = pinButtonMaxSize, maxHeight = pinButtonMaxSize)
.aspectRatio(1f)
.drawBehind {
drawRoundRect(
@@ -345,10 +348,32 @@
}
}
-private val pinButtonSize = 84.dp
-private val pinButtonErrorShrinkFactor = 67.dp / pinButtonSize
+/** Returns the amount of horizontal spacing between columns, in dips. */
+private fun calculateHorizontalSpacingBetweenColumns(
+ gridWidth: Dp,
+): Dp {
+ return (gridWidth - (pinButtonMaxSize * columns)) / (columns - 1)
+}
+
+/** The width of the grid of PIN pad buttons, in dips. */
+private val BouncerSceneLayout.gridWidth: Dp
+ get() = if (isUseCompactSize) 292.dp else 300.dp
+
+/** The spacing between rows of PIN pad buttons, in dips. */
+private val BouncerSceneLayout.verticalSpacing: Dp
+ get() = if (isUseCompactSize) 8.dp else 12.dp
+
+/** Number of columns in the PIN pad grid. */
+private const val columns = 3
+/** Maximum size (width and height) of each PIN pad button. */
+private val pinButtonMaxSize = 84.dp
+/** Scale factor to apply to buttons when animating the "error" animation on them. */
+private val pinButtonErrorShrinkFactor = 67.dp / pinButtonMaxSize
+/** Animation duration of the "shrink" phase of the error animation, on each PIN pad button. */
private const val pinButtonErrorShrinkMs = 50
+/** Amount of time to wait between application of the "error" animation to each row of buttons. */
private const val pinButtonErrorStaggerDelayMs = 33
+/** Animation duration of the "revert" phase of the error animation, on each PIN pad button. */
private const val pinButtonErrorRevertMs = 617
// Pin button motion spec: http://shortn/_9TTIG6SoEa
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 80d45bc..78b854e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -22,8 +22,11 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
import com.android.internal.util.LatencyTracker
import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockscreenCredential
+import com.android.keyguard.KeyguardPinViewController.PinBouncerUiEvent
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
@@ -91,6 +94,7 @@
@Mock lateinit var passwordTextView: PasswordTextView
@Mock lateinit var deleteButton: NumPadButton
@Mock lateinit var enterButton: View
+ @Mock lateinit var uiEventLogger: UiEventLogger
@Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
@@ -137,6 +141,7 @@
postureController,
featureFlags,
mSelectedUserInteractor,
+ uiEventLogger
)
}
@@ -251,4 +256,21 @@
verify(lockPatternUtils).getCurrentFailedPasswordAttempts(anyInt())
}
+
+ @Test
+ fun onUserInput_autoConfirmation_attemptsUnlock() {
+ val pinViewController = constructPinViewController(mockKeyguardPinView)
+ whenever(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
+ whenever(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
+ whenever(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
+ whenever(passwordTextView.text).thenReturn("000000")
+ whenever(enterButton.visibility).thenReturn(View.INVISIBLE)
+ whenever(mockKeyguardPinView.enteredCredential)
+ .thenReturn(LockscreenCredential.createPin("000000"))
+
+ pinViewController.onUserInput()
+
+ verify(uiEventLogger).log(PinBouncerUiEvent.ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE)
+ verify(keyguardUpdateMonitor).setCredentialAttempted()
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index b309483..714fe64 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -26,6 +26,7 @@
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -210,6 +211,7 @@
private final KeyguardViewController mKeyguardViewController;
private final FeatureFlags mFeatureFlags;
private final SelectedUserInteractor mSelectedUserInteractor;
+ private final UiEventLogger mUiEventLogger;
@Inject
public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -222,7 +224,8 @@
EmergencyButtonController.Factory emergencyButtonControllerFactory,
DevicePostureController devicePostureController,
KeyguardViewController keyguardViewController,
- FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor) {
+ FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor,
+ UiEventLogger uiEventLogger) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
@@ -238,6 +241,7 @@
mKeyguardViewController = keyguardViewController;
mFeatureFlags = featureFlags;
mSelectedUserInteractor = selectedUserInteractor;
+ mUiEventLogger = uiEventLogger;
}
/** Create a new {@link KeyguardInputViewController}. */
@@ -265,7 +269,8 @@
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
mLiftToActivateListener, emergencyButtonController, mFalsingCollector,
- mDevicePostureController, mFeatureFlags, mSelectedUserInteractor);
+ mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
+ mUiEventLogger);
} else if (keyguardInputView instanceof KeyguardSimPinView) {
return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 947d90f..2aab1f1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -20,6 +20,8 @@
import android.view.View;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -44,6 +46,7 @@
private View mOkButton = mView.findViewById(R.id.key_enter);
private long mPinLength;
+ private final UiEventLogger mUiEventLogger;
private boolean mDisabledAutoConfirmation;
@@ -56,7 +59,8 @@
EmergencyButtonController emergencyButtonController,
FalsingCollector falsingCollector,
DevicePostureController postureController,
- FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor) {
+ FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor,
+ UiEventLogger uiEventLogger) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor);
@@ -67,6 +71,7 @@
view.setIsLockScreenLandscapeEnabled(mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE));
mBackspaceKey = view.findViewById(R.id.delete_button);
mPinLength = mLockPatternUtils.getPinLength(selectedUserInteractor.getSelectedUserId());
+ mUiEventLogger = uiEventLogger;
}
@Override
@@ -95,6 +100,7 @@
updateAutoConfirmationState();
if (mPasswordEntry.getText().length() == mPinLength
&& mOkButton.getVisibility() == View.INVISIBLE) {
+ mUiEventLogger.log(PinBouncerUiEvent.ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE);
verifyPasswordAndUnlock();
}
}
@@ -184,4 +190,21 @@
mSelectedUserInteractor.getSelectedUserId())
&& mPinLength != LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
}
+
+ /** UI Events for the auto confirmation feature in*/
+ enum PinBouncerUiEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Attempting to unlock the device with the auto confirm feature.")
+ ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE(1547);
+
+ private final int mId;
+
+ PinBouncerUiEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index c1871e0..71bac06 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -209,11 +209,11 @@
return result
}
- open fun enableShowProtection(show: Boolean) {
- if (showProtection == show) {
+ open fun enableShowProtection(isCameraActive: Boolean) {
+ if (showProtection == isCameraActive) {
return
}
- showProtection = show
+ showProtection = isCameraActive
updateProtectionBoundingPath()
// Delay the relayout until the end of the animation when hiding the cutout,
// otherwise we'd clip it.
diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
index ab35e06..3abcb13 100644
--- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
@@ -28,12 +28,10 @@
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
-import android.hardware.biometrics.BiometricSourceType
import android.view.View
import androidx.core.graphics.ColorUtils
import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
import com.android.systemui.biometrics.AuthController
import com.android.systemui.log.ScreenDecorationsLogger
@@ -66,26 +64,11 @@
com.android.internal.R.attr.materialColorPrimaryFixed)
private var cameraProtectionAnimator: ValueAnimator? = null
var hideOverlayRunnable: Runnable? = null
- var faceAuthSucceeded = false
init {
visibility = View.INVISIBLE // only show this view when face scanning is happening
}
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- mainExecutor.execute {
- keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
- }
- }
-
- override fun onDetachedFromWindow() {
- super.onDetachedFromWindow()
- mainExecutor.execute {
- keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
- }
- }
-
override fun setColor(color: Int) {
cameraProtectionColor = color
invalidate()
@@ -103,18 +86,22 @@
}
}
- override fun enableShowProtection(show: Boolean) {
- val animationRequired =
+ override fun enableShowProtection(isCameraActive: Boolean) {
+ val scanningAnimationRequiredWhenCameraActive =
keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing
- val showScanningAnimNow = animationRequired && show
- if (showScanningAnimNow == showScanningAnim) {
+ val faceAuthSucceeded = keyguardUpdateMonitor.isFaceAuthenticated
+ val showScanningAnimationNow = scanningAnimationRequiredWhenCameraActive && isCameraActive
+ if (showScanningAnimationNow == showScanningAnim) {
return
}
- logger.cameraProtectionShownOrHidden(keyguardUpdateMonitor.isFaceDetectionRunning,
+ logger.cameraProtectionShownOrHidden(
+ showScanningAnimationNow,
+ keyguardUpdateMonitor.isFaceDetectionRunning,
authController.isShowing,
- show,
+ faceAuthSucceeded,
+ isCameraActive,
showScanningAnim)
- showScanningAnim = showScanningAnimNow
+ showScanningAnim = showScanningAnimationNow
updateProtectionBoundingPath()
// Delay the relayout until the end of the animation when hiding,
// otherwise we'd clip it.
@@ -125,7 +112,7 @@
cameraProtectionAnimator?.cancel()
cameraProtectionAnimator = ValueAnimator.ofFloat(cameraProtectionProgress,
- if (showScanningAnimNow) SHOW_CAMERA_PROTECTION_SCALE
+ if (showScanningAnimationNow) SHOW_CAMERA_PROTECTION_SCALE
else HIDDEN_CAMERA_PROTECTION_SCALE).apply {
startDelay =
if (showScanningAnim) 0
@@ -335,70 +322,16 @@
invalidate()
}
- private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
- override fun onBiometricAuthenticated(
- userId: Int,
- biometricSourceType: BiometricSourceType?,
- isStrongBiometric: Boolean
- ) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- post {
- faceAuthSucceeded = true
- logger.biometricEvent("biometricAuthenticated")
- enableShowProtection(false)
- }
- }
- }
-
- override fun onBiometricAcquired(
- biometricSourceType: BiometricSourceType?,
- acquireInfo: Int
- ) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- post {
- faceAuthSucceeded = false // reset
- }
- }
- }
-
- override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- post {
- faceAuthSucceeded = false
- logger.biometricEvent("biometricFailed")
- enableShowProtection(false)
- }
- }
- }
-
- override fun onBiometricError(
- msgId: Int,
- errString: String?,
- biometricSourceType: BiometricSourceType?
- ) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- post {
- faceAuthSucceeded = false
- logger.biometricEvent("biometricError")
- enableShowProtection(false)
- }
- }
- }
- }
-
companion object {
private const val HIDDEN_RIM_SCALE = HIDDEN_CAMERA_PROTECTION_SCALE
private const val SHOW_CAMERA_PROTECTION_SCALE = 1f
- private const val PULSE_RADIUS_IN = 1.1f
private const val PULSE_RADIUS_OUT = 1.125f
private const val PULSE_RADIUS_SUCCESS = 1.25f
private const val CAMERA_PROTECTION_APPEAR_DURATION = 250L
private const val PULSE_APPEAR_DURATION = 250L // without start delay
- private const val HALF_PULSE_DURATION = 500L
-
private const val PULSE_SUCCESS_DISAPPEAR_DURATION = 400L
private const val CAMERA_PROTECTION_SUCCESS_DISAPPEAR_DURATION = 500L // without start delay
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index 702a23e..e1c6f41 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -35,7 +35,7 @@
*
* To enable logcat echoing for an entire buffer:
* ```
- * adb shell settings put global systemui/buffer/ScreenDecorationsLog <logLevel>
+ * adb shell cmd statusbar echo -b ScreenDecorationsLog:<logLevel>
*
* ```
*/
@@ -134,33 +134,35 @@
}
fun cameraProtectionShownOrHidden(
+ showAnimationNow: Boolean,
faceDetectionRunning: Boolean,
biometricPromptShown: Boolean,
- requestedState: Boolean,
+ faceAuthenticated: Boolean,
+ isCameraActive: Boolean,
currentlyShowing: Boolean
) {
logBuffer.log(
TAG,
DEBUG,
{
+ str1 = "$showAnimationNow"
bool1 = faceDetectionRunning
bool2 = biometricPromptShown
- bool3 = requestedState
+ str2 = "$faceAuthenticated"
+ bool3 = isCameraActive
bool4 = currentlyShowing
},
{
- "isFaceDetectionRunning: $bool1, " +
+ "cameraProtectionShownOrHidden showAnimationNow: $str1, " +
+ "isFaceDetectionRunning: $bool1, " +
"isBiometricPromptShowing: $bool2, " +
- "requestedState: $bool3, " +
+ "faceAuthenticated: $str2, " +
+ "isCameraActive: $bool3, " +
"currentState: $bool4"
}
)
}
- fun biometricEvent(@CompileTimeConstant info: String) {
- logBuffer.log(TAG, DEBUG, info)
- }
-
fun cameraProtectionEvent(@CompileTimeConstant cameraProtectionEvent: String) {
logBuffer.log(TAG, DEBUG, cameraProtectionEvent)
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index be0c09e..eacdc2f 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -32,6 +32,8 @@
android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
android.os.Binder.init$ravenwood();
+ com.android.server.LocalServices.removeAllServicesForTest();
+
if (rule.mProvideMainThread) {
final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME);
main.start();
@@ -45,6 +47,8 @@
Looper.clearMainLooperForTest();
}
+ com.android.server.LocalServices.removeAllServicesForTest();
+
android.os.Process.reset$ravenwood();
android.os.Binder.reset$ravenwood();
}
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eba6e0b..72e9ba3 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -64,3 +64,5 @@
android.graphics.PointF
android.graphics.Rect
android.graphics.RectF
+
+com.android.server.LocalServices
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index e3797c9..f55ecb0 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -916,18 +916,27 @@
&& event.getPointerCount() == 2;
mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
- if (isActivated() && event.getPointerCount() == 2) {
- storePointerDownLocation(mSecondPointerDownLocation, event);
- mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
- ViewConfiguration.getTapTimeout());
- } else if (mIsTwoFingerCountReached) {
- // Placing two-finger triple-taps behind isActivated to avoid
- // blocking panning scaling state
+ if (event.getPointerCount() == 2) {
if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)) {
// 3tap and hold
afterLongTapTimeoutTransitionToDraggingState(event);
} else {
- afterMultiTapTimeoutTransitionToDelegatingState();
+ if (mDetectTwoFingerTripleTap) {
+ // If mDetectTwoFingerTripleTap, delay transition to the delegating
+ // state for mMultiTapMaxDelay to ensure reachability of
+ // multi finger multi tap
+ afterMultiTapTimeoutTransitionToDelegatingState();
+ }
+
+ if (isActivated()) {
+ // If activated, delay transition to the panning scaling
+ // state for tap timeout to ensure reachability of
+ // multi finger multi tap
+ storePointerDownLocation(mSecondPointerDownLocation, event);
+ mHandler.sendEmptyMessageDelayed(
+ MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
+ ViewConfiguration.getTapTimeout());
+ }
}
} else {
transitionToDelegatingStateAndClear();
@@ -953,6 +962,9 @@
// (which is a rare combo to be used aside from magnification)
if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
transitionToViewportDraggingStateAndClear(event);
+ } else if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)
+ && event.getPointerCount() == 2) {
+ transitionToViewportDraggingStateAndClear(event);
} else if (isActivated() && event.getPointerCount() == 2) {
if (mIsSinglePanningEnabled
&& overscrollState(event, mFirstPointerDownLocation)
@@ -961,11 +973,6 @@
}
//Primary pointer is swiping, so transit to PanningScalingState
transitToPanningScalingStateAndClear();
- } else if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)
- && event.getPointerCount() == 2) {
- // Placing two-finger triple-taps behind isActivated to avoid
- // blocking panning scaling state
- transitionToViewportDraggingStateAndClear(event);
} else if (mIsSinglePanningEnabled
&& isActivated()
&& event.getPointerCount() == 1) {
@@ -979,8 +986,11 @@
}
} else if (isActivated() && pointerDownValid(mSecondPointerDownLocation)
&& distanceClosestPointerToPoint(
- mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
- //Second pointer is swiping, so transit to PanningScalingState
+ mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance
+ // If mCompleteTapCount is not zero, it means that it is a multi tap
+ // gesture. So, we should not transit to the PanningScalingState.
+ && mCompletedTapCount == 0) {
+ // Second pointer is swiping, so transit to PanningScalingState
transitToPanningScalingStateAndClear();
}
}
@@ -988,6 +998,7 @@
case ACTION_UP: {
mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
+ mHandler.removeMessages(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE);
if (!mFullScreenMagnificationController.magnificationRegionContains(
mDisplayId, event.getX(), event.getY())) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 898b693..31c9348 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -45,7 +45,6 @@
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.permission.persistence.RuntimePermissionsState;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.KnownPackages;
import com.android.server.pm.PackageArchiver;
@@ -1104,7 +1103,9 @@
* Read legacy permission states for permissions migration to new permission subsystem.
* Note that this api is supposed to be used for permissions state migration only.
*/
- public abstract RuntimePermissionsState getLegacyPermissionsState(@UserIdInt int userId);
+ // TODO: restore to com.android.permission.persistence.RuntimePermissionsState
+ // once Ravenwood includes Mainline stubs
+ public abstract Object getLegacyPermissionsState(@UserIdInt int userId);
/**
* @return permissions file version for the given user.
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 35c6120..d359280 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -467,8 +467,7 @@
}
public byte[] getUuid() throws RemoteException {
- //TODO(b/247124878): return the UUID defined in this file when the API is put in use
- throw new RemoteException("This API is not implemented yet.");
+ return UUID;
}
@Override
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index af6a002..b23ccb8 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -397,6 +397,9 @@
@Nullable Certificate[] trustedInstallers,
Map<Integer, ApkChecksum> checksums,
@NonNull Injector injector) {
+ if (!file.exists()) {
+ return;
+ }
final String filePath = file.getAbsolutePath();
// Always available: FSI or IncFs.
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index ba2cf1d..1a65297 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -690,6 +690,9 @@
pkgSetting.setInstallReason(installReason, userId);
pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId);
pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId);
+ // Clear any existing archive state.
+ pkgSetting.setArchiveTimeMillis(0, userId);
+ pkgSetting.setArchiveState(null, userId);
mPm.mSettings.writePackageRestrictionsLPr(userId);
mPm.mSettings.writeKernelMappingLPr(pkgSetting);
installed = true;
@@ -2263,6 +2266,9 @@
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId,
installerPackageName);
}
+ // Clear any existing archive state.
+ ps.setArchiveState(null, userId);
+ ps.setArchiveTimeMillis(0, userId);
} else if (allUsers != null) {
// The caller explicitly specified INSTALL_ALL_USERS flag.
// Thus, updating the settings to install the app for all users.
@@ -2285,6 +2291,9 @@
ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
installerPackageName);
}
+ // Clear any existing archive state.
+ ps.setArchiveState(null, currentUserId);
+ ps.setArchiveTimeMillis(0, currentUserId);
} else {
ps.setInstalled(false, currentUserId);
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 293b873..26dc576 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -770,6 +770,11 @@
onChanged();
}
+ void setArchiveState(ArchiveState archiveState, int userId) {
+ modifyUserState(userId).setArchiveState(archiveState);
+ onChanged();
+ }
+
void setArchiveTimeMillis(long value, int userId) {
modifyUserState(userId).setArchiveTimeMillis(value);
onChanged();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java
index dbf4047..28818f7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java
@@ -93,7 +93,7 @@
Map<Integer, Map<String, LegacyPermissionState>> appIdPermissionStates = new ArrayMap<>();
RuntimePermissionsState legacyState =
- mPackageManagerInternal.getLegacyPermissionsState(userId);
+ (RuntimePermissionsState) mPackageManagerInternal.getLegacyPermissionsState(userId);
PackageManagerLocal packageManagerLocal =
LocalManagerRegistry.getManager(PackageManagerLocal.class);
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 940feb5..e876241 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -4871,7 +4871,7 @@
}
private int pullCachedAppsHighWatermark(int atomTag, List<StatsEvent> pulledData) {
- pulledData.add(LocalServices.getService(ActivityManagerInternal.class)
+ pulledData.add((StatsEvent) LocalServices.getService(ActivityManagerInternal.class)
.getCachedAppsHighWatermarkStats(atomTag, true));
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 3b39160..9114027 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -588,6 +588,38 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ public void testTwoFingerTap_StateIsActivated_shouldInDelegating() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
+ mMgh.setSinglePanningEnabled(false);
+ goFromStateIdleTo(STATE_ACTIVATED);
+ allowEventDelegation();
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+ send(upEvent());
+ fastForward(ViewConfiguration.getDoubleTapTimeout());
+
+ assertTrue(mMgh.mCurrentState == mMgh.mDelegatingState);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+ public void testTwoFingerTap_StateIsIdle_shouldInDelegating() {
+ assumeTrue(mMgh.mIsSinglePanningEnabled);
+ mMgh.setSinglePanningEnabled(false);
+ goFromStateIdleTo(STATE_IDLE);
+ allowEventDelegation();
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+ send(upEvent());
+ fastForward(ViewConfiguration.getDoubleTapTimeout());
+
+ assertTrue(mMgh.mCurrentState == mMgh.mDelegatingState);
+ }
+
+ @Test
public void testMultiTap_outOfDistanceSlop_shouldInIdle() {
// All delay motion events should be sent, if multi-tap with out of distance slop.
// STATE_IDLE will check if tapCount() < 2.
@@ -719,6 +751,20 @@
}
@Test
+ public void testTwoFingerDown_twoPointerDownAndActivatedState_panningState() {
+ goFromStateIdleTo(STATE_ACTIVATED);
+ PointF pointer1 = DEFAULT_POINT;
+ PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+ fastForward(ViewConfiguration.getTapTimeout());
+ assertIn(STATE_PANNING);
+
+ returnToNormalFrom(STATE_PANNING);
+ }
+
+ @Test
public void testActivatedWithTripleTap_invokeShowWindowPromptAction() {
goFromStateIdleTo(STATE_ACTIVATED);
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index d415dc5..0e2e158 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -284,6 +284,7 @@
java_host_for_device {
name: "hoststubgen-helper-libcore-runtime.ravenwood",
+ defaults: ["hoststubgen-for-prototype-only-java"],
libs: [
"hoststubgen-helper-libcore-runtime",
],