diff options
96 files changed, 1442 insertions, 1271 deletions
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 9933c8be6015..54fb4e72a79c 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -234,6 +234,24 @@ public abstract class PackageManager { "android.camera.PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT"; /** + * Application level {@link android.content.pm.PackageManager.Property PackageManager + * .Property} for a privileged system installer to define a list of up to 500 packages that + * should not have their updates owned by any installer. The list must be provided via a default + * XML resource with the following format: + * + * <pre> + * <deny-ownership>PACKAGE_NAME</deny-ownership> + * <deny-ownership>PACKAGE_NAME</deny-ownership> + * </pre> + * + * <b>NOTE:</b> Installers that provide this property will not granted update ownership for any + * packages that they request update ownership of. + * @hide + */ + public static final String PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST = + "android.app.PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST"; + + /** * A property value set within the manifest. * <p> * The value of a property will only have a single type, as defined by diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 3c5757dd5615..5d6dfc760b02 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -63,6 +63,7 @@ import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; +import java.util.Locale; import java.util.Objects; import java.util.concurrent.Executor; @@ -1956,9 +1957,8 @@ public class CallLog { userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI, user.getIdentifier()); - if (VERBOSE_LOG) { - Log.v(LOG_TAG, String.format("Inserting to %s", uri)); - } + Log.i(LOG_TAG, String.format(Locale.getDefault(), + "addEntryAndRemoveExpiredEntries: provider uri=%s", uri)); try { // When cleaning up the call log, try to delete older call long entries on a per diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 3da9e96618f3..f39122a0a5c1 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -8207,7 +8207,8 @@ public class Editor { */ void beforeSetText() { // TextView#setText is called because our call to - // TextView#setTransformationMethodInternal in enterInsertMode() or exitInsertMode(). + // TextView#setTransformationMethodInternal in enterInsertMode(), exitInsertMode() or + // updateTransformationMethod(). // Do nothing in this case. if (mUpdatingTransformationMethod) { return; @@ -8218,22 +8219,28 @@ public class Editor { } /** - * Notify the {@link InsertModeController} before the TextView's - * {@link TransformationMethod} is updated. If it's not in the insert mode, - * the given method is directly returned. Otherwise, it will wrap the given transformation - * method with an {@link InsertModeTransformationMethod} and then return. + * Notify the {@link InsertModeController} that TextView#setTransformationMethod is called. + * If it's not in the insert mode, the given transformation method is directly set to the + * TextView. Otherwise, it will wrap the given transformation method with an + * {@link InsertModeTransformationMethod} and then set it on the TextView. * - * @param oldTransformationMethod the new {@link TransformationMethod} to be set on the + * @param transformationMethod the new {@link TransformationMethod} to be set on the * TextView. - * @return the updated {@link TransformationMethod} to be set on the Textview. */ - TransformationMethod updateTransformationMethod( - TransformationMethod oldTransformationMethod) { - if (!mIsInsertModeActive) return oldTransformationMethod; + void updateTransformationMethod(TransformationMethod transformationMethod) { + if (!mIsInsertModeActive) { + setTransformationMethod(transformationMethod, /* updateText */ true); + return; + } + // Changing TransformationMethod will reset selection range to [0, 0), we need to + // manually restore the old selection range. + final int selectionStart = mTextView.getSelectionStart(); + final int selectionEnd = mTextView.getSelectionEnd(); mInsertModeTransformationMethod = mInsertModeTransformationMethod.update( - oldTransformationMethod, mTextView.isSingleLine()); - return mInsertModeTransformationMethod; + transformationMethod, mTextView.isSingleLine()); + setTransformationMethod(mInsertModeTransformationMethod, /* updateText */ true); + Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd); } } @@ -8259,18 +8266,11 @@ public class Editor { * @param method the {@link TransformationMethod} to be set on the TextView. */ void setTransformationMethod(TransformationMethod method) { - if (mInsertModeController == null || !mInsertModeController.mIsInsertModeActive) { + if (mInsertModeController == null) { mTextView.setTransformationMethodInternal(method, /* updateText */ true); return; } - - // Changing TransformationMethod will reset selection range to [0, 0), we need to - // manually restore the old selection range. - final int selectionStart = mTextView.getSelectionStart(); - final int selectionEnd = mTextView.getSelectionEnd(); - method = mInsertModeController.updateTransformationMethod(method); - mTextView.setTransformationMethodInternal(method, /* updateText */ true); - Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd); + mInsertModeController.updateTransformationMethod(method); } /** diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index 43683ffad432..c6a9033210e3 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -87,5 +87,6 @@ <permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" /> <permission name="android.permission.READ_SEARCH_INDEXABLES" /> <permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/> + <permission name="android.permission.QUERY_CLONED_APPS"/> </privapp-permissions> </permissions> diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 71598938f42f..603272e3df1d 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -151,6 +151,7 @@ android_library { ], static_libs: [ "androidx.appcompat_appcompat", + "androidx.core_core-animation", "androidx.arch.core_core-runtime", "androidx-constraintlayout_constraintlayout", "androidx.dynamicanimation_dynamicanimation", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java index 798250de89d0..26edd7d2268b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java @@ -117,6 +117,20 @@ public class FlingAnimationUtils { * @param endValue the end value of the animator * @param velocity the current velocity of the motion */ + public void apply(androidx.core.animation.Animator animator, + float currValue, float endValue, float velocity) { + apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); + } + + /** + * Applies the interpolator and length to the animator, such that the fling animation is + * consistent with the finger motion. + * + * @param animator the animator to apply + * @param currValue the current value + * @param endValue the end value of the animator + * @param velocity the current velocity of the motion + */ public void apply(ViewPropertyAnimator animator, float currValue, float endValue, float velocity) { apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue)); @@ -152,6 +166,24 @@ public class FlingAnimationUtils { * @param maxDistance the maximum distance for this interaction; the maximum animation length * gets multiplied by the ratio between the actual distance and this value */ + public void apply(androidx.core.animation.Animator animator, + float currValue, float endValue, float velocity, float maxDistance) { + AnimatorProperties properties = getProperties(currValue, endValue, velocity, maxDistance); + animator.setDuration(properties.mDuration); + animator.setInterpolator(properties.getInterpolator()); + } + + /** + * Applies the interpolator and length to the animator, such that the fling animation is + * consistent with the finger motion. + * + * @param animator the animator to apply + * @param currValue the current value + * @param endValue the end value of the animator + * @param velocity the current velocity of the motion + * @param maxDistance the maximum distance for this interaction; the maximum animation length + * gets multiplied by the ratio between the actual distance and this value + */ public void apply(ViewPropertyAnimator animator, float currValue, float endValue, float velocity, float maxDistance) { AnimatorProperties properties = getProperties(currValue, endValue, velocity, @@ -367,6 +399,11 @@ public class FlingAnimationUtils { private static class AnimatorProperties { Interpolator mInterpolator; long mDuration; + + /** Get an AndroidX interpolator wrapper of the current mInterpolator */ + public androidx.core.animation.Interpolator getInterpolator() { + return mInterpolator::getInterpolation; + } } /** Builder for {@link #FlingAnimationUtils}. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index f8d7b6bc3aad..9bc28a4626c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -730,7 +730,7 @@ class DesktopTasksController( * * @param taskInfo the task being dragged. * @param position position of surface when drag ends. - * @param y the Y position of the motion event. + * @param y the Y position of the top edge of the task * @param windowDecor the window decoration for the task being dragged */ fun onDragPositioningEnd( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 2d7e6a602f2f..ea9976da3229 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -429,10 +429,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDragPointerId = e.getPointerId(0); } final int dragPointerIdx = e.findPointerIndex(mDragPointerId); - mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo, - decoration.mTaskSurface, e.getRawY(dragPointerIdx))); - mDragPositioningCallback.onDragPositioningMove( + final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningMove( e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); + mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo, + decoration.mTaskSurface, newTaskBounds.top)); mIsDragging = true; mShouldClick = false; return true; @@ -458,10 +458,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { final Point position = new Point( (int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)), (int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx))); - mDragPositioningCallback.onDragPositioningEnd( + final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd( e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo, - position, e.getRawY(), mWindowDecorByTaskId.get(mTaskId))); + position, newTaskBounds.top, mWindowDecorByTaskId.get(mTaskId))); mIsDragging = false; return true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java index 941617de3aec..1669cf4a222c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java @@ -17,6 +17,7 @@ package com.android.wm.shell.windowdecor; import android.annotation.IntDef; +import android.graphics.Rect; /** * Callback called when receiving drag-resize or drag-move related input events. @@ -46,13 +47,15 @@ public interface DragPositioningCallback { * Called when the pointer moves during a drag-resize or drag-move. * @param x x coordinate in window decoration coordinate system of the new pointer location * @param y y coordinate in window decoration coordinate system of the new pointer location + * @return the updated task bounds */ - void onDragPositioningMove(float x, float y); + Rect onDragPositioningMove(float x, float y); /** * Called when a drag-resize or drag-move stops. * @param x x coordinate in window decoration coordinate system where the drag resize stops * @param y y coordinate in window decoration coordinate system where the drag resize stops + * @return the final bounds for the dragged task */ - void onDragPositioningEnd(float x, float y); + Rect onDragPositioningEnd(float x, float y); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java index e1b6db595975..e0ee25242550 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java @@ -85,7 +85,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { } @Override - public void onDragPositioningMove(float x, float y) { + public Rect onDragPositioningMove(float x, float y) { final WindowContainerTransaction wct = new WindowContainerTransaction(); PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint); if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType, @@ -106,10 +106,11 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y); t.apply(); } + return new Rect(mRepositionTaskBounds); } @Override - public void onDragPositioningEnd(float x, float y) { + public Rect onDragPositioningEnd(float x, float y) { // If task has been resized or task was dragged into area outside of // mDisallowedAreaForEndBounds, apply WCT to finish it. if (isResizing() && mHasDragResized) { @@ -136,6 +137,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback { mRepositionStartPoint.set(0, 0); mCtrlType = CTRL_TYPE_UNDEFINED; mHasDragResized = false; + return new Rect(mRepositionTaskBounds); } private boolean isResizing() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java index ae3b5eb6a5b5..fb05c696af82 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java @@ -105,7 +105,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, } @Override - public void onDragPositioningMove(float x, float y) { + public Rect onDragPositioningMove(float x, float y) { PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint); if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType, mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta, @@ -117,10 +117,11 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y); t.apply(); } + return new Rect(mRepositionTaskBounds); } @Override - public void onDragPositioningEnd(float x, float y) { + public Rect onDragPositioningEnd(float x, float y) { PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint); if (isResizing()) { @@ -151,6 +152,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback, mCtrlType = CTRL_TYPE_UNDEFINED; mTaskBoundsAtDragStart.setEmpty(); mRepositionStartPoint.set(0, 0); + return new Rect(mRepositionTaskBounds); } private boolean isResizing() { diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 2bac32785d41..dca9e2148237 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -200,6 +200,7 @@ android_library { "lottie", "LowLightDreamLib", "motion_tool_lib", + "IntentResolver-core", ], manifest: "AndroidManifest.xml", @@ -383,6 +384,7 @@ android_library { "motion_tool_lib", "androidx.core_core-animation-testing-nodeps", "androidx.compose.ui_ui", + "IntentResolver-core", ], } diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt new file mode 100644 index 000000000000..c94fad7246fa --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.surfaceeffects.shaders + +import android.graphics.RuntimeShader + +/** Simply renders a solid color. */ +class SolidColorShader(color: Int) : RuntimeShader(SHADER) { + // language=AGSL + private companion object { + private const val SHADER = + """ + layout(color) uniform vec4 in_color; + vec4 main(vec2 p) { + return in_color; + } + """ + } + + init { + setColorUniform("in_color", color) + } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt new file mode 100644 index 000000000000..df07856e325e --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.surfaceeffects.shaders + +import android.graphics.Color +import android.graphics.RuntimeShader +import android.graphics.Shader +import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary + +/** + * Renders sparkles based on the luma matte. + * + * For example, you can pass in simplex noise as the luma matte and have a cloud looking sparkles. + * + * You may want to utilize this shader by: (Preferred) 1. Create a RuntimeShaderEffect and set the + * [RenderEffect] to the target [View]. + * 2. Create a custom [View], set the shader to the [Paint] and use [Canvas.drawPaint] in [onDraw]. + */ +class SparkleShader : RuntimeShader(SPARKLE_SHADER) { + // language=AGSL + companion object { + private const val UNIFORMS = + """ + // Used it for RenderEffect. For example: + // myView.setRenderEffect( + // RenderEffect.createRuntimeShaderEffect(SparkleShader(), "in_src") + // ) + uniform shader in_src; + uniform half in_time; + uniform half in_pixelate; + uniform shader in_lumaMatte; + layout(color) uniform vec4 in_color; + """ + private const val MAIN_SHADER = + """vec4 main(vec2 p) { + half3 src = in_src.eval(p).rgb; + half luma = getLuminosity(in_lumaMatte.eval(p).rgb); + half sparkle = sparkles(p - mod(p, in_pixelate), in_time); + half3 mask = maskLuminosity(in_color.rgb * sparkle, luma); + + return vec4(src * mask * in_color.a, in_color.a); + } + """ + private const val SPARKLE_SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER + + /** Highly recommended to use this value unless specified by design spec. */ + const val DEFAULT_SPARKLE_PIXELATE_AMOUNT = 0.8f + } + + init { + // Initializes the src and luma matte to be white. + setInputShader("in_src", SolidColorShader(Color.WHITE)) + setLumaMatteColor(Color.WHITE) + } + + /** + * Sets the time of the sparkle animation. + * + * This is used for animating sparkles. Note that this only makes the sparkles sparkle in place. + * In order to move the sparkles in x, y directions, move the luma matte input instead. + */ + fun setTime(time: Float) { + setFloatUniform("in_time", time) + } + + /** + * Sets pixelated amount of the sparkle. + * + * This value *must* be based on [resources.displayMetrics.density]. Otherwise, this will result + * in having different sparkle sizes on different screens. + * + * Expected to be used as follows: + * <pre> + * {@code + * val pixelDensity = context.resources.displayMetrics.density + * // Sparkles will be 0.8 of the pixel size. + * val sparkleShader = SparkleShader().apply { setPixelateAmount(pixelDensity * 0.8f) } + * } + * </pre> + */ + fun setPixelateAmount(pixelateAmount: Float) { + setFloatUniform("in_pixelate", pixelateAmount) + } + + /** + * Sets the luma matte for the sparkles. The luminosity determines the sparkle's visibility. + * Useful for setting a complex mask (e.g. simplex noise, texture, etc.) + */ + fun setLumaMatte(lumaMatte: Shader) { + setInputShader("in_lumaMatte", lumaMatte) + } + + /** Sets the luma matte for the sparkles. Useful for setting a solid color. */ + fun setLumaMatteColor(color: Int) { + setInputShader("in_lumaMatte", SolidColorShader(color)) + } + + /** Sets the color of the sparkles. Expect to have the alpha value encoded. */ + fun setColor(color: Int) { + setColorUniform("in_color", color) + } +} diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt index 5413f9097c5b..24064b1261b7 100644 --- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt @@ -17,12 +17,10 @@ package com.android.systemui.scene.ui.composable import com.android.systemui.scene.shared.model.Scene -import com.android.systemui.scene.shared.model.SceneContainerNames import dagger.Module import dagger.multibindings.Multibinds -import javax.inject.Named @Module interface SceneModule { - @Multibinds @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) fun scenes(): Set<Scene> + @Multibinds fun scenes(): Set<Scene> } diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt index d3643747ad91..3e9b3975eef4 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt @@ -16,35 +16,29 @@ package com.android.systemui.scene.ui.composable +import android.app.AlertDialog import android.content.Context import com.android.systemui.bouncer.ui.composable.BouncerScene -import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel +import com.android.systemui.bouncer.ui.composable.BouncerSceneDialogFactory import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.ui.composable.LockscreenScene -import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel import com.android.systemui.qs.ui.composable.QuickSettingsScene -import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel import com.android.systemui.scene.shared.model.Scene -import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.shade.ui.composable.ShadeScene -import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel import com.android.systemui.statusbar.phone.SystemUIDialog import dagger.Module import dagger.Provides -import javax.inject.Named -import kotlinx.coroutines.CoroutineScope @Module object SceneModule { @Provides - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) fun scenes( - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) bouncer: BouncerScene, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) gone: GoneScene, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) lockScreen: LockscreenScene, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) qs: QuickSettingsScene, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) shade: ShadeScene, + bouncer: BouncerScene, + gone: GoneScene, + lockScreen: LockscreenScene, + qs: QuickSettingsScene, + shade: ShadeScene, ): Set<Scene> { return setOf( bouncer, @@ -57,70 +51,11 @@ object SceneModule { @Provides @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun bouncerScene( - @Application context: Context, - viewModelFactory: BouncerViewModel.Factory, - ): BouncerScene { - return BouncerScene( - viewModel = - viewModelFactory.create( - containerName = SceneContainerNames.SYSTEM_UI_DEFAULT, - ), - dialogFactory = { SystemUIDialog(context) }, - ) - } - - @Provides - @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun goneScene(): GoneScene { - return GoneScene() - } - - @Provides - @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun lockscreenScene( - @Application applicationScope: CoroutineScope, - viewModelFactory: LockscreenSceneViewModel.Factory, - ): LockscreenScene { - return LockscreenScene( - applicationScope = applicationScope, - viewModel = - viewModelFactory.create( - containerName = SceneContainerNames.SYSTEM_UI_DEFAULT, - ), - ) - } - - @Provides - @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun quickSettingsScene( - viewModelFactory: QuickSettingsSceneViewModel.Factory, - ): QuickSettingsScene { - return QuickSettingsScene( - viewModel = - viewModelFactory.create( - containerName = SceneContainerNames.SYSTEM_UI_DEFAULT, - ), - ) - } - - @Provides - @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun shadeScene( - @Application applicationScope: CoroutineScope, - viewModelFactory: ShadeSceneViewModel.Factory, - ): ShadeScene { - return ShadeScene( - applicationScope = applicationScope, - viewModel = - viewModelFactory.create( - containerName = SceneContainerNames.SYSTEM_UI_DEFAULT, - ), - ) + fun bouncerSceneDialogFactory(@Application context: Context): BouncerSceneDialogFactory { + return object : BouncerSceneDialogFactory { + override fun invoke(): AlertDialog { + return SystemUIDialog(context) + } + } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index d83596eeb853..6d9497dac8ea 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -52,24 +52,27 @@ import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction import com.android.systemui.scene.ui.composable.ComposableScene +import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow /** The bouncer scene displays authentication challenges like PIN, password, or pattern. */ -class BouncerScene( +@SysUISingleton +class BouncerScene +@Inject +constructor( private val viewModel: BouncerViewModel, - private val dialogFactory: () -> AlertDialog, + private val dialogFactory: BouncerSceneDialogFactory, ) : ComposableScene { override val key = SceneKey.Bouncer - override fun destinationScenes( - containerName: String, - ): StateFlow<Map<UserAction, SceneModel>> = + override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow<Map<UserAction, SceneModel>>( mapOf( UserAction.Back to SceneModel(SceneKey.Lockscreen), @@ -79,7 +82,6 @@ class BouncerScene( @Composable override fun Content( - containerName: String, modifier: Modifier, ) = BouncerScene(viewModel, dialogFactory, modifier) } @@ -87,7 +89,7 @@ class BouncerScene( @Composable private fun BouncerScene( viewModel: BouncerViewModel, - dialogFactory: () -> AlertDialog, + dialogFactory: BouncerSceneDialogFactory, modifier: Modifier = Modifier, ) { val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState() @@ -175,3 +177,7 @@ private fun BouncerScene( } } } + +interface BouncerSceneDialogFactory { + operator fun invoke(): AlertDialog +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt index 10652678739c..ab7bc26d59e1 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel import com.android.systemui.scene.shared.model.Direction @@ -38,6 +39,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction import com.android.systemui.scene.ui.composable.ComposableScene +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -45,15 +47,16 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** The lock screen scene shows when the device is locked. */ -class LockscreenScene( +@SysUISingleton +class LockscreenScene +@Inject +constructor( @Application private val applicationScope: CoroutineScope, private val viewModel: LockscreenSceneViewModel, ) : ComposableScene { override val key = SceneKey.Lockscreen - override fun destinationScenes( - containerName: String, - ): StateFlow<Map<UserAction, SceneModel>> = + override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = viewModel.upDestinationSceneKey .map { pageKey -> destinationScenes(up = pageKey) } .stateIn( @@ -64,7 +67,6 @@ class LockscreenScene( @Composable override fun Content( - containerName: String, modifier: Modifier, ) { LockscreenScene( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 30b80ca7fc1e..130395a38512 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -27,25 +27,28 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction import com.android.systemui.scene.ui.composable.ComposableScene +import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow /** The Quick Settings (AKA "QS") scene shows the quick setting tiles. */ -class QuickSettingsScene( +@SysUISingleton +class QuickSettingsScene +@Inject +constructor( private val viewModel: QuickSettingsSceneViewModel, ) : ComposableScene { override val key = SceneKey.QuickSettings - override fun destinationScenes( - containerName: String, - ): StateFlow<Map<UserAction, SceneModel>> = + override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow<Map<UserAction, SceneModel>>( mapOf( UserAction.Swipe(Direction.UP) to SceneModel(SceneKey.Shade), @@ -55,7 +58,6 @@ class QuickSettingsScene( @Composable override fun Content( - containerName: String, modifier: Modifier, ) { QuickSettingsScene( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt index 6f3363e940e5..a21366695f66 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt @@ -22,5 +22,5 @@ import com.android.systemui.scene.shared.model.Scene /** Compose-capable extension of [Scene]. */ interface ComposableScene : Scene { - @Composable fun Content(containerName: String, modifier: Modifier) + @Composable fun Content(modifier: Modifier) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt index 0a4da1d6ba1e..007055221691 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt @@ -23,10 +23,12 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction +import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -35,12 +37,11 @@ import kotlinx.coroutines.flow.asStateFlow * "Gone" is not a real scene but rather the absence of scenes when we want to skip showing any * content from the scene framework. */ -class GoneScene : ComposableScene { +@SysUISingleton +class GoneScene @Inject constructor() : ComposableScene { override val key = SceneKey.Gone - override fun destinationScenes( - containerName: String, - ): StateFlow<Map<UserAction, SceneModel>> = + override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow<Map<UserAction, SceneModel>>( mapOf( UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade), @@ -50,7 +51,6 @@ class GoneScene : ComposableScene { @Composable override fun Content( - containerName: String, modifier: Modifier, ) { /* diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt index 32986649388d..49e2bf97b3f0 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt @@ -75,7 +75,6 @@ fun SceneContainer( if (key == currentSceneKey) { Scene( scene = composableScene, - containerName = viewModel.containerName, onSceneChanged = viewModel::setCurrentScene, modifier = Modifier.fillMaxSize(), ) @@ -88,12 +87,10 @@ fun SceneContainer( @Composable private fun Scene( scene: ComposableScene, - containerName: String, onSceneChanged: (SceneModel) -> Unit, modifier: Modifier = Modifier, ) { - val destinationScenes: Map<UserAction, SceneModel> by - scene.destinationScenes(containerName).collectAsState() + val destinationScenes: Map<UserAction, SceneModel> by scene.destinationScenes().collectAsState() val swipeLeftDestinationScene = destinationScenes[UserAction.Swipe(Direction.LEFT)] val swipeUpDestinationScene = destinationScenes[UserAction.Swipe(Direction.UP)] val swipeRightDestinationScene = destinationScenes[UserAction.Swipe(Direction.RIGHT)] @@ -107,7 +104,6 @@ private fun Scene( modifier = Modifier.align(Alignment.Center), ) { scene.Content( - containerName = containerName, modifier = Modifier, ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 27358f53aaf2..b73e0b26f208 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.qs.footer.ui.compose.QuickSettings @@ -35,6 +36,7 @@ import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.scene.shared.model.UserAction import com.android.systemui.scene.ui.composable.ComposableScene import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -42,15 +44,16 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** The shade scene shows scrolling list of notifications and some of the quick setting tiles. */ -class ShadeScene( +@SysUISingleton +class ShadeScene +@Inject +constructor( @Application private val applicationScope: CoroutineScope, private val viewModel: ShadeSceneViewModel, ) : ComposableScene { override val key = SceneKey.Shade - override fun destinationScenes( - containerName: String, - ): StateFlow<Map<UserAction, SceneModel>> = + override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = viewModel.upDestinationSceneKey .map { sceneKey -> destinationScenes(up = sceneKey) } .stateIn( @@ -61,7 +64,6 @@ class ShadeScene( @Composable override fun Content( - containerName: String, modifier: Modifier, ) = ShadeScene(viewModel, modifier) diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml index c7d2d81ded36..29e14c57a047 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml @@ -16,202 +16,10 @@ ** limitations under the License. */ --> - -<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/res-auto" - android:id="@+id/keyguard_pin_view" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center_horizontal|bottom" - android:clipChildren="false" - android:clipToPadding="false" - android:orientation="vertical" - androidprv:layout_maxWidth="@dimen/keyguard_security_width"> -<include layout="@layout/keyguard_bouncer_message_area"/> - -<com.android.systemui.bouncer.ui.BouncerMessageView - android:id="@+id/bouncer_message_view" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" /> - -<androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/pin_container" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_marginBottom="8dp" - android:clipChildren="false" - android:clipToPadding="false" - android:layout_weight="1" - android:layoutDirection="ltr" - android:orientation="vertical"> - - <!-- Set this to be just above key1. It would be better to introduce a barrier above - key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier - drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any - case, the Flow should ensure that key1/2/3 all have the same top, so this should be - fine. --> - <com.android.keyguard.AlphaOptimizedRelativeLayout - android:id="@+id/row0" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom" - androidprv:layout_constraintTop_toTopOf="parent" - androidprv:layout_constraintEnd_toEndOf="parent" - androidprv:layout_constraintStart_toStartOf="parent" - androidprv:layout_constraintBottom_toTopOf="@id/key1" - androidprv:layout_constraintVertical_bias="0.5"> - - <com.android.keyguard.PasswordTextView - android:id="@+id/pinEntry" - style="@style/Widget.TextView.Password" - android:layout_width="@dimen/keyguard_security_width" - android:layout_height="@dimen/keyguard_password_height" - android:layout_centerHorizontal="true" - android:layout_marginRight="72dp" - android:contentDescription="@string/keyguard_accessibility_pin_area" - androidprv:scaledTextSize="@integer/scaled_password_text_size" /> - </com.android.keyguard.AlphaOptimizedRelativeLayout> - - <!-- Guideline used to place the top row of keys relative to the screen height. This will be - updated in KeyguardPINView to reduce the height of the PIN pad. --> - <androidx.constraintlayout.widget.Guideline - android:id="@+id/pin_pad_top_guideline" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - androidprv:layout_constraintGuide_percent="0" - android:orientation="horizontal" /> - - <com.android.keyguard.KeyguardPinFlowView - android:id="@+id/flow1" - android:layout_width="0dp" - android:layout_height="0dp" - android:orientation="horizontal" - android:clipChildren="false" - android:clipToPadding="false" - - androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter" - - androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end" - - androidprv:flow_horizontalStyle="packed" - androidprv:flow_maxElementsWrap="3" - - androidprv:flow_verticalBias="1.0" - androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom" - androidprv:flow_verticalStyle="packed" - - androidprv:flow_wrapMode="aligned" - androidprv:layout_constraintBottom_toBottomOf="parent" - androidprv:layout_constraintEnd_toEndOf="parent" - androidprv:layout_constraintStart_toStartOf="parent" - androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key1" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key2" - androidprv:digit="1" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key2" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key3" - androidprv:digit="2" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key3" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key4" - androidprv:digit="3" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key4" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key5" - androidprv:digit="4" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key5" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key6" - androidprv:digit="5" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key6" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key7" - androidprv:digit="6" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key7" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key8" - androidprv:digit="7" - androidprv:textView="@+id/pinEntry" /> - - - <com.android.keyguard.NumPadKey - android:id="@+id/key8" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key9" - androidprv:digit="8" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key9" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/delete_button" - androidprv:digit="9" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadButton - android:id="@+id/delete_button" - style="@style/NumPadKey.Delete" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key0" - android:contentDescription="@string/keyboardview_keycode_delete" /> - - <com.android.keyguard.NumPadKey - android:id="@+id/key0" - android:layout_width="0dp" - android:layout_height="0dp" - android:accessibilityTraversalBefore="@id/key_enter" - androidprv:digit="0" - androidprv:textView="@+id/pinEntry" /> - - <com.android.keyguard.NumPadButton - android:id="@+id/key_enter" - style="@style/NumPadKey.Enter" - android:layout_width="0dp" - android:layout_height="0dp" - android:contentDescription="@string/keyboardview_keycode_enter" /> -</androidx.constraintlayout.widget.ConstraintLayout> + android:layout_height="match_parent"> - <include layout="@layout/keyguard_eca" - android:id="@+id/keyguard_selector_fade_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:layout_gravity="bottom|center_horizontal" - android:layout_marginTop="@dimen/keyguard_eca_top_margin" - android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin" - android:gravity="center_horizontal"/> + <include layout="@layout/keyguard_pin_view_portrait" /> -</com.android.keyguard.KeyguardPINView> +</FrameLayout> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml new file mode 100644 index 000000000000..f3cd9e49b49c --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml @@ -0,0 +1,218 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2023, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License") +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/res-auto" + android:id="@+id/keyguard_pin_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal|bottom" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="vertical" + androidprv:layout_maxWidth="@dimen/keyguard_security_width"> + + <include layout="@layout/keyguard_bouncer_message_area"/> + + <com.android.systemui.bouncer.ui.BouncerMessageView + android:id="@+id/bouncer_message_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/pin_container" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginBottom="8dp" + android:clipChildren="false" + android:clipToPadding="false" + android:layout_weight="1" + android:layoutDirection="ltr" + android:orientation="vertical"> + + <!-- Set this to be just above key1. It would be better to introduce a barrier above + key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier + drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any + case, the Flow should ensure that key1/2/3 all have the same top, so this should be + fine. --> + <com.android.keyguard.AlphaOptimizedRelativeLayout + android:id="@+id/row0" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom" + androidprv:layout_constraintTop_toTopOf="parent" + androidprv:layout_constraintEnd_toEndOf="parent" + androidprv:layout_constraintStart_toStartOf="parent" + androidprv:layout_constraintBottom_toTopOf="@id/key1" + androidprv:layout_constraintVertical_bias="0.5"> + + <com.android.keyguard.PasswordTextView + android:id="@+id/pinEntry" + style="@style/Widget.TextView.Password" + android:layout_width="@dimen/keyguard_security_width" + android:layout_height="@dimen/keyguard_password_height" + android:layout_centerHorizontal="true" + android:layout_marginRight="72dp" + android:contentDescription="@string/keyguard_accessibility_pin_area" + androidprv:scaledTextSize="@integer/scaled_password_text_size" /> + </com.android.keyguard.AlphaOptimizedRelativeLayout> + + <!-- Guideline used to place the top row of keys relative to the screen height. This will be + updated in KeyguardPINView to reduce the height of the PIN pad. --> + <androidx.constraintlayout.widget.Guideline + android:id="@+id/pin_pad_top_guideline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + androidprv:layout_constraintGuide_percent="0" + android:orientation="horizontal" /> + + <com.android.keyguard.KeyguardPinFlowView + android:id="@+id/flow1" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + android:clipChildren="false" + android:clipToPadding="false" + + androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter" + + androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end" + + androidprv:flow_horizontalStyle="packed" + androidprv:flow_maxElementsWrap="3" + + androidprv:flow_verticalBias="1.0" + androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom" + androidprv:flow_verticalStyle="packed" + + androidprv:flow_wrapMode="aligned" + androidprv:layout_constraintBottom_toBottomOf="parent" + androidprv:layout_constraintEnd_toEndOf="parent" + androidprv:layout_constraintStart_toStartOf="parent" + androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key1" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key2" + androidprv:digit="1" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key2" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key3" + androidprv:digit="2" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key3" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key4" + androidprv:digit="3" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key4" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key5" + androidprv:digit="4" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key5" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key6" + androidprv:digit="5" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key6" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key7" + androidprv:digit="6" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key7" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key8" + androidprv:digit="7" + androidprv:textView="@+id/pinEntry" /> + + + <com.android.keyguard.NumPadKey + android:id="@+id/key8" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key9" + androidprv:digit="8" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key9" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/delete_button" + androidprv:digit="9" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadButton + android:id="@+id/delete_button" + style="@style/NumPadKey.Delete" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key0" + android:contentDescription="@string/keyboardview_keycode_delete" /> + + <com.android.keyguard.NumPadKey + android:id="@+id/key0" + android:layout_width="0dp" + android:layout_height="0dp" + android:accessibilityTraversalBefore="@id/key_enter" + androidprv:digit="0" + androidprv:textView="@+id/pinEntry" /> + + <com.android.keyguard.NumPadButton + android:id="@+id/key_enter" + style="@style/NumPadKey.Enter" + android:layout_width="0dp" + android:layout_height="0dp" + android:contentDescription="@string/keyboardview_keycode_enter" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <include layout="@layout/keyguard_eca" + android:id="@+id/keyguard_selector_fade_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginTop="@dimen/keyguard_eca_top_margin" + android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin" + android:gravity="center_horizontal"/> + +</com.android.keyguard.KeyguardPINView> diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml index e4749381243a..5404cfad25c5 100644 --- a/packages/SystemUI/res/layout/media_projection_app_selector.xml +++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<com.android.internal.widget.ResolverDrawerLayout +<com.android.intentresolver.widget.ResolverDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:layout_width="match_parent" @@ -84,7 +84,7 @@ android:id="@*android:id/tabcontent" android:layout_width="match_parent" android:layout_height="wrap_content"> - <com.android.internal.app.ResolverViewPager + <com.android.intentresolver.ResolverViewPager android:id="@*android:id/profile_pager" android:layout_width="match_parent" android:layout_height="wrap_content"/> @@ -92,4 +92,4 @@ </LinearLayout> </TabHost> -</com.android.internal.widget.ResolverDrawerLayout> +</com.android.intentresolver.widget.ResolverDrawerLayout> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index bc24249b23c9..3b09910fbe88 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -81,7 +81,6 @@ import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.scene.domain.interactor.SceneInteractor; -import com.android.systemui.scene.shared.model.SceneContainerNames; import com.android.systemui.scene.shared.model.SceneKey; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -476,7 +475,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) { // When the scene framework transitions from bouncer to gone, we dismiss the keyguard. mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow( - mSceneInteractor.get().sceneTransitions(SceneContainerNames.SYSTEM_UI_DEFAULT), + mSceneInteractor.get().getTransitions(), sceneTransitionModel -> { if (sceneTransitionModel != null && sceneTransitionModel.getFrom() == SceneKey.Bouncer.INSTANCE diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index fbacd6818648..bc5b1ba9a294 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -117,15 +117,19 @@ public class KeyguardSecurityViewFlipperController KeyguardSecurityCallback keyguardSecurityCallback, @Nullable OnViewInflatedCallback onViewInflatedListener) { int layoutId = getLayoutIdFor(securityMode); - if (layoutId != 0) { - if (DEBUG) Log.v(TAG, "inflating on bg thread id = " + layoutId); + int viewID = getKeyguardInputViewId(securityMode); + if (layoutId != 0 && viewID != 0) { + if (DEBUG) { + Log.v(TAG, "inflating on bg thread id = " + + layoutId + " . viewID = " + viewID); + } mAsyncLayoutInflater.inflate(layoutId, mView, (view, resId, parent) -> { mView.addView(view); KeyguardInputViewController<KeyguardInputView> childController = mKeyguardSecurityViewControllerFactory.create( - (KeyguardInputView) view, securityMode, - keyguardSecurityCallback); + (KeyguardInputView) view.findViewById(viewID), + securityMode, keyguardSecurityCallback); childController.init(); mChildren.add(childController); if (onViewInflatedListener != null) { @@ -147,6 +151,19 @@ public class KeyguardSecurityViewFlipperController } } + private int getKeyguardInputViewId(SecurityMode securityMode) { + //Keyguard Input View is not the root view of the layout, use these IDs for lookup. + switch (securityMode) { + case Pattern: return R.id.keyguard_pattern_view; + case PIN: return R.id.keyguard_pin_view; + case Password: return R.id.keyguard_password_view; + case SimPin: return R.id.keyguard_sim_pin_view; + case SimPuk: return R.id.keyguard_sim_puk_view; + default: + return 0; + } + } + /** Makes the supplied child visible if it is contained win this view, */ public void show(KeyguardInputViewController<KeyguardInputView> childController) { int index = childController.getIndexIn(mView); diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index f00615bc0fe6..7c377d2841e3 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -19,9 +19,6 @@ package com.android.systemui; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_EXPAND; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.content.Context; import android.util.FloatProperty; import android.util.Log; @@ -34,6 +31,11 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; +import androidx.annotation.NonNull; +import androidx.core.animation.Animator; +import androidx.core.animation.AnimatorListenerAdapter; +import androidx.core.animation.ObjectAnimator; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -616,7 +618,7 @@ public class ExpandHelper implements Gefingerpoken { public boolean mCancelled; @Override - public void onAnimationEnd(Animator animation) { + public void onAnimationEnd(@NonNull Animator animation) { if (!mCancelled) { mCallback.setUserExpandedChild(scaledView, expand); if (!mExpanding) { @@ -633,7 +635,7 @@ public class ExpandHelper implements Gefingerpoken { } @Override - public void onAnimationCancel(Animator animation) { + public void onAnimationCancel(@NonNull Animator animation) { mCancelled = true; } }); diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt index 8e14237c0586..d8cf398b696b 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.authentication.domain.interactor.AuthenticationInter import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel import com.android.systemui.bouncer.data.repository.BouncerRepository +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -31,9 +32,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.util.kotlin.pairwise -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -44,8 +43,9 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Encapsulates business logic and application state accessing use-cases. */ +@SysUISingleton class BouncerInteractor -@AssistedInject +@Inject constructor( @Application private val applicationScope: CoroutineScope, @Application private val applicationContext: Context, @@ -53,7 +53,6 @@ constructor( private val authenticationInteractor: AuthenticationInteractor, private val sceneInteractor: SceneInteractor, featureFlags: FeatureFlags, - @Assisted private val containerName: String, ) { /** The user-facing message to show in the bouncer. */ @@ -118,23 +117,19 @@ constructor( /** * Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown. * - * @param containerName The name of the scene container to show the bouncer in. * @param message An optional message to show to the user in the bouncer. */ fun showOrUnlockDevice( - containerName: String, message: String? = null, ) { applicationScope.launch { if (authenticationInteractor.isAuthenticationRequired()) { repository.setMessage(message ?: promptMessage(getAuthenticationMethod())) sceneInteractor.setCurrentScene( - containerName = containerName, scene = SceneModel(SceneKey.Bouncer), ) } else { sceneInteractor.setCurrentScene( - containerName = containerName, scene = SceneModel(SceneKey.Gone), ) } @@ -180,7 +175,6 @@ constructor( if (isAuthenticated) { sceneInteractor.setCurrentScene( - containerName = containerName, scene = SceneModel(SceneKey.Gone), ) } else { @@ -228,11 +222,4 @@ constructor( else -> "" } } - - @AssistedFactory - interface Factory { - fun create( - containerName: String, - ): BouncerInteractor - } } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt index a4ef5cec6525..68e1a29bc609 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt @@ -22,13 +22,12 @@ import android.content.Context import com.android.systemui.R import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.bouncer.domain.interactor.BouncerInteractor +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.util.kotlin.pairwise -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import javax.inject.Inject import kotlin.math.ceil import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -45,17 +44,15 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Holds UI state and handles user input on bouncer UIs. */ +@SysUISingleton class BouncerViewModel -@AssistedInject +@Inject constructor( @Application private val applicationContext: Context, @Application private val applicationScope: CoroutineScope, - interactorFactory: BouncerInteractor.Factory, + private val interactor: BouncerInteractor, featureFlags: FeatureFlags, - @Assisted containerName: String, ) { - private val interactor: BouncerInteractor = interactorFactory.create(containerName) - private val isInputEnabled: StateFlow<Boolean> = interactor.isThrottled .map { !it } @@ -222,11 +219,4 @@ constructor( */ val isUpdateAnimated: Boolean, ) - - @AssistedFactory - interface Factory { - fun create( - containerName: String, - ): BouncerViewModel - } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 553405f2c944..5577cbcb0dd7 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -17,6 +17,7 @@ package com.android.systemui.dreams; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_WINDOW_TITLE; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_TOUCH_INSET_MANAGER; import android.content.ComponentName; import android.content.Context; @@ -161,7 +162,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ DreamOverlayStateController stateController, KeyguardUpdateMonitor keyguardUpdateMonitor, UiEventLogger uiEventLogger, - TouchInsetManager touchInsetManager, + @Named(DREAM_TOUCH_INSET_MANAGER) TouchInsetManager touchInsetManager, @Nullable @Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT) ComponentName lowLightDreamComponent, DreamOverlayCallbackController dreamOverlayCallbackController, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java index c61b47758ab7..4bafe325cda0 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java @@ -31,11 +31,13 @@ import com.android.systemui.dreams.DreamOverlayNotificationCountProvider; import com.android.systemui.dreams.DreamOverlayService; import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule; +import com.android.systemui.touch.TouchInsetManager; import dagger.Module; import dagger.Provides; import java.util.Optional; +import java.util.concurrent.Executor; import javax.inject.Named; @@ -55,7 +57,7 @@ public interface DreamModule { String DREAM_ONLY_ENABLED_FOR_DOCK_USER = "dream_only_enabled_for_dock_user"; String DREAM_OVERLAY_SERVICE_COMPONENT = "dream_overlay_service_component"; String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled"; - + String DREAM_TOUCH_INSET_MANAGER = "dream_touch_inset_manager"; String DREAM_SUPPORTED = "dream_supported"; String DREAM_OVERLAY_WINDOW_TITLE = "dream_overlay_window_title"; @@ -69,6 +71,15 @@ public interface DreamModule { } /** + * Provides a touch inset manager for dreams. + */ + @Provides + @Named(DREAM_TOUCH_INSET_MANAGER) + static TouchInsetManager providesTouchInsetManager(@Main Executor executor) { + return new TouchInsetManager(executor); + } + + /** * Provides whether dream overlay is enabled. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index b04d9705f857..dc38ec040830 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -62,11 +62,12 @@ object Flags { val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply") /** - * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to - * enable it on release builds. + * This flag controls whether we register a listener for StatsD notification memory reports. + * For statsd to actually call the listener however, a server-side toggle needs to be + * enabled as well. */ val NOTIFICATION_MEMORY_LOGGING_ENABLED = - unreleasedFlag(119, "notification_memory_logging_enabled") + releasedFlag(119, "notification_memory_logging_enabled") // TODO(b/260335638): Tracking Bug @JvmField @@ -239,7 +240,7 @@ object Flags { /** Whether to delay showing bouncer UI when face auth or active unlock are enrolled. */ // TODO(b/279794160): Tracking bug. - @JvmField val DELAY_BOUNCER = unreleasedFlag(235, "delay_bouncer", teamfood = true) + @JvmField val DELAY_BOUNCER = releasedFlag(235, "delay_bouncer") /** Keyguard Migration */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index 6fd3e21b25a4..30f8f3edfa8f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -110,6 +110,18 @@ interface DeviceEntryFaceAuthRepository { fun lockoutFaceAuth() /** + * Cancel current face authentication and prevent it from running until [resumeFaceAuth] is + * invoked. + */ + fun pauseFaceAuth() + + /** + * Allow face auth paused using [pauseFaceAuth] to run again. The next invocation to + * [authenticate] will run as long as other gating conditions don't stop it from running. + */ + fun resumeFaceAuth() + + /** * Trigger face authentication. * * [uiEvent] provided should be logged whenever face authentication runs. Invocation should be @@ -186,6 +198,15 @@ constructor( override val isAuthRunning: StateFlow<Boolean> get() = _isAuthRunning + private val faceAuthPaused = MutableStateFlow(false) + override fun pauseFaceAuth() { + faceAuthPaused.value = true + } + + override fun resumeFaceAuth() { + faceAuthPaused.value = false + } + private val keyguardSessionId: InstanceId? get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD) @@ -329,11 +350,7 @@ constructor( "isFaceAuthenticationEnabled", tableLogBuffer ), - logAndObserve( - userRepository.userSwitchingInProgress.isFalse(), - "userSwitchingNotInProgress", - tableLogBuffer - ), + logAndObserve(faceAuthPaused.isFalse(), "faceAuthIsNotPaused", tableLogBuffer), logAndObserve( keyguardRepository.isKeyguardGoingAway.isFalse(), "keyguardNotGoingAway", @@ -454,7 +471,6 @@ constructor( } private fun handleFaceCancellationError() { - cancelNotReceivedHandlerJob?.cancel() applicationScope.launch { faceAuthRequestedWhileCancellation?.let { faceAuthLogger.launchingQueuedFaceAuthRequest(it) @@ -483,6 +499,7 @@ constructor( } private fun onFaceAuthRequestCompleted() { + cancelNotReceivedHandlerJob?.cancel() cancellationInProgress = false _isAuthRunning.value = false authCancellationSignal = null diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt index 5ef9a9e0482c..e4e6a6dae6b0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/NoopDeviceEntryFaceAuthRepository.kt @@ -56,6 +56,9 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA get() = emptyFlow() override fun lockoutFaceAuth() = Unit + override fun pauseFaceAuth() = Unit + + override fun resumeFaceAuth() = Unit /** * Trigger face authentication. diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt index 1c200b086990..278c68d3c55b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt @@ -19,10 +19,9 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.bouncer.domain.interactor.BouncerInteractor +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -30,17 +29,14 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** Hosts business and application state accessing logic for the lockscreen scene. */ +@SysUISingleton class LockscreenSceneInteractor -@AssistedInject +@Inject constructor( @Application applicationScope: CoroutineScope, private val authenticationInteractor: AuthenticationInteractor, - bouncerInteractorFactory: BouncerInteractor.Factory, - @Assisted private val containerName: String, + private val bouncerInteractor: BouncerInteractor, ) { - private val bouncerInteractor: BouncerInteractor = - bouncerInteractorFactory.create(containerName) - /** Whether the device is currently locked. */ val isDeviceLocked: StateFlow<Boolean> = authenticationInteractor.isUnlocked @@ -67,13 +63,6 @@ constructor( /** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */ fun dismissLockscreen() { - bouncerInteractor.showOrUnlockDevice(containerName = containerName) - } - - @AssistedFactory - interface Factory { - fun create( - containerName: String, - ): LockscreenSceneInteractor + bouncerInteractor.showOrUnlockDevice() } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt index 8f4776fa2ed3..2a3f8520a63c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -35,6 +35,7 @@ import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.log.FaceAuthenticationLogger +import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -49,6 +50,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * Encapsulates business logic related face authentication being triggered for device entry from @@ -69,6 +71,7 @@ constructor( private val faceAuthenticationLogger: FaceAuthenticationLogger, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, + private val userRepository: UserRepository, ) : CoreStartable, KeyguardFaceAuthInteractor { private val listeners: MutableList<FaceAuthenticationListener> = mutableListOf() @@ -128,6 +131,23 @@ constructor( } } .launchIn(applicationScope) + + // User switching should stop face auth and then when it is complete we should trigger face + // auth so that the switched user can unlock the device with face auth. + userRepository.userSwitchingInProgress + .pairwise(false) + .onEach { (wasSwitching, isSwitching) -> + if (!wasSwitching && isSwitching) { + repository.pauseFaceAuth() + } else if (wasSwitching && !isSwitching) { + repository.resumeFaceAuth() + runFaceAuth( + FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING, + fallbackToDetect = true + ) + } + } + .launchIn(applicationScope) } override fun onSwipeUpOnBouncer() { @@ -199,8 +219,10 @@ constructor( } else { faceAuthenticationStatusOverride.value = null applicationScope.launch { - faceAuthenticationLogger.authRequested(uiEvent) - repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect) + withContext(mainDispatcher) { + faceAuthenticationLogger.authRequested(uiEvent) + repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect) + } } } } else { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt index f212a553aeb3..abd178ca6c1d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt @@ -19,12 +19,11 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.R import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor import com.android.systemui.scene.shared.model.SceneKey -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -32,15 +31,13 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** Models UI state and handles user input for the lockscreen scene. */ +@SysUISingleton class LockscreenSceneViewModel -@AssistedInject +@Inject constructor( @Application applicationScope: CoroutineScope, - interactorFactory: LockscreenSceneInteractor.Factory, - @Assisted containerName: String, + private val interactor: LockscreenSceneInteractor, ) { - private val interactor: LockscreenSceneInteractor = interactorFactory.create(containerName) - /** The icon for the "lock" button on the lockscreen. */ val lockButtonIcon: StateFlow<Icon> = interactor.isDeviceLocked @@ -98,11 +95,4 @@ constructor( ) ) } - - @AssistedFactory - interface Factory { - fun create( - containerName: String, - ): LockscreenSceneViewModel - } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt index 42164c795b06..fdb3ddd7294f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt @@ -30,16 +30,11 @@ import android.os.IBinder import android.os.ResultReceiver import android.os.UserHandle import android.view.ViewGroup -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry +import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider +import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider +import com.android.intentresolver.ChooserActivity +import com.android.intentresolver.chooser.TargetInfo import com.android.internal.annotations.VisibleForTesting -import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider -import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider -import com.android.internal.app.ChooserActivity -import com.android.internal.app.ResolverListController -import com.android.internal.app.chooser.NotSelectableTargetInfo -import com.android.internal.app.chooser.TargetInfo import com.android.systemui.R import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController @@ -56,12 +51,8 @@ class MediaProjectionAppSelectorActivity( private val activityLauncher: AsyncActivityLauncher, /** This is used to override the dependency in a screenshot test */ @VisibleForTesting - private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)? -) : - ChooserActivity(), - MediaProjectionAppSelectorView, - MediaProjectionAppSelectorResultHandler, - LifecycleOwner { + private val listControllerFactory: ((userHandle: UserHandle) -> ChooserListController)? +) : ChooserActivity(), MediaProjectionAppSelectorView, MediaProjectionAppSelectorResultHandler { @Inject constructor( @@ -69,8 +60,6 @@ class MediaProjectionAppSelectorActivity( activityLauncher: AsyncActivityLauncher ) : this(componentFactory, activityLauncher, listControllerFactory = null) - private val lifecycleRegistry = LifecycleRegistry(this) - override val lifecycle = lifecycleRegistry private lateinit var configurationController: ConfigurationController private lateinit var controller: MediaProjectionAppSelectorController private lateinit var recentsViewController: MediaProjectionRecentsViewController @@ -84,7 +73,6 @@ class MediaProjectionAppSelectorActivity( override fun getLayoutResource() = R.layout.media_projection_app_selector public override fun onCreate(bundle: Bundle?) { - lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) component = componentFactory.create(view = this, resultHandler = this) component.lifecycleObservers.forEach { lifecycle.addObserver(it) } @@ -107,26 +95,6 @@ class MediaProjectionAppSelectorActivity( controller.init() } - override fun onStart() { - super.onStart() - lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) - } - - override fun onResume() { - super.onResume() - lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) - } - - override fun onPause() { - lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) - super.onPause() - } - - override fun onStop() { - lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) - super.onStop() - } - override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) configurationController.onConfigurationChanged(newConfig) @@ -137,13 +105,13 @@ class MediaProjectionAppSelectorActivity( override fun createBlockerEmptyStateProvider(): EmptyStateProvider = component.emptyStateProvider - override fun createListController(userHandle: UserHandle): ResolverListController = + override fun createListController(userHandle: UserHandle): ChooserListController = listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle) override fun startSelected(which: Int, always: Boolean, filtered: Boolean) { val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return - if (targetInfo is NotSelectableTargetInfo) return + if (targetInfo.isNotSelectableTargetInfo) return val intent = createIntent(targetInfo) @@ -183,7 +151,6 @@ class MediaProjectionAppSelectorActivity( } override fun onDestroy() { - lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) component.lifecycleObservers.forEach { lifecycle.removeObserver(it) } // onDestroy is also called when an app is selected, in that case we only want to send // RECORD_CONTENT_TASK but not RECORD_CANCEL diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt index 829b0ddbe3a8..fd14e2b9a96b 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt @@ -17,10 +17,10 @@ package com.android.systemui.mediaprojection.appselector import android.content.Context import android.os.UserHandle +import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState +import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider +import com.android.intentresolver.ResolverListAdapter import com.android.internal.R as AndroidR -import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState -import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider -import com.android.internal.app.ResolverListAdapter import com.android.systemui.R import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt index 36dec1d112b9..5e6a44bf8130 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt @@ -16,30 +16,19 @@ package com.android.systemui.qs.ui.viewmodel +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import javax.inject.Inject /** Models UI state and handles user input for the quick settings scene. */ +@SysUISingleton class QuickSettingsSceneViewModel -@AssistedInject +@Inject constructor( - lockscreenSceneInteractorFactory: LockscreenSceneInteractor.Factory, - @Assisted containerName: String, + private val lockscreenSceneInteractor: LockscreenSceneInteractor, ) { - private val lockscreenSceneInteractor: LockscreenSceneInteractor = - lockscreenSceneInteractorFactory.create(containerName) - /** Notifies that some content in quick settings was clicked. */ fun onContentClicked() { lockscreenSceneInteractor.dismissLockscreen() } - - @AssistedFactory - interface Factory { - fun create( - containerName: String, - ): QuickSettingsSceneViewModel - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index bf40a2d0ad51..03bd11bb433e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -97,7 +97,6 @@ import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.buttons.KeyButtonView; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; import com.android.systemui.scene.domain.interactor.SceneInteractor; -import com.android.systemui.scene.shared.model.SceneContainerNames; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeViewController; @@ -221,8 +220,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis // If scene framework is enabled, set the scene container window to // visible and let the touch "slip" into that window. if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) { - mSceneInteractor.get().setVisible( - SceneContainerNames.SYSTEM_UI_DEFAULT, true); + mSceneInteractor.get().setVisible(true); } else { centralSurfaces.onInputFocusTransfer( mInputFocusTransferStarted, false /* cancel */, diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt index 26c52199f493..398e64b1981b 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt @@ -19,7 +19,6 @@ package com.android.systemui.scene import com.android.systemui.scene.domain.startable.SceneContainerStartableModule import com.android.systemui.scene.shared.model.SceneContainerConfigModule import com.android.systemui.scene.ui.composable.SceneModule -import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModelModule import dagger.Module @Module( @@ -27,7 +26,6 @@ import dagger.Module [ SceneContainerConfigModule::class, SceneContainerStartableModule::class, - SceneContainerViewModelModule::class, SceneModule::class, ], ) diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt index 0a86d35b7b62..1fca4886a31f 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt @@ -29,26 +29,20 @@ import kotlinx.coroutines.flow.asStateFlow class SceneContainerRepository @Inject constructor( - private val containerConfigByName: Map<String, SceneContainerConfig>, + private val config: SceneContainerConfig, ) { - private val containerVisibilityByName: Map<String, MutableStateFlow<Boolean>> = - containerConfigByName - .map { (containerName, _) -> containerName to MutableStateFlow(true) } - .toMap() - private val currentSceneByContainerName: Map<String, MutableStateFlow<SceneModel>> = - containerConfigByName - .map { (containerName, config) -> - containerName to MutableStateFlow(SceneModel(config.initialSceneKey)) - } - .toMap() - private val sceneTransitionProgressByContainerName: Map<String, MutableStateFlow<Float>> = - containerConfigByName - .map { (containerName, _) -> containerName to MutableStateFlow(1f) } - .toMap() - private val sceneTransitionByContainerName: - Map<String, MutableStateFlow<SceneTransitionModel?>> = - containerConfigByName.keys.associateWith { MutableStateFlow(null) } + private val _isVisible = MutableStateFlow(true) + val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow() + + private val _currentScene = MutableStateFlow(SceneModel(config.initialSceneKey)) + val currentScene: StateFlow<SceneModel> = _currentScene.asStateFlow() + + private val _transitionProgress = MutableStateFlow(1f) + val transitionProgress: StateFlow<Float> = _transitionProgress.asStateFlow() + + private val _transitions = MutableStateFlow<SceneTransitionModel?>(null) + val transitions: StateFlow<SceneTransitionModel?> = _transitions.asStateFlow() /** * Returns the keys to all scenes in the container with the given name. @@ -56,100 +50,50 @@ constructor( * The scenes will be sorted in z-order such that the last one is the one that should be * rendered on top of all previous ones. */ - fun allSceneKeys(containerName: String): List<SceneKey> { - return containerConfigByName[containerName]?.sceneKeys - ?: error(noSuchContainerErrorMessage(containerName)) + fun allSceneKeys(): List<SceneKey> { + return config.sceneKeys } /** Sets the current scene in the container with the given name. */ - fun setCurrentScene(containerName: String, scene: SceneModel) { - check(allSceneKeys(containerName).contains(scene.key)) { + fun setCurrentScene(scene: SceneModel) { + check(allSceneKeys().contains(scene.key)) { """ - Cannot set current scene key to "${scene.key}". The container "$containerName" does - not contain a scene with that key. + Cannot set current scene key to "${scene.key}". The configuration does not contain a + scene with that key. """ .trimIndent() } - currentSceneByContainerName.setValue(containerName, scene) + _currentScene.value = scene } /** Sets the scene transition in the container with the given name. */ - fun setSceneTransition(containerName: String, from: SceneKey, to: SceneKey) { - check(allSceneKeys(containerName).contains(from)) { + fun setSceneTransition(from: SceneKey, to: SceneKey) { + check(allSceneKeys().contains(from)) { """ - Cannot set current scene key to "$from". The container "$containerName" does - not contain a scene with that key. + Cannot set current scene key to "$from". The configuration does not contain a scene + with that key. """ .trimIndent() } - check(allSceneKeys(containerName).contains(to)) { + check(allSceneKeys().contains(to)) { """ - Cannot set current scene key to "$to". The container "$containerName" does - not contain a scene with that key. + Cannot set current scene key to "$to". The configuration does not contain a scene + with that key. """ .trimIndent() } - sceneTransitionByContainerName.setValue( - containerName, - SceneTransitionModel(from = from, to = to) - ) - } - - /** The current scene in the container with the given name. */ - fun currentScene(containerName: String): StateFlow<SceneModel> { - return currentSceneByContainerName.mutableOrError(containerName).asStateFlow() - } - - /** - * Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene - * transition occurs. The flow begins with a `null` value at first, because the initial scene is - * not something that we transition to from another scene. - */ - fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> { - return sceneTransitionByContainerName.mutableOrError(containerName).asStateFlow() + _transitions.value = SceneTransitionModel(from = from, to = to) } /** Sets whether the container with the given name is visible. */ - fun setVisible(containerName: String, isVisible: Boolean) { - containerVisibilityByName.setValue(containerName, isVisible) - } - - /** Whether the container with the given name should be visible. */ - fun isVisible(containerName: String): StateFlow<Boolean> { - return containerVisibilityByName.mutableOrError(containerName).asStateFlow() + fun setVisible(isVisible: Boolean) { + _isVisible.value = isVisible } /** Sets scene transition progress to the current scene in the container with the given name. */ - fun setSceneTransitionProgress(containerName: String, progress: Float) { - sceneTransitionProgressByContainerName.setValue(containerName, progress) - } - - /** Progress of the transition into the current scene in the container with the given name. */ - fun sceneTransitionProgress(containerName: String): StateFlow<Float> { - return sceneTransitionProgressByContainerName.mutableOrError(containerName).asStateFlow() - } - - private fun <T> Map<String, MutableStateFlow<T>>.mutableOrError( - containerName: String, - ): MutableStateFlow<T> { - return this[containerName] ?: error(noSuchContainerErrorMessage(containerName)) - } - - private fun <T> Map<String, MutableStateFlow<T>>.setValue( - containerName: String, - value: T, - ) { - val mutable = mutableOrError(containerName) - mutable.value = value - } - - private fun noSuchContainerErrorMessage(containerName: String): String { - return """ - No container named "$containerName". Existing containers: - ${containerConfigByName.values.joinToString(", ") { it.name }} - """ - .trimIndent() + fun setSceneTransitionProgress(progress: Float) { + _transitionProgress.value = progress } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt index f03f040c206d..39daad33f75e 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt @@ -30,12 +30,8 @@ import kotlinx.coroutines.flow.asStateFlow /** * Generic business logic and app state accessors for the scene framework. * - * Note that scene container specific business logic does not belong in this class. Instead, it - * should be hoisted to a class that is specific to that scene container, for an example, please see - * [SystemUiDefaultSceneContainerStartable]. - * - * Also note that this class should not depend on state or logic of other modules or features. - * Instead, other feature modules should depend on and call into this class when their parts of the + * Note that this class should not depend on state or logic of other modules or features. Instead, + * other feature modules should depend on and call into this class when their parts of the * application state change. */ @SysUISingleton @@ -51,50 +47,42 @@ constructor( * The scenes will be sorted in z-order such that the last one is the one that should be * rendered on top of all previous ones. */ - fun allSceneKeys(containerName: String): List<SceneKey> { - return repository.allSceneKeys(containerName) + fun allSceneKeys(): List<SceneKey> { + return repository.allSceneKeys() } /** Sets the scene in the container with the given name. */ - fun setCurrentScene(containerName: String, scene: SceneModel) { - val currentSceneKey = repository.currentScene(containerName).value.key - repository.setCurrentScene(containerName, scene) - repository.setSceneTransition(containerName, from = currentSceneKey, to = scene.key) + fun setCurrentScene(scene: SceneModel) { + val currentSceneKey = repository.currentScene.value.key + repository.setCurrentScene(scene) + repository.setSceneTransition(from = currentSceneKey, to = scene.key) } /** The current scene in the container with the given name. */ - fun currentScene(containerName: String): StateFlow<SceneModel> { - return repository.currentScene(containerName) - } + val currentScene: StateFlow<SceneModel> = repository.currentScene /** Sets the visibility of the container with the given name. */ - fun setVisible(containerName: String, isVisible: Boolean) { - return repository.setVisible(containerName, isVisible) + fun setVisible(isVisible: Boolean) { + return repository.setVisible(isVisible) } /** Whether the container with the given name is visible. */ - fun isVisible(containerName: String): StateFlow<Boolean> { - return repository.isVisible(containerName) - } + val isVisible: StateFlow<Boolean> = repository.isVisible /** Sets scene transition progress to the current scene in the container with the given name. */ - fun setSceneTransitionProgress(containerName: String, progress: Float) { - repository.setSceneTransitionProgress(containerName, progress) + fun setSceneTransitionProgress(progress: Float) { + repository.setSceneTransitionProgress(progress) } /** Progress of the transition into the current scene in the container with the given name. */ - fun sceneTransitionProgress(containerName: String): StateFlow<Float> { - return repository.sceneTransitionProgress(containerName) - } + val transitionProgress: StateFlow<Float> = repository.transitionProgress /** * Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene * transition occurs. The flow begins with a `null` value at first, because the initial scene is * not something that we transition to from another scene. */ - fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> { - return repository.sceneTransitions(containerName) - } + val transitions: StateFlow<SceneTransitionModel?> = repository.transitions private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null) diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 92384d68157b..1c87eb25004e 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -28,7 +28,6 @@ import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.model.SysUiState import com.android.systemui.model.updateFlags import com.android.systemui.scene.domain.interactor.SceneInteractor -import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING @@ -44,12 +43,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch /** - * Hooks up business logic that manipulates the state of the [SceneInteractor] for the default - * system UI scene container (the one named [SceneContainerNames.SYSTEM_UI_DEFAULT]) based on state - * from other systems. + * Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI + * scene container based on state from other systems. */ @SysUISingleton -class SystemUiDefaultSceneContainerStartable +class SceneContainerStartable @Inject constructor( @Application private val applicationScope: CoroutineScope, @@ -72,13 +70,10 @@ constructor( /** Updates the visibility of the scene container based on the current scene. */ private fun hydrateVisibility() { applicationScope.launch { - sceneInteractor - .currentScene(CONTAINER_NAME) + sceneInteractor.currentScene .map { it.key } .distinctUntilChanged() - .collect { sceneKey -> - sceneInteractor.setVisible(CONTAINER_NAME, sceneKey != SceneKey.Gone) - } + .collect { sceneKey -> sceneInteractor.setVisible(sceneKey != SceneKey.Gone) } } } @@ -87,7 +82,7 @@ constructor( applicationScope.launch { authenticationInteractor.isUnlocked .map { isUnlocked -> - val currentSceneKey = sceneInteractor.currentScene(CONTAINER_NAME).value.key + val currentSceneKey = sceneInteractor.currentScene.value.key val isBypassEnabled = authenticationInteractor.isBypassEnabled() when { isUnlocked -> @@ -135,8 +130,7 @@ constructor( /** Keeps [SysUiState] up-to-date */ private fun hydrateSystemUiState() { applicationScope.launch { - sceneInteractor - .currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT) + sceneInteractor.currentScene .map { it.key } .distinctUntilChanged() .collect { sceneKey -> @@ -155,12 +149,7 @@ constructor( private fun switchToScene(targetSceneKey: SceneKey) { sceneInteractor.setCurrentScene( - containerName = CONTAINER_NAME, scene = SceneModel(targetSceneKey), ) } - - companion object { - private const val CONTAINER_NAME = SceneContainerNames.SYSTEM_UI_DEFAULT - } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt index b3de2d158a53..8da1803053f4 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt @@ -27,6 +27,6 @@ interface SceneContainerStartableModule { @Binds @IntoMap - @ClassKey(SystemUiDefaultSceneContainerStartable::class) - fun bind(impl: SystemUiDefaultSceneContainerStartable): CoreStartable + @ClassKey(SceneContainerStartable::class) + fun bind(impl: SceneContainerStartable): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt index 354de8ac7aa5..31597c1752db 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt @@ -27,8 +27,6 @@ import kotlinx.coroutines.flow.asStateFlow * takes care of rendering the current scene and allowing scenes to be switched from one to another * based on either user action (for example, swiping down while on the lock screen scene may switch * to the shade scene). - * - * The framework also supports multiple containers, each one with its own configuration. */ interface Scene { @@ -59,7 +57,7 @@ interface Scene { * The API is designed such that it's possible to emit ever-changing values for each * [UserAction] to enable, disable, or change the destination scene of a given user action. */ - fun destinationScenes(containerName: String): StateFlow<Map<UserAction, SceneModel>> = + fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> = MutableStateFlow(emptyMap<UserAction, SceneModel>()).asStateFlow() } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt index 0327edbb06b4..8204edc33fe4 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfig.kt @@ -16,10 +16,8 @@ package com.android.systemui.scene.shared.model -/** Models the configuration of a single scene container. */ +/** Models the configuration of the scene container. */ data class SceneContainerConfig( - /** Container name. Must be unique across all containers in System UI. */ - val name: String, /** * The keys to all scenes in the container, sorted by z-order such that the last one renders on diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt index 7562a5a848d8..f74005b03816 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt @@ -16,44 +16,27 @@ package com.android.systemui.scene.shared.model -import com.android.systemui.dagger.SysUISingleton import dagger.Module import dagger.Provides -import javax.inject.Named @Module object SceneContainerConfigModule { @Provides - fun containerConfigs(): Map<String, SceneContainerConfig> { - return mapOf( - SceneContainerNames.SYSTEM_UI_DEFAULT to - SceneContainerConfig( - name = SceneContainerNames.SYSTEM_UI_DEFAULT, - // Note that this list is in z-order. The first one is the bottom-most and the - // last - // one is top-most. - sceneKeys = - listOf( - SceneKey.Gone, - SceneKey.Lockscreen, - SceneKey.Bouncer, - SceneKey.Shade, - SceneKey.QuickSettings, - ), - initialSceneKey = SceneKey.Lockscreen, + fun containerConfig(): SceneContainerConfig { + return SceneContainerConfig( + // Note that this list is in z-order. The first one is the bottom-most and the + // last + // one is top-most. + sceneKeys = + listOf( + SceneKey.Gone, + SceneKey.Lockscreen, + SceneKey.Bouncer, + SceneKey.Shade, + SceneKey.QuickSettings, ), + initialSceneKey = SceneKey.Lockscreen, ) } - - @Provides - @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun provideDefaultSceneContainerConfig( - configs: Map<String, SceneContainerConfig>, - ): SceneContainerConfig { - return checkNotNull(configs[SceneContainerNames.SYSTEM_UI_DEFAULT]) { - "No SceneContainerConfig named \"${SceneContainerNames.SYSTEM_UI_DEFAULT}\"." - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt index 005f48d9f250..f44748a99080 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt @@ -17,16 +17,20 @@ package com.android.systemui.scene.ui.viewmodel import android.view.MotionEvent +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.RemoteUserInput import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel +import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow -/** Models UI state for a single scene container. */ -class SceneContainerViewModel( +/** Models UI state for the scene container. */ +@SysUISingleton +class SceneContainerViewModel +@Inject +constructor( private val interactor: SceneInteractor, - val containerName: String, ) { /** A flow of motion events originating from outside of the scene framework. */ val remoteUserInput: StateFlow<RemoteUserInput?> = interactor.remoteUserInput @@ -37,22 +41,22 @@ class SceneContainerViewModel( * The scenes will be sorted in z-order such that the last one is the one that should be * rendered on top of all previous ones. */ - val allSceneKeys: List<SceneKey> = interactor.allSceneKeys(containerName) + val allSceneKeys: List<SceneKey> = interactor.allSceneKeys() /** The current scene. */ - val currentScene: StateFlow<SceneModel> = interactor.currentScene(containerName) + val currentScene: StateFlow<SceneModel> = interactor.currentScene /** Whether the container is visible. */ - val isVisible: StateFlow<Boolean> = interactor.isVisible(containerName) + val isVisible: StateFlow<Boolean> = interactor.isVisible /** Requests a transition to the scene with the given key. */ fun setCurrentScene(scene: SceneModel) { - interactor.setCurrentScene(containerName, scene) + interactor.setCurrentScene(scene) } /** Notifies of the progress of a scene transition. */ fun setSceneTransitionProgress(progress: Float) { - interactor.setSceneTransitionProgress(containerName, progress) + interactor.setSceneTransitionProgress(progress) } /** Handles a [MotionEvent] representing remote user input. */ diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt deleted file mode 100644 index 100f42764322..000000000000 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelModule.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.scene.ui.viewmodel - -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.scene.domain.interactor.SceneInteractor -import com.android.systemui.scene.shared.model.SceneContainerNames -import dagger.Module -import dagger.Provides -import javax.inject.Named - -@Module -object SceneContainerViewModelModule { - - @Provides - @SysUISingleton - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) - fun defaultSceneContainerViewModel( - interactor: SceneInteractor, - ): SceneContainerViewModel { - return SceneContainerViewModel( - interactor = interactor, - containerName = SceneContainerNames.SYSTEM_UI_DEFAULT, - ) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt index e02c4275f095..29551188c5c7 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt @@ -36,7 +36,6 @@ import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.scene.shared.model.Scene import com.android.systemui.scene.shared.model.SceneContainerConfig -import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.ui.view.SceneWindowRootView import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel @@ -73,11 +72,8 @@ abstract class ShadeViewProviderModule { fun providesWindowRootView( layoutInflater: LayoutInflater, featureFlags: FeatureFlags, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) viewModelProvider: Provider<SceneContainerViewModel>, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) containerConfigProvider: Provider<SceneContainerConfig>, - @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>, layoutInsetController: NotificationInsetsController, ): WindowRootView { diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt index 8a96a4764e66..0b3ed5601c2e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt @@ -16,12 +16,11 @@ package com.android.systemui.shade.ui.viewmodel +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor import com.android.systemui.scene.shared.model.SceneKey -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -29,32 +28,29 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** Models UI state and handles user input for the shade scene. */ +@SysUISingleton class ShadeSceneViewModel -@AssistedInject +@Inject constructor( @Application private val applicationScope: CoroutineScope, - lockscreenSceneInteractorFactory: LockscreenSceneInteractor.Factory, - @Assisted private val containerName: String, + private val lockscreenSceneInteractor: LockscreenSceneInteractor, ) { - private val lockScreenInteractor: LockscreenSceneInteractor = - lockscreenSceneInteractorFactory.create(containerName) - /** The key of the scene we should switch to when swiping up. */ val upDestinationSceneKey: StateFlow<SceneKey> = - lockScreenInteractor.isDeviceLocked + lockscreenSceneInteractor.isDeviceLocked .map { isLocked -> upDestinationSceneKey(isLocked = isLocked) } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = upDestinationSceneKey( - isLocked = lockScreenInteractor.isDeviceLocked.value, + isLocked = lockscreenSceneInteractor.isDeviceLocked.value, ), ) /** Notifies that some content in the shade was clicked. */ fun onContentClicked() { - lockScreenInteractor.dismissLockscreen() + lockscreenSceneInteractor.dismissLockscreen() } private fun upDestinationSceneKey( @@ -62,11 +58,4 @@ constructor( ): SceneKey { return if (isLocked) SceneKey.Lockscreen else SceneKey.Gone } - - @AssistedFactory - interface Factory { - fun create( - containerName: String, - ): ShadeSceneViewModel - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt new file mode 100644 index 000000000000..92e9765936d7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationMemoryModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.dagger + +import com.android.systemui.CoreStartable +import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +interface NotificationMemoryModule { + + /** Binds memory monitor into startable map. */ + @Binds + @IntoMap + @ClassKey(NotificationMemoryMonitor::class) + fun bindsNotificationMemoryMonitorStartable(monitor: NotificationMemoryMonitor): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index f7bd177594a2..106d11f6bcc1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -39,7 +39,6 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.notification.logging.NotificationLogger -import com.android.systemui.statusbar.notification.logging.NotificationMemoryMonitor import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.wm.shell.bubbles.Bubbles @@ -72,7 +71,6 @@ class NotificationsControllerImpl @Inject constructor( private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager, private val bubblesOptional: Optional<Bubbles>, private val fgsNotifListener: ForegroundServiceNotificationListener, - private val memoryMonitor: Lazy<NotificationMemoryMonitor>, private val featureFlags: FeatureFlags ) : NotificationsController { @@ -108,7 +106,6 @@ class NotificationsControllerImpl @Inject constructor( notificationLogger.setUpWithContainer(listContainer) peopleSpaceWidgetManager.attach(notificationListener) fgsNotifListener.init() - memoryMonitor.get().init() } // TODO: Convert all functions below this line into listeners instead of public methods diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt index f38c1e557b25..0fdf681aac26 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.logging import android.util.Log +import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -32,13 +33,13 @@ constructor( private val featureFlags: FeatureFlags, private val notificationMemoryDumper: NotificationMemoryDumper, private val notificationMemoryLogger: Lazy<NotificationMemoryLogger>, -) { +) : CoreStartable { companion object { private const val TAG = "NotificationMemory" } - fun init() { + override fun start() { Log.d(TAG, "NotificationMemoryMonitor initialized.") notificationMemoryDumper.init() if (featureFlags.isEnabled(Flags.NOTIFICATION_MEMORY_LOGGING_ENABLED)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 36a8e9833d39..5e7e4be60104 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -426,16 +426,21 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView updateAppearAnimationAlpha(); updateAppearRect(); mAppearAnimator.addListener(new AnimatorListenerAdapter() { - private boolean mWasCancelled; + private boolean mRunWithoutInterruptions; @Override public void onAnimationEnd(Animator animation) { if (onFinishedRunnable != null) { onFinishedRunnable.run(); } - if (!mWasCancelled) { + if (mRunWithoutInterruptions) { enableAppearDrawing(false); - onAppearAnimationFinished(isAppearing); + } + + // We need to reset the View state, even if the animation was cancelled + onAppearAnimationFinished(isAppearing); + + if (mRunWithoutInterruptions) { InteractionJankMonitor.getInstance().end(getCujType(isAppearing)); } else { InteractionJankMonitor.getInstance().cancel(getCujType(isAppearing)); @@ -444,7 +449,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView @Override public void onAnimationStart(Animator animation) { - mWasCancelled = false; + mRunWithoutInterruptions = true; Configuration.Builder builder = Configuration.Builder .withView(getCujType(isAppearing), ActivatableNotificationView.this); InteractionJankMonitor.getInstance().begin(builder); @@ -452,7 +457,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView @Override public void onAnimationCancel(Animator animation) { - mWasCancelled = true; + mRunWithoutInterruptions = false; } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index 8c3050d48d53..122728716eee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -30,7 +30,6 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.RemoteUserInput -import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.shade.ShadeController import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController @@ -183,7 +182,7 @@ class PhoneStatusBarViewController private constructor( sceneInteractor.get() .onRemoteUserInput(RemoteUserInput.translateMotionEvent(event)) // TODO(b/291965119): remove once view is expanded to cover the status bar - sceneInteractor.get().setVisible(SceneContainerNames.SYSTEM_UI_DEFAULT, true) + sceneInteractor.get().setVisible(true) return false } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java index 68a6b3d62bae..fa9b9d2c571a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -37,7 +37,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.scene.domain.interactor.SceneInteractor; -import com.android.systemui.scene.shared.model.SceneContainerNames; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -126,7 +125,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable { if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) { javaAdapter.get().alwaysCollectFlow( - sceneInteractor.get().isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT), + sceneInteractor.get().isVisible(), this::onShadeExpansionFullyChanged); } diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java index 757b4e50c3f8..13c1019591a1 100644 --- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java +++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java @@ -25,16 +25,12 @@ import android.view.ViewGroup; import androidx.concurrent.futures.CallbackToFutureAdapter; -import com.android.systemui.dagger.qualifiers.Main; - import com.google.common.util.concurrent.ListenableFuture; import java.util.HashMap; import java.util.HashSet; import java.util.concurrent.Executor; -import javax.inject.Inject; - /** * {@link TouchInsetManager} handles setting the touchable inset regions for a given View. This * is useful for passing through touch events for all but select areas. @@ -153,8 +149,7 @@ public class TouchInsetManager { * Default constructor. * @param executor An {@link Executor} to marshal all operations on. */ - @Inject - public TouchInsetManager(@Main Executor executor) { + public TouchInsetManager(Executor executor) { mExecutor = executor; } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index 3abae6bcd197..e447c29b351f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -733,29 +733,20 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { // is // not enough to trigger a dismissal of the keyguard. underTest.onViewAttached() - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer, null) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null)) runCurrent() verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt()) // While listening, going from the bouncer scene to the gone scene, does dismiss the // keyguard. - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Gone, null) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null)) runCurrent() verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt()) // While listening, moving back to the bouncer scene does not dismiss the keyguard // again. clearInvocations(viewMediatorCallback) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer, null) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null)) runCurrent() verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt()) @@ -763,18 +754,12 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { // scene // does not dismiss the keyguard while we're not listening. underTest.onViewDetached() - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Gone, null) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null)) runCurrent() verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt()) // While not listening, moving back to the bouncer does not dismiss the keyguard. - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer, null) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null)) runCurrent() verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt()) @@ -782,10 +767,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { // gone // scene now does dismiss the keyguard again. underTest.onViewAttached() - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Gone, null) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null)) runCurrent() verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt()) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index cd187540ba74..64e1458c42d4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -138,6 +138,11 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { @Test public void asynchronouslyInflateView_setNeedsInput() { + when(mKeyguardSecurityViewControllerFactory.create( + any(), any(SecurityMode.class), + any(KeyguardSecurityCallback.class))) + .thenReturn(mKeyguardInputViewController); + ArgumentCaptor<AsyncLayoutInflater.OnInflateFinishedListener> argumentCaptor = ArgumentCaptor.forClass(AsyncLayoutInflater.OnInflateFinishedListener.class); mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN, diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java index 5867a40c78fa..44a2b682bf37 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java @@ -20,12 +20,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import android.animation.ObjectAnimator; import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import androidx.core.animation.AnimatorTestRule; +import androidx.core.animation.ObjectAnimator; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; @@ -37,6 +38,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,6 +47,9 @@ import org.junit.runner.RunWith; @RunWithLooper public class ExpandHelperTest extends SysuiTestCase { + @Rule + public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); private ExpandableNotificationRow mRow; private ExpandHelper mExpandHelper; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt index 6babf0490ea9..14fc931522a4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt @@ -69,13 +69,12 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun pinAuthMethod() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(underTest.message) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN) @@ -101,14 +100,13 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun pinAuthMethod_tryAutoConfirm_withAutoConfirmPin() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(underTest.message) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setAutoConfirmEnabled(true) utils.authenticationRepository.setUnlocked(false) - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN) underTest.clearMessage() @@ -138,13 +136,12 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(underTest.message) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.clearMessage() @@ -168,14 +165,13 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun passwordAuthMethod() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(underTest.message) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) utils.authenticationRepository.setUnlocked(false) - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD) @@ -201,14 +197,13 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun patternAuthMethod() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(underTest.message) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pattern ) utils.authenticationRepository.setUnlocked(false) - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN) @@ -239,13 +234,12 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun showOrUnlockDevice_notLocked_switchesToGoneScene() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(true) runCurrent() - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone)) } @@ -253,12 +247,11 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe) utils.authenticationRepository.setUnlocked(false) - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone)) } @@ -266,8 +259,7 @@ class BouncerInteractorTest : SysuiTestCase() { @Test fun showOrUnlockDevice_customMessageShown() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(underTest.message) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password @@ -275,7 +267,7 @@ class BouncerInteractorTest : SysuiTestCase() { utils.authenticationRepository.setUnlocked(false) val customMessage = "Hello there!" - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1, customMessage) + underTest.showOrUnlockDevice(customMessage) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) assertThat(message).isEqualTo(customMessage) @@ -287,11 +279,10 @@ class BouncerInteractorTest : SysuiTestCase() { val isThrottled by collectLastValue(underTest.isThrottled) val throttling by collectLastValue(underTest.throttling) val message by collectLastValue(underTest.message) - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) runCurrent() - underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1) + underTest.showOrUnlockDevice() runCurrent() assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer) assertThat(isThrottled).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt index b1533fecbc5e..1f089ca8b98e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt @@ -72,18 +72,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { @Test fun onShown() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val password by collectLastValue(underTest.password) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() @@ -96,18 +92,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { @Test fun onPasswordInputChanged() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val password by collectLastValue(underTest.password) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() runCurrent() @@ -122,16 +114,12 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { @Test fun onAuthenticateKeyPressed_whenCorrect() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onPasswordInputChanged("password") @@ -144,18 +132,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { @Test fun onAuthenticateKeyPressed_whenWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val password by collectLastValue(underTest.password) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onPasswordInputChanged("wrong") @@ -170,18 +154,14 @@ class PasswordBouncerViewModelTest : SysuiTestCase() { @Test fun onAuthenticateKeyPressed_correctAfterWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val password by collectLastValue(underTest.password) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onPasswordInputChanged("wrong") diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt index f69cbb8fd004..af54989002e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt @@ -75,8 +75,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { @Test fun onShown() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val selectedDots by collectLastValue(underTest.selectedDots) val currentDot by collectLastValue(underTest.currentDot) @@ -84,10 +83,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { AuthenticationMethodModel.Pattern ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() @@ -101,8 +97,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { @Test fun onDragStart() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val selectedDots by collectLastValue(underTest.selectedDots) val currentDot by collectLastValue(underTest.currentDot) @@ -110,10 +105,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { AuthenticationMethodModel.Pattern ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() runCurrent() @@ -129,18 +121,14 @@ class PatternBouncerViewModelTest : SysuiTestCase() { @Test fun onDragEnd_whenCorrect() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val selectedDots by collectLastValue(underTest.selectedDots) val currentDot by collectLastValue(underTest.currentDot) utils.authenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pattern ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onDragStart() @@ -180,8 +168,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { @Test fun onDragEnd_whenWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val selectedDots by collectLastValue(underTest.selectedDots) val currentDot by collectLastValue(underTest.currentDot) @@ -189,10 +176,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { AuthenticationMethodModel.Pattern ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onDragStart() @@ -216,8 +200,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { @Test fun onDragEnd_correctAfterWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val selectedDots by collectLastValue(underTest.selectedDots) val currentDot by collectLastValue(underTest.currentDot) @@ -225,10 +208,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() { AuthenticationMethodModel.Pattern ) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onDragStart() diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 8edc6cf8dd54..c12ed033d752 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -75,15 +75,11 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onShown() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() @@ -96,16 +92,12 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onPinButtonClicked() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() runCurrent() @@ -120,16 +112,12 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onBackspaceButtonClicked() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() runCurrent() @@ -146,15 +134,11 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onPinEdit() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() @@ -172,16 +156,12 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onBackspaceButtonLongPressed() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() runCurrent() @@ -200,14 +180,10 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onAuthenticateButtonClicked_whenCorrect() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit -> @@ -222,16 +198,12 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onAuthenticateButtonClicked_whenWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onPinButtonClicked(1) @@ -250,16 +222,12 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onAuthenticateButtonClicked_correctAfterWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() underTest.onPinButtonClicked(1) @@ -286,15 +254,11 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onAutoConfirm_whenCorrect() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) utils.authenticationRepository.setAutoConfirmEnabled(true) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit -> @@ -307,17 +271,13 @@ class PinBouncerViewModelTest : SysuiTestCase() { @Test fun onAutoConfirm_whenWrong() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) val message by collectLastValue(bouncerViewModel.message) val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) utils.authenticationRepository.setAutoConfirmEnabled(true) - sceneInteractor.setCurrentScene( - SceneTestUtils.CONTAINER_1, - SceneModel(SceneKey.Bouncer) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) underTest.onShown() FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit -> diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index 01a6c64a6898..85ee0e4d6ec3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -541,10 +541,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test - fun authenticateDoesNotRunIfUserIsCurrentlySwitching() = - testScope.runTest { - testGatingCheckForFaceAuth { fakeUserRepository.setUserSwitching(true) } - } + fun authenticateDoesNotRunIfFaceAuthIsCurrentlyPaused() = + testScope.runTest { testGatingCheckForFaceAuth { underTest.pauseFaceAuth() } } @Test fun authenticateDoesNotRunIfKeyguardIsNotShowing() = @@ -840,7 +838,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { @Test fun detectDoesNotRunWhenUserSwitchingInProgress() = - testScope.runTest { testGatingCheckForDetect { fakeUserRepository.setUserSwitching(true) } } + testScope.runTest { testGatingCheckForDetect { underTest.pauseFaceAuth() } } @Test fun detectDoesNotRunWhenKeyguardGoingAway() = @@ -1130,7 +1128,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { .addLockoutResetCallback(faceLockoutResetCallback.capture()) biometricSettingsRepository.setFaceEnrolled(true) biometricSettingsRepository.setIsFaceAuthEnabled(true) - fakeUserRepository.setUserSwitching(false) + underTest.resumeFaceAuth() trustRepository.setCurrentUserTrusted(false) keyguardRepository.setKeyguardGoingAway(false) keyguardRepository.setWakefulnessModel( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index 8636dd8df3b0..93f208ee14f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -48,6 +48,7 @@ import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.log.FaceAuthenticationLogger import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -74,6 +75,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private lateinit var faceAuthRepository: FakeDeviceEntryFaceAuthRepository + private lateinit var fakeUserRepository: FakeUserRepository private lateinit var fakeDeviceEntryFingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository @@ -98,6 +100,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { .keyguardTransitionInteractor fakeDeviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() + fakeUserRepository = FakeUserRepository() underTest = SystemUIKeyguardFaceAuthInteractor( mContext, @@ -131,7 +134,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { featureFlags, FaceAuthenticationLogger(logcatLogBuffer("faceAuthBuffer")), keyguardUpdateMonitor, - fakeDeviceEntryFingerprintAuthRepository + fakeDeviceEntryFingerprintAuthRepository, + fakeUserRepository, ) } @@ -212,6 +216,38 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { } @Test + fun faceAuthIsPausedWhenUserSwitchingIsInProgress() = + testScope.runTest { + underTest.start() + + fakeUserRepository.setUserSwitching(false) + runCurrent() + fakeUserRepository.setUserSwitching(true) + runCurrent() + + assertThat(faceAuthRepository.isFaceAuthPaused()).isTrue() + } + + @Test + fun faceAuthIsUnpausedWhenUserSwitchingIsInComplete() = + testScope.runTest { + underTest.start() + + // previously running + fakeUserRepository.setUserSwitching(true) + runCurrent() + fakeUserRepository.setUserSwitching(false) + runCurrent() + + assertThat(faceAuthRepository.isFaceAuthPaused()).isFalse() + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value!!.first) + .isEqualTo(FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING) + assertThat(faceAuthRepository.runningAuthRequest.value!!.second).isEqualTo(true) + } + + @Test fun faceAuthIsRequestedWhenPrimaryBouncerIsVisible() = testScope.runTest { underTest.start() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt index ca6a5b6234b9..d825c2a01464 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt @@ -21,7 +21,6 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1 import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.google.common.truth.Truth.assertThat @@ -91,7 +90,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { @Test fun dismissLockScreen_deviceLockedWithSecureAuthMethod_switchesToBouncer() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setUnlocked(false) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) @@ -104,7 +103,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { @Test fun dismissLockScreen_deviceUnlocked_switchesToGone() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setUnlocked(true) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) @@ -117,7 +116,7 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { @Test fun dismissLockScreen_deviceLockedWithInsecureAuthMethod_switchesToGone() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setUnlocked(false) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) @@ -131,11 +130,11 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() = testScope.runTest { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) - sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen)) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Lockscreen)) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) assertThat(isUnlocked).isFalse() - sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone)) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone)) assertThat(isUnlocked).isFalse() } @@ -145,13 +144,13 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { testScope.runTest { val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked) runCurrent() - sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade)) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade)) runCurrent() utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe) runCurrent() assertThat(isUnlocked).isFalse() - sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone)) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone)) assertThat(isUnlocked).isFalse() } @@ -159,10 +158,10 @@ class LockscreenSceneInteractorTest : SysuiTestCase() { @Test fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe) runCurrent() - sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings)) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.QuickSettings)) runCurrent() assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index ba8e0f277b6b..63ee240fd2c6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -22,9 +22,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.common.shared.model.Icon import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1 import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.google.common.truth.Truth.assertThat @@ -51,20 +49,15 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { private val underTest = LockscreenSceneViewModel( applicationScope = testScope.backgroundScope, - interactorFactory = - object : LockscreenSceneInteractor.Factory { - override fun create(containerName: String): LockscreenSceneInteractor { - return utils.lockScreenSceneInteractor( + interactor = + utils.lockScreenSceneInteractor( + authenticationInteractor = authenticationInteractor, + bouncerInteractor = + utils.bouncerInteractor( authenticationInteractor = authenticationInteractor, - bouncerInteractor = - utils.bouncerInteractor( - authenticationInteractor = authenticationInteractor, - sceneInteractor = sceneInteractor, - ), - ) - } - }, - containerName = CONTAINER_1 + sceneInteractor = sceneInteractor, + ), + ), ) @Test @@ -116,7 +109,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { @Test fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) runCurrent() @@ -129,7 +122,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { @Test fun onContentClicked_deviceUnlocked_switchesToGone() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(true) runCurrent() @@ -142,7 +135,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { @Test fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) runCurrent() @@ -155,7 +148,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { @Test fun onLockButtonClicked_deviceUnlocked_switchesToGone() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(true) runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt index ed7a59ea7032..ee42a7011264 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt @@ -20,9 +20,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1 import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.google.common.truth.Truth.assertThat @@ -48,26 +46,21 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { private val underTest = QuickSettingsSceneViewModel( - lockscreenSceneInteractorFactory = - object : LockscreenSceneInteractor.Factory { - override fun create(containerName: String): LockscreenSceneInteractor { - return utils.lockScreenSceneInteractor( + lockscreenSceneInteractor = + utils.lockScreenSceneInteractor( + authenticationInteractor = authenticationInteractor, + bouncerInteractor = + utils.bouncerInteractor( authenticationInteractor = authenticationInteractor, - bouncerInteractor = - utils.bouncerInteractor( - authenticationInteractor = authenticationInteractor, - sceneInteractor = sceneInteractor, - ), - ) - } - }, - containerName = CONTAINER_1 + sceneInteractor = sceneInteractor, + ), + ), ) @Test fun onContentClicked_deviceUnlocked_switchesToGone() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(true) runCurrent() @@ -80,7 +73,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { @Test fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt index 9ce378dd079f..826a6ccfbaec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt @@ -41,7 +41,7 @@ class SceneContainerRepositoryTest : SysuiTestCase() { @Test fun allSceneKeys() { val underTest = utils.fakeSceneContainerRepository() - assertThat(underTest.allSceneKeys(SceneTestUtils.CONTAINER_1)) + assertThat(underTest.allSceneKeys()) .isEqualTo( listOf( SceneKey.QuickSettings, @@ -53,115 +53,58 @@ class SceneContainerRepositoryTest : SysuiTestCase() { ) } - @Test(expected = IllegalStateException::class) - fun allSceneKeys_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.allSceneKeys("nonExistingContainer") - } - @Test fun currentScene() = runTest { val underTest = utils.fakeSceneContainerRepository() - val currentScene by collectLastValue(underTest.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(underTest.currentScene) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) - underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade)) + underTest.setCurrentScene(SceneModel(SceneKey.Shade)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade)) } @Test(expected = IllegalStateException::class) - fun currentScene_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.currentScene("nonExistingContainer") - } - - @Test(expected = IllegalStateException::class) - fun setCurrentScene_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.setCurrentScene("nonExistingContainer", SceneModel(SceneKey.Shade)) - } - - @Test(expected = IllegalStateException::class) fun setCurrentScene_noSuchSceneInContainer_throws() { val underTest = utils.fakeSceneContainerRepository( - setOf( - utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1), - utils.fakeSceneContainerConfig( - SceneTestUtils.CONTAINER_2, - listOf(SceneKey.QuickSettings, SceneKey.Lockscreen) - ), - ) + utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)), ) - underTest.setCurrentScene(SceneTestUtils.CONTAINER_2, SceneModel(SceneKey.Shade)) + underTest.setCurrentScene(SceneModel(SceneKey.Shade)) } @Test fun isVisible() = runTest { val underTest = utils.fakeSceneContainerRepository() - val isVisible by collectLastValue(underTest.isVisible(SceneTestUtils.CONTAINER_1)) + val isVisible by collectLastValue(underTest.isVisible) assertThat(isVisible).isTrue() - underTest.setVisible(SceneTestUtils.CONTAINER_1, false) + underTest.setVisible(false) assertThat(isVisible).isFalse() - underTest.setVisible(SceneTestUtils.CONTAINER_1, true) + underTest.setVisible(true) assertThat(isVisible).isTrue() } - @Test(expected = IllegalStateException::class) - fun isVisible_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.isVisible("nonExistingContainer") - } - - @Test(expected = IllegalStateException::class) - fun setVisible_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.setVisible("nonExistingContainer", false) - } - @Test - fun sceneTransitionProgress() = runTest { + fun transitionProgress() = runTest { val underTest = utils.fakeSceneContainerRepository() - val sceneTransitionProgress by - collectLastValue(underTest.sceneTransitionProgress(SceneTestUtils.CONTAINER_1)) + val sceneTransitionProgress by collectLastValue(underTest.transitionProgress) assertThat(sceneTransitionProgress).isEqualTo(1f) - underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.1f) + underTest.setSceneTransitionProgress(0.1f) assertThat(sceneTransitionProgress).isEqualTo(0.1f) - underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.9f) + underTest.setSceneTransitionProgress(0.9f) assertThat(sceneTransitionProgress).isEqualTo(0.9f) } - @Test(expected = IllegalStateException::class) - fun sceneTransitionProgress_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.sceneTransitionProgress("nonExistingContainer") - } - @Test fun setSceneTransition() = runTest { - val underTest = - utils.fakeSceneContainerRepository( - setOf( - utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1), - utils.fakeSceneContainerConfig( - SceneTestUtils.CONTAINER_2, - listOf(SceneKey.QuickSettings, SceneKey.Lockscreen) - ), - ) - ) - val sceneTransition by - collectLastValue(underTest.sceneTransitions(SceneTestUtils.CONTAINER_2)) + val underTest = utils.fakeSceneContainerRepository() + val sceneTransition by collectLastValue(underTest.transitions) assertThat(sceneTransition).isNull() - underTest.setSceneTransition( - SceneTestUtils.CONTAINER_2, - SceneKey.Lockscreen, - SceneKey.QuickSettings - ) + underTest.setSceneTransition(SceneKey.Lockscreen, SceneKey.QuickSettings) assertThat(sceneTransition) .isEqualTo( SceneTransitionModel(from = SceneKey.Lockscreen, to = SceneKey.QuickSettings) @@ -169,46 +112,20 @@ class SceneContainerRepositoryTest : SysuiTestCase() { } @Test(expected = IllegalStateException::class) - fun setSceneTransition_noSuchContainer_throws() { - val underTest = utils.fakeSceneContainerRepository() - underTest.setSceneTransition("nonExistingContainer", SceneKey.Lockscreen, SceneKey.Shade) - } - - @Test(expected = IllegalStateException::class) fun setSceneTransition_noFromSceneInContainer_throws() { val underTest = utils.fakeSceneContainerRepository( - setOf( - utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1), - utils.fakeSceneContainerConfig( - SceneTestUtils.CONTAINER_2, - listOf(SceneKey.QuickSettings, SceneKey.Lockscreen) - ), - ) + utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)), ) - underTest.setSceneTransition( - SceneTestUtils.CONTAINER_2, - SceneKey.Shade, - SceneKey.Lockscreen - ) + underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen) } @Test(expected = IllegalStateException::class) fun setSceneTransition_noToSceneInContainer_throws() { val underTest = utils.fakeSceneContainerRepository( - setOf( - utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1), - utils.fakeSceneContainerConfig( - SceneTestUtils.CONTAINER_2, - listOf(SceneKey.QuickSettings, SceneKey.Lockscreen) - ), - ) + utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)), ) - underTest.setSceneTransition( - SceneTestUtils.CONTAINER_2, - SceneKey.Shade, - SceneKey.Lockscreen - ) + underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt index d2bbfa85604b..13a602dcddb0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt @@ -41,48 +41,46 @@ class SceneInteractorTest : SysuiTestCase() { @Test fun allSceneKeys() { - assertThat(underTest.allSceneKeys(SceneTestUtils.CONTAINER_1)) - .isEqualTo(utils.fakeSceneKeys()) + assertThat(underTest.allSceneKeys()).isEqualTo(utils.fakeSceneKeys()) } @Test fun currentScene() = runTest { - val currentScene by collectLastValue(underTest.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(underTest.currentScene) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen)) - underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade)) + underTest.setCurrentScene(SceneModel(SceneKey.Shade)) assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade)) } @Test fun sceneTransitionProgress() = runTest { - val progress by - collectLastValue(underTest.sceneTransitionProgress(SceneTestUtils.CONTAINER_1)) + val progress by collectLastValue(underTest.transitionProgress) assertThat(progress).isEqualTo(1f) - underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.55f) + underTest.setSceneTransitionProgress(0.55f) assertThat(progress).isEqualTo(0.55f) } @Test fun isVisible() = runTest { - val isVisible by collectLastValue(underTest.isVisible(SceneTestUtils.CONTAINER_1)) + val isVisible by collectLastValue(underTest.isVisible) assertThat(isVisible).isTrue() - underTest.setVisible(SceneTestUtils.CONTAINER_1, false) + underTest.setVisible(false) assertThat(isVisible).isFalse() - underTest.setVisible(SceneTestUtils.CONTAINER_1, true) + underTest.setVisible(true) assertThat(isVisible).isTrue() } @Test fun sceneTransitions() = runTest { - val transitions by collectLastValue(underTest.sceneTransitions(SceneTestUtils.CONTAINER_1)) + val transitions by collectLastValue(underTest.transitions) assertThat(transitions).isNull() - val initialSceneKey = underTest.currentScene(SceneTestUtils.CONTAINER_1).value.key - underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade)) + val initialSceneKey = underTest.currentScene.value.key + underTest.setCurrentScene(SceneModel(SceneKey.Shade)) assertThat(transitions) .isEqualTo( SceneTransitionModel( @@ -91,7 +89,7 @@ class SceneInteractorTest : SysuiTestCase() { ) ) - underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.QuickSettings)) + underTest.setCurrentScene(SceneModel(SceneKey.QuickSettings)) assertThat(transitions) .isEqualTo( SceneTransitionModel( diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index 6f6c5a589f44..b6bd31f43d30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -28,7 +28,6 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.model.SysUiState import com.android.systemui.scene.SceneTestUtils -import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel import com.android.systemui.util.mockito.mock @@ -47,7 +46,7 @@ import org.mockito.Mockito.verify @SmallTest @RunWith(JUnit4::class) -class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { +class SceneContainerStartableTest : SysuiTestCase() { private val utils = SceneTestUtils(this) private val testScope = utils.testScope @@ -66,7 +65,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { private val sysUiState: SysUiState = mock() private val underTest = - SystemUiDefaultSceneContainerStartable( + SceneContainerStartable( applicationScope = testScope.backgroundScope, sceneInteractor = sceneInteractor, authenticationInteractor = authenticationInteractor, @@ -84,14 +83,8 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun hydrateVisibility_featureEnabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) - val isVisible by - collectLastValue(sceneInteractor.isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT)) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) + val isVisible by collectLastValue(sceneInteractor.isVisible) prepareState( isFeatureEnabled = true, isDeviceUnlocked = true, @@ -104,24 +97,15 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { assertThat(isVisible).isFalse() - sceneInteractor.setCurrentScene( - SceneContainerNames.SYSTEM_UI_DEFAULT, - SceneModel(SceneKey.Shade) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade)) assertThat(isVisible).isTrue() } @Test fun hydrateVisibility_featureDisabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) - val isVisible by - collectLastValue(sceneInteractor.isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT)) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) + val isVisible by collectLastValue(sceneInteractor.isVisible) prepareState( isFeatureEnabled = false, isDeviceUnlocked = true, @@ -133,28 +117,17 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { underTest.start() assertThat(isVisible).isTrue() - sceneInteractor.setCurrentScene( - SceneContainerNames.SYSTEM_UI_DEFAULT, - SceneModel(SceneKey.Gone) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone)) assertThat(isVisible).isTrue() - sceneInteractor.setCurrentScene( - SceneContainerNames.SYSTEM_UI_DEFAULT, - SceneModel(SceneKey.Shade) - ) + sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade)) assertThat(isVisible).isTrue() } @Test fun switchToLockscreenWhenDeviceLocks_featureEnabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = true, isDeviceUnlocked = true, @@ -171,12 +144,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchToLockscreenWhenDeviceLocks_featureDisabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = false, isDeviceUnlocked = false, @@ -193,12 +161,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchFromBouncerToGoneWhenDeviceUnlocked_featureEnabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = true, isDeviceUnlocked = false, @@ -215,12 +178,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchFromBouncerToGoneWhenDeviceUnlocked_featureDisabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = false, isDeviceUnlocked = false, @@ -237,12 +195,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOn() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = true, isBypassEnabled = true, @@ -259,12 +212,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOff() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = true, isBypassEnabled = false, @@ -281,12 +229,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOff_bypassOn() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = false, isBypassEnabled = true, @@ -303,12 +246,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchToGoneWhenDeviceSleepsUnlocked_featureEnabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = true, isDeviceUnlocked = true, @@ -325,12 +263,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchToGoneWhenDeviceSleepsUnlocked_featureDisabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = false, isDeviceUnlocked = true, @@ -347,12 +280,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchToLockscreenWhenDeviceSleepsLocked_featureEnabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = true, isDeviceUnlocked = false, @@ -369,12 +297,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { @Test fun switchToLockscreenWhenDeviceSleepsLocked_featureDisabled() = testScope.runTest { - val currentSceneKey by - collectLastValue( - sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map { - it.key - } - ) + val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key }) prepareState( isFeatureEnabled = false, isDeviceUnlocked = false, @@ -403,10 +326,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { SceneKey.QuickSettings, ) .forEachIndexed { index, sceneKey -> - sceneInteractor.setCurrentScene( - SceneContainerNames.SYSTEM_UI_DEFAULT, - SceneModel(sceneKey), - ) + sceneInteractor.setCurrentScene(SceneModel(sceneKey)) runCurrent() verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY) @@ -422,9 +342,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() { featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled) authenticationRepository.setUnlocked(isDeviceUnlocked) keyguardRepository.setBypassEnabled(isBypassEnabled) - initialSceneKey?.let { - sceneInteractor.setCurrentScene(SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(it)) - } + initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneModel(it)) } } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt index 63ea918c904a..0ab98ad512ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt @@ -45,7 +45,6 @@ class SceneContainerViewModelTest : SysuiTestCase() { private val underTest = SceneContainerViewModel( interactor = interactor, - containerName = SceneTestUtils.CONTAINER_1, ) @Test @@ -53,10 +52,10 @@ class SceneContainerViewModelTest : SysuiTestCase() { val isVisible by collectLastValue(underTest.isVisible) assertThat(isVisible).isTrue() - interactor.setVisible(SceneTestUtils.CONTAINER_1, false) + interactor.setVisible(false) assertThat(isVisible).isFalse() - interactor.setVisible(SceneTestUtils.CONTAINER_1, true) + interactor.setVisible(true) assertThat(isVisible).isTrue() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt index 6e9fba64263b..8739b28c940e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt @@ -20,7 +20,6 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor import com.android.systemui.scene.SceneTestUtils import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.SceneModel @@ -48,20 +47,15 @@ class ShadeSceneViewModelTest : SysuiTestCase() { private val underTest = ShadeSceneViewModel( applicationScope = testScope.backgroundScope, - lockscreenSceneInteractorFactory = - object : LockscreenSceneInteractor.Factory { - override fun create(containerName: String): LockscreenSceneInteractor { - return utils.lockScreenSceneInteractor( + lockscreenSceneInteractor = + utils.lockScreenSceneInteractor( + authenticationInteractor = authenticationInteractor, + bouncerInteractor = + utils.bouncerInteractor( authenticationInteractor = authenticationInteractor, - bouncerInteractor = - utils.bouncerInteractor( - authenticationInteractor = authenticationInteractor, - sceneInteractor = sceneInteractor, - ), - ) - } - }, - containerName = SceneTestUtils.CONTAINER_1 + sceneInteractor = sceneInteractor, + ), + ), ) @Test @@ -87,8 +81,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { @Test fun onContentClicked_deviceUnlocked_switchesToGone() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(true) runCurrent() @@ -101,8 +94,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { @Test fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = testScope.runTest { - val currentScene by - collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1)) + val currentScene by collectLastValue(sceneInteractor.currentScene) utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.authenticationRepository.setUnlocked(false) runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt index 0b2da8bfa649..0cfca614a256 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt @@ -24,6 +24,7 @@ import android.util.Pair import android.view.Gravity import android.view.View import android.widget.FrameLayout +import androidx.core.animation.AnimatorTestRule import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags @@ -38,6 +39,7 @@ import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -50,6 +52,7 @@ import org.mockito.MockitoAnnotations class SystemEventChipAnimationControllerTest : SysuiTestCase() { private lateinit var controller: SystemEventChipAnimationController + @get:Rule val animatorTestRule = AnimatorTestRule() @Mock private lateinit var sbWindowController: StatusBarWindowController @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 1dc8453a90ec..ac8b42afd4b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -789,6 +789,50 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { assertThat(row.isExpanded()).isTrue(); } + @Test + public void onDisappearAnimationFinished_shouldSetFalse_headsUpAnimatingAway() + throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + + // Initial state: suppose heads up animation in progress + row.setHeadsUpAnimatingAway(true); + assertThat(row.isHeadsUpAnimatingAway()).isTrue(); + + // on disappear animation ends + row.onAppearAnimationFinished(/* wasAppearing = */ false); + assertThat(row.isHeadsUpAnimatingAway()).isFalse(); + } + + @Test + public void onHUNAppear_cancelAppearDrawing_shouldResetAnimationState() throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + + row.performAddAnimation(/* delay */ 0, /* duration */ 1000, /* isHeadsUpAppear */ true); + + waitForIdleSync(); + assertThat(row.isDrawingAppearAnimation()).isTrue(); + + row.cancelAppearDrawing(); + + waitForIdleSync(); + assertThat(row.isDrawingAppearAnimation()).isFalse(); + } + + @Test + public void onHUNDisappear_cancelAppearDrawing_shouldResetAnimationState() throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + + row.performAddAnimation(/* delay */ 0, /* duration */ 1000, /* isHeadsUpAppear */ false); + + waitForIdleSync(); + assertThat(row.isDrawingAppearAnimation()).isTrue(); + + row.cancelAppearDrawing(); + + waitForIdleSync(); + assertThat(row.isDrawingAppearAnimation()).isFalse(); + } + private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable, Drawable rightIconDrawable) { ImageView iconView = mock(ImageView.class); diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerNames.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt index 64f5087d99bf..f1fadf6f1a4a 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerNames.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt @@ -13,9 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.android.systemui.surfaceeffects.shaders -package com.android.systemui.scene.shared.model +import android.graphics.Color +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Test +import org.junit.runner.RunWith -object SceneContainerNames { - const val SYSTEM_UI_DEFAULT = "system_ui" +@SmallTest +@RunWith(AndroidTestingRunner::class) +class SolidColorShaderTest : SysuiTestCase() { + + @Test + fun compilesShader() { + SolidColorShader(Color.RED) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt new file mode 100644 index 000000000000..64ea6a68a518 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.surfaceeffects.shaders + +import android.graphics.Color +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class SparkleShaderTest : SysuiTestCase() { + + private lateinit var sparkleShader: SparkleShader + + @Test + fun compilesSparkleShader() { + sparkleShader = + SparkleShader().apply { + setPixelateAmount( + context.resources.displayMetrics.density * + SparkleShader.DEFAULT_SPARKLE_PIXELATE_AMOUNT + ) + setColor(Color.RED) + setTime(0.01f) + setLumaMatteColor(Color.WHITE) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 2f228a8da0c8..e10a80cce793 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -158,7 +158,6 @@ import com.android.wm.shell.transition.Transitions; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -174,7 +173,6 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; -@Ignore("b/292153259") @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -280,8 +278,6 @@ public class BubblesTest extends SysuiTestCase { @Mock private TaskStackListenerImpl mTaskStackListener; @Mock - private ShellTaskOrganizer mShellTaskOrganizer; - @Mock private KeyguardStateController mKeyguardStateController; @Mock private ScreenOffAnimationController mScreenOffAnimationController; @@ -298,6 +294,7 @@ public class BubblesTest extends SysuiTestCase { @Mock private Icon mAppBubbleIcon; + private ShellTaskOrganizer mShellTaskOrganizer; private TaskViewTransitions mTaskViewTransitions; private TestableBubblePositioner mPositioner; @@ -379,7 +376,13 @@ public class BubblesTest extends SysuiTestCase { mock(UiEventLogger.class), mock(UserTracker.class) ); - when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor); + + mShellTaskOrganizer = new ShellTaskOrganizer(mock(ShellInit.class), + mock(ShellCommandHandler.class), + null, + Optional.empty(), + Optional.empty(), + syncExecutor); mBubbleProperties = new FakeBubbleProperties(); mBubbleController = new TestableBubbleController( mContext, diff --git a/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt new file mode 100644 index 000000000000..026372f64e2c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/androidx/core/animation/AndroidXAnimatorIsolationRule.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.core.animation + +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +class AndroidXAnimatorIsolationRule : TestRule { + + private class TestAnimationHandler : AnimationHandler(null) { + override fun addAnimationFrameCallback(callback: AnimationFrameCallback?) = doFail() + override fun removeCallback(callback: AnimationFrameCallback?) = doFail() + override fun onAnimationFrame(frameTime: Long) = doFail() + override fun setFrameDelay(frameDelay: Long) = doFail() + override fun getFrameDelay(): Long = doFail() + } + + override fun apply(base: Statement, description: Description): Statement { + return object : Statement() { + @Throws(Throwable::class) + override fun evaluate() { + AnimationHandler.setTestHandler(testHandler) + try { + base.evaluate() + } finally { + AnimationHandler.setTestHandler(null) + } + } + } + } + + companion object { + private val testHandler = TestAnimationHandler() + private fun doFail(): Nothing = + error( + "Test's animations are not isolated! " + + "Did you forget to add an AnimatorTestRule to your test class?" + ) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java index de177168e20f..28b7d4171df1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java @@ -33,6 +33,7 @@ import android.testing.TestWithLooperRule; import android.testing.TestableLooper; import android.util.Log; +import androidx.core.animation.AndroidXAnimatorIsolationRule; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.UiDevice; @@ -52,6 +53,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogManager; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Rule; import org.mockito.Mockito; @@ -69,6 +71,12 @@ public abstract class SysuiTestCase { private static final String TAG = "SysuiTestCase"; private Handler mHandler; + + // set the lowest order so it's the outermost rule + @ClassRule(order = Integer.MIN_VALUE) + public static AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule = + new AndroidXAnimatorIsolationRule(); + @Rule public SysuiTestableContext mContext = new SysuiTestableContext( InstrumentationRegistry.getContext(), getLeakCheck()); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt index f4c2db1b944e..1e1dc4fc59b1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt @@ -61,6 +61,19 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository { _wasDisabled = true } + private val faceAuthPaused = MutableStateFlow(false) + override fun pauseFaceAuth() { + faceAuthPaused.value = true + } + + override fun resumeFaceAuth() { + faceAuthPaused.value = false + } + + fun isFaceAuthPaused(): Boolean { + return faceAuthPaused.value + } + override suspend fun authenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) { _runningAuthRequest.value = uiEvent to fallbackToDetection _isAuthRunning.value = true diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt index f39982f54441..26a75d0cc70a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt @@ -41,7 +41,6 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.RemoteUserInput import com.android.systemui.scene.shared.model.RemoteUserInputAction import com.android.systemui.scene.shared.model.SceneContainerConfig -import com.android.systemui.scene.shared.model.SceneContainerNames import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.UserRepository @@ -96,13 +95,9 @@ class SceneTestUtils( private val context = test.context fun fakeSceneContainerRepository( - containerConfigurations: Set<SceneContainerConfig> = - setOf( - fakeSceneContainerConfig(CONTAINER_1), - fakeSceneContainerConfig(CONTAINER_2), - ) + containerConfig: SceneContainerConfig = fakeSceneContainerConfig(), ): SceneContainerRepository { - return SceneContainerRepository(containerConfigurations.associateBy { it.name }) + return SceneContainerRepository(containerConfig) } fun fakeSceneKeys(): List<SceneKey> { @@ -116,11 +111,9 @@ class SceneTestUtils( } fun fakeSceneContainerConfig( - name: String, sceneKeys: List<SceneKey> = fakeSceneKeys(), ): SceneContainerConfig { return SceneContainerConfig( - name = name, sceneKeys = sceneKeys, initialSceneKey = SceneKey.Lockscreen, ) @@ -174,7 +167,6 @@ class SceneTestUtils( authenticationInteractor = authenticationInteractor, sceneInteractor = sceneInteractor, featureFlags = featureFlags, - containerName = CONTAINER_1, ) } @@ -184,14 +176,8 @@ class SceneTestUtils( return BouncerViewModel( applicationContext = context, applicationScope = applicationScope(), - interactorFactory = - object : BouncerInteractor.Factory { - override fun create(containerName: String): BouncerInteractor { - return bouncerInteractor - } - }, + interactor = bouncerInteractor, featureFlags = featureFlags, - containerName = CONTAINER_1, ) } @@ -202,13 +188,7 @@ class SceneTestUtils( return LockscreenSceneInteractor( applicationScope = applicationScope(), authenticationInteractor = authenticationInteractor, - bouncerInteractorFactory = - object : BouncerInteractor.Factory { - override fun create(containerName: String): BouncerInteractor { - return bouncerInteractor - } - }, - containerName = CONTAINER_1, + bouncerInteractor = bouncerInteractor, ) } @@ -217,9 +197,6 @@ class SceneTestUtils( } companion object { - const val CONTAINER_1 = SceneContainerNames.SYSTEM_UI_DEFAULT - const val CONTAINER_2 = "container2" - val REMOTE_INPUT_DOWN_GESTURE = listOf( RemoteUserInput(10f, 10f, RemoteUserInputAction.DOWN), diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index fbd54555dbbf..622cb6609630 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -166,6 +166,7 @@ import com.android.internal.util.CollectionUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.LocalManagerRegistry; +import com.android.server.SystemConfig; import com.android.server.art.model.DexoptParams; import com.android.server.art.model.DexoptResult; import com.android.server.pm.Installer.LegacyDexoptDisabledException; @@ -230,6 +231,7 @@ final class InstallPackageHelper { private final ViewCompiler mViewCompiler; private final SharedLibrariesImpl mSharedLibraries; private final PackageManagerServiceInjector mInjector; + private final UpdateOwnershipHelper mUpdateOwnershipHelper; // TODO(b/198166813): remove PMS dependency InstallPackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) { @@ -247,6 +249,7 @@ final class InstallPackageHelper { mPackageAbiHelper = pm.mInjector.getAbiHelper(); mViewCompiler = pm.mInjector.getViewCompiler(); mSharedLibraries = pm.mInjector.getSharedLibrariesImpl(); + mUpdateOwnershipHelper = pm.mInjector.getUpdateOwnershipHelper(); } InstallPackageHelper(PackageManagerService pm) { @@ -332,6 +335,8 @@ final class InstallPackageHelper { final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null : mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName( parsedPackage.getPackageName()); + final boolean isUpdateOwnershipDenylisted = + mUpdateOwnershipHelper.isUpdateOwnershipDenylisted(parsedPackage.getPackageName()); final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null; // For standard install (install via session), the installSource isn't null. @@ -367,6 +372,9 @@ final class InstallPackageHelper { & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; final boolean isSameUpdateOwner = TextUtils.equals(oldUpdateOwner, installSource.mInstallerPackageName); + final boolean isInstallerUpdateOwnerDenylistProvider = + mUpdateOwnershipHelper.isUpdateOwnershipDenyListProvider( + installSource.mUpdateOwnerPackageName); // Here we handle the update owner for the package, and the rules are: // -. Only enabling update ownership enforcement on initial installation if the @@ -374,13 +382,16 @@ final class InstallPackageHelper { // -. Once the installer changes and users agree to proceed, clear the update // owner (package state in other users are taken into account as well). if (!isUpdate) { - if (!isRequestUpdateOwnership) { + if (!isRequestUpdateOwnership + || isUpdateOwnershipDenylisted + || isInstallerUpdateOwnerDenylistProvider) { installSource = installSource.setUpdateOwnerPackageName(null); } else if ((!isUpdateOwnershipEnabled && pkgAlreadyExists) || (isUpdateOwnershipEnabled && !isSameUpdateOwner)) { installSource = installSource.setUpdateOwnerPackageName(null); } - } else if (!isSameUpdateOwner || !isUpdateOwnershipEnabled) { + } else if (!isSameUpdateOwner + || !isUpdateOwnershipEnabled) { installSource = installSource.setUpdateOwnerPackageName(null); } } @@ -473,6 +484,19 @@ final class InstallPackageHelper { pkgSetting.setLoadingProgress(1f); } + ArraySet<String> listItems = mUpdateOwnershipHelper.readUpdateOwnerDenyList(pkgSetting); + if (listItems != null && !listItems.isEmpty()) { + mUpdateOwnershipHelper.addToUpdateOwnerDenyList(pkgSetting.getPackageName(), listItems); + for (String unownedPackage : listItems) { + PackageSetting unownedSetting = mPm.mSettings.getPackageLPr(unownedPackage); + SystemConfig config = SystemConfig.getInstance(); + if (unownedSetting != null + && config.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) { + unownedSetting.setUpdateOwnerPackage(null); + } + } + } + return pkg; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dbc2fd89e58c..e5dc688529e8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1608,7 +1608,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService (i, pm) -> new SharedLibrariesImpl(pm, i), (i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(), i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(), - context)); + context), + (i, pm) -> new UpdateOwnershipHelper()); if (Build.VERSION.SDK_INT <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java index 13549f536c9f..51840e70ed26 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java @@ -144,6 +144,7 @@ public class PackageManagerServiceInjector { private final Singleton<IBackupManager> mIBackupManager; private final Singleton<SharedLibrariesImpl> mSharedLibrariesProducer; private final Singleton<CrossProfileIntentFilterHelper> mCrossProfileIntentFilterHelperProducer; + private final Singleton<UpdateOwnershipHelper> mUpdateOwnershipHelperProducer; PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock, Installer installer, Object installLock, PackageAbiHelper abiHelper, @@ -183,7 +184,8 @@ public class PackageManagerServiceInjector { Producer<BackgroundDexOptService> backgroundDexOptService, Producer<IBackupManager> iBackupManager, Producer<SharedLibrariesImpl> sharedLibrariesProducer, - Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer) { + Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer, + Producer<UpdateOwnershipHelper> updateOwnershipHelperProducer) { mContext = context; mLock = lock; mInstaller = installer; @@ -238,6 +240,7 @@ public class PackageManagerServiceInjector { mSharedLibrariesProducer = new Singleton<>(sharedLibrariesProducer); mCrossProfileIntentFilterHelperProducer = new Singleton<>( crossProfileIntentFilterHelperProducer); + mUpdateOwnershipHelperProducer = new Singleton<>(updateOwnershipHelperProducer); } /** @@ -423,6 +426,11 @@ public class PackageManagerServiceInjector { return mSharedLibrariesProducer.get(this, mPackageManager); } + public UpdateOwnershipHelper getUpdateOwnershipHelper() { + return mUpdateOwnershipHelperProducer.get(this, mPackageManager); + } + + /** Provides an abstraction to static access to system state. */ public interface SystemWrapper { void disablePackageCaches(); diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java index 10673c6f2dd2..59314a26ab97 100644 --- a/services/core/java/com/android/server/pm/RemovePackageHelper.java +++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java @@ -312,6 +312,7 @@ final class RemovePackageHelper { synchronized (mPm.mLock) { mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName()); mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName); + mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName); final Computer snapshot = mPm.snapshotComputer(); mPm.mAppsFilter.removePackage(snapshot, snapshot.getPackageStateInternal(packageName)); diff --git a/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java b/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java new file mode 100644 index 000000000000..43752f31a1a2 --- /dev/null +++ b/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.pm; + +import static android.content.pm.PackageManager.PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST; + +import static com.android.server.pm.PackageManagerService.TAG; + +import android.Manifest; +import android.app.ResourcesManager; +import android.content.pm.ApplicationInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.pkg.AndroidPackage; +import com.android.server.pm.pkg.component.ParsedUsesPermission; + +import org.xmlpull.v1.XmlPullParser; + +import java.util.List; + +/** Helper class for managing update ownership and optouts for the feature. */ +public class UpdateOwnershipHelper { + + // Called out in PackageManager.PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST docs + private static final int MAX_DENYLIST_SIZE = 500; + private static final String TAG_OWNERSHIP_OPT_OUT = "deny-ownership"; + private final ArrayMap<String, ArraySet<String>> mUpdateOwnerOptOutsToOwners = + new ArrayMap<>(200); + + private final Object mLock = new Object(); + + private static boolean hasValidOwnershipDenyList(PackageSetting pkgSetting) { + AndroidPackage pkg = pkgSetting.getPkg(); + // we're checking for uses-permission for these priv permissions instead of grant as we're + // only considering system apps to begin with, so presumed to be granted. + return pkg != null + && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp()) + && pkg.getProperties().containsKey(PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST) + && usesAnyPermission(pkg, + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.INSTALL_PACKAGE_UPDATES); + } + + + /** Returns true if a package setting declares that it uses a permission */ + private static boolean usesAnyPermission(AndroidPackage pkgSetting, String... permissions) { + List<ParsedUsesPermission> usesPermissions = pkgSetting.getUsesPermissions(); + for (int i = 0; i < usesPermissions.size(); i++) { + for (int j = 0; j < permissions.length; j++) { + if (permissions[j].equals(usesPermissions.get(i).getName())) { + return true; + } + } + } + return false; + } + + /** + * Reads the update owner deny list from a {@link PackageSetting} and returns the set of + * packages it contains or {@code null} if it cannot be read. + */ + public ArraySet<String> readUpdateOwnerDenyList(PackageSetting pkgSetting) { + if (!hasValidOwnershipDenyList(pkgSetting)) { + return null; + } + AndroidPackage pkg = pkgSetting.getPkg(); + if (pkg == null) { + return null; + } + ArraySet<String> ownershipDenyList = new ArraySet<>(MAX_DENYLIST_SIZE); + try { + int resId = pkg.getProperties().get(PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST) + .getResourceId(); + ApplicationInfo appInfo = AndroidPackageUtils.generateAppInfoWithoutState(pkg); + Resources resources = ResourcesManager.getInstance().getResources( + null, appInfo.sourceDir, appInfo.splitSourceDirs, appInfo.resourceDirs, + appInfo.overlayPaths, appInfo.sharedLibraryFiles, null, Configuration.EMPTY, + null, null, null); + try (XmlResourceParser parser = resources.getXml(resId)) { + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + if (parser.next() == XmlResourceParser.START_TAG) { + if (TAG_OWNERSHIP_OPT_OUT.equals(parser.getName())) { + parser.next(); + String packageName = parser.getText(); + if (packageName != null && !packageName.isBlank()) { + ownershipDenyList.add(packageName); + if (ownershipDenyList.size() > MAX_DENYLIST_SIZE) { + Slog.w(TAG, "Deny list defined by " + pkg.getPackageName() + + " was trucated to maximum size of " + + MAX_DENYLIST_SIZE); + break; + } + } + } + } + } + } + } catch (Exception e) { + Slog.e(TAG, "Failed to parse update owner list for " + pkgSetting.getPackageName(), e); + return null; + } + return ownershipDenyList; + } + + /** + * Begins tracking the contents of a deny list and the owner of that deny list for use in calls + * to {@link #isUpdateOwnershipDenylisted(String)} and + * {@link #isUpdateOwnershipDenyListProvider(String)}. + * + * @param listOwner the packageName of the package that owns the deny list. + * @param listContents the list of packageNames that are on the deny list. + */ + public void addToUpdateOwnerDenyList(String listOwner, ArraySet<String> listContents) { + synchronized (mLock) { + for (int i = 0; i < listContents.size(); i++) { + String packageName = listContents.valueAt(i); + ArraySet<String> priorDenyListOwners = mUpdateOwnerOptOutsToOwners.putIfAbsent( + packageName, new ArraySet<>(new String[]{listOwner})); + if (priorDenyListOwners != null) { + priorDenyListOwners.add(listOwner); + } + } + } + } + + /** + * Stop tracking the contents of a deny list owned by the provided owner of the deny list. + * @param listOwner the packageName of the package that owns the deny list. + */ + public void removeUpdateOwnerDenyList(String listOwner) { + synchronized (mLock) { + for (int i = mUpdateOwnerOptOutsToOwners.size() - 1; i >= 0; i--) { + ArraySet<String> packageDenyListContributors = + mUpdateOwnerOptOutsToOwners.get(mUpdateOwnerOptOutsToOwners.keyAt(i)); + if (packageDenyListContributors.remove(listOwner) + && packageDenyListContributors.isEmpty()) { + mUpdateOwnerOptOutsToOwners.removeAt(i); + } + } + } + } + + /** + * Returns {@code true} if the provided package name is on a valid update ownership deny list. + */ + public boolean isUpdateOwnershipDenylisted(String packageName) { + return mUpdateOwnerOptOutsToOwners.containsKey(packageName); + } + + /** + * Returns {@code true} if the provided package name defines a valid update ownership deny list. + */ + public boolean isUpdateOwnershipDenyListProvider(String packageName) { + if (packageName == null) { + return false; + } + synchronized (mLock) { + for (int i = mUpdateOwnerOptOutsToOwners.size() - 1; i >= 0; i--) { + if (mUpdateOwnerOptOutsToOwners.valueAt(i).contains(packageName)) { + return true; + } + } + return false; + } + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 931a2bf53b84..3c753326fb7d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -216,6 +216,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { val handler = TestHandler(null) val defaultAppProvider: DefaultAppProvider = mock() val backgroundHandler = TestHandler(null) + val updateOwnershipHelper: UpdateOwnershipHelper = mock() } companion object { @@ -303,6 +304,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { whenever(mocks.injector.handler) { mocks.handler } whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider } whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler } + whenever(mocks.injector.updateOwnershipHelper) { mocks.updateOwnershipHelper } wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig) whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP) whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST) diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java index bb8b986c6f61..ddd1221e4c91 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java @@ -62,6 +62,7 @@ import android.platform.test.annotations.Presubmit; import android.view.ContentRecordingSession; import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; @@ -688,6 +689,7 @@ public class MediaProjectionManagerServiceTest { assertThat(mService.isCurrentProjection(projection)).isTrue(); } + @FlakyTest(bugId = 288342281) @Test public void setContentRecordingSession_successful_notifiesListeners() throws Exception { diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index 997015ff1c08..b3db2dea4a27 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java @@ -365,7 +365,7 @@ public class SoundTriggerService extends SystemService { // Validate package name try { int uid = mPackageManager.getPackageUid(mOriginatorIdentity.packageName, - PackageManager.PackageInfoFlags.of(0)); + PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ANY_USER)); if (!UserHandle.isSameApp(uid, mOriginatorIdentity.uid)) { throw new SecurityException("Uid " + mOriginatorIdentity.uid + " attempted to spoof package name " + |