Merge "[Ravenwood] Rename all-updatable-modules-system-stubs" into main
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 18914e1..6da96c1 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -217,6 +217,16 @@
}
flag {
+ name: "disallow_user_control_stopped_state_fix"
+ namespace: "enterprise"
+ description: "Ensure DPM.setUserControlDisabledPackages() clears FLAG_STOPPED for the app"
+ bug: "330688482"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "esim_management_ux_enabled"
namespace: "enterprise"
description: "Enable UX changes for esim management"
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 7f01a82..37f419d 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -462,6 +462,20 @@
}
/**
+ * @return The next package's device Id from its context.
+ * This device ID is used for permissions checking during attribution source validation.
+ *
+ * @hide
+ */
+ public int getNextDeviceId() {
+ if (mAttributionSourceState.next != null
+ && mAttributionSourceState.next.length > 0) {
+ return mAttributionSourceState.next[0].deviceId;
+ }
+ return Context.DEVICE_ID_DEFAULT;
+ }
+
+ /**
* Checks whether this attribution source can be trusted. That is whether
* the app it refers to created it and provided to the attribution chain.
*
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 51758aa..ee5e533 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -81,8 +81,15 @@
}
flag {
- name: "report_primary_auth_attempts"
- namespace: "biometrics"
- description: "Report primary auth attempts from LockSettingsService"
- bug: "285053096"
+ name: "report_primary_auth_attempts"
+ namespace: "biometrics"
+ description: "Report primary auth attempts from LockSettingsService"
+ bug: "285053096"
+}
+
+flag {
+ name: "dump_attestation_verifications"
+ namespace: "hardware_backed_security"
+ description: "Add a dump capability for attestation_verification service"
+ bug: "335498868"
}
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index db665a9..c4becea 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -1392,10 +1392,6 @@
private static Rect computeSafeInsets(int displayW, int displayH, Insets waterFallInsets,
Rect[] bounds) {
- if (displayW == displayH) {
- throw new UnsupportedOperationException("not implemented: display=" + displayW + "x"
- + displayH + " bounding rects=" + Arrays.toString(bounds));
- }
int leftInset = Math.max(waterFallInsets.left, findCutoutInsetForSide(
displayW, displayH, bounds[BOUNDS_POSITION_LEFT], Gravity.LEFT));
diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp
index 7f630cb..5d7b33e 100644
--- a/core/jni/android_hardware_display_DisplayViewport.cpp
+++ b/core/jni/android_hardware_display_DisplayViewport.cpp
@@ -59,7 +59,8 @@
static const jclass intClass = FindClassOrDie(env, "java/lang/Integer");
static const jmethodID byteValue = env->GetMethodID(intClass, "byteValue", "()B");
- viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId);
+ viewport->displayId = ui::LogicalDisplayId{
+ env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId)};
viewport->isActive = env->GetBooleanField(viewportObj, gDisplayViewportClassInfo.isActive);
jint orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
viewport->orientation = static_cast<ui::Rotation>(orientation);
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index bed7768..69f6334 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -165,8 +165,8 @@
mInfo.ownerUid = gui::Uid{
static_cast<uid_t>(env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid))};
mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
- mInfo.displayId = env->GetIntField(obj,
- gInputWindowHandleClassInfo.displayId);
+ mInfo.displayId =
+ ui::LogicalDisplayId{env->GetIntField(obj, gInputWindowHandleClassInfo.displayId)};
jobject inputApplicationHandleObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.inputApplicationHandle);
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index ca8752f..06e0d2d 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -135,8 +135,8 @@
jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
KeyEvent event;
- event.initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
- metaState, repeatCount, downTime, eventTime);
+ event.initialize(id, deviceId, source, ui::LogicalDisplayId{displayId}, *hmac, action, flags,
+ keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
return event;
}
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 3e3af40..f914bee 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -22,7 +22,6 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <attestation/HmacKeyManager.h>
-#include <gui/constants.h>
#include <input/Input.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
@@ -367,8 +366,8 @@
ui::Transform transform;
transform.set(xOffset, yOffset);
ui::Transform identityTransform;
- event->initialize(InputEvent::nextId(), deviceId, source, displayId, INVALID_HMAC, action, 0,
- flags, edgeFlags, metaState, buttonState,
+ event->initialize(InputEvent::nextId(), deviceId, source, ui::LogicalDisplayId{displayId},
+ INVALID_HMAC, action, 0, flags, edgeFlags, metaState, buttonState,
static_cast<MotionClassification>(classification), transform, xPrecision,
yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, downTimeNanos,
@@ -646,13 +645,13 @@
static jint android_view_MotionEvent_nativeGetDisplayId(CRITICAL_JNI_PARAMS_COMMA jlong nativePtr) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getDisplayId();
+ return static_cast<jint>(event->getDisplayId().val());
}
static void android_view_MotionEvent_nativeSetDisplayId(CRITICAL_JNI_PARAMS_COMMA jlong nativePtr,
jint displayId) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->setDisplayId(displayId);
+ event->setDisplayId(ui::LogicalDisplayId{displayId});
}
static jint android_view_MotionEvent_nativeGetAction(CRITICAL_JNI_PARAMS_COMMA jlong nativePtr) {
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
index bc69d1e6..c39d5e2 100644
--- a/core/jni/android_window_WindowInfosListener.cpp
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -60,7 +60,7 @@
}
ScopedLocalRef<jobject> matrixObj(env, AMatrix_newInstance(env, transformValues));
return env->NewObject(gDisplayInfoClassInfo.clazz, gDisplayInfoClassInfo.ctor,
- displayInfo.displayId, displayInfo.logicalWidth,
+ displayInfo.displayId.val(), displayInfo.logicalWidth,
displayInfo.logicalHeight, matrixObj.get());
}
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 0433855..bf2fdda 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -329,7 +329,8 @@
InputDeviceInfo info = InputDeviceInfo();
info.initialize(keyboardId, 0, 0, InputDeviceIdentifier(),
- "keyboard " + std::to_string(keyboardId), true, false, 0);
+ "keyboard " + std::to_string(keyboardId), true, false,
+ ui::ADISPLAY_ID_DEFAULT);
info.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
info.setKeyCharacterMap(*charMap);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 3c788b1..7bceb2c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -2341,8 +2341,8 @@
showScrim(true, null /* runnable */);
updateBubbleShadows(mIsExpanded);
- updateBadges(false /* setBadgeForCollapsedStack */);
mBubbleContainer.setActiveController(mExpandedAnimationController);
+ updateBadges(false /* setBadgeForCollapsedStack */);
updateOverflowVisibility();
updatePointerPosition(false /* forIme */);
mExpandedAnimationController.expandFromStack(() -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index ad29d15..19af3d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -52,7 +52,7 @@
WM_SHELL_SYSUI_EVENTS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
- Consts.TAG_WM_SHELL),
+ Consts.TAG_WM_DESKTOP_MODE),
WM_SHELL_FLOATING_APPS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
WM_SHELL_FOLDABLE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
@@ -120,6 +120,7 @@
private static final String TAG_WM_SHELL = "WindowManagerShell";
private static final String TAG_WM_STARTING_WINDOW = "ShellStartingWindow";
private static final String TAG_WM_SPLIT_SCREEN = "ShellSplitScreen";
+ private static final String TAG_WM_DESKTOP_MODE = "ShellDesktopMode";
private static final boolean ENABLE_DEBUG = true;
private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 4d02ec2..968b27b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -426,7 +426,8 @@
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"Converting mixed transition into a keyguard transition");
// Consume the original mixed transition
- onTransitionConsumed(transition, false, null);
+ mActiveTransitions.remove(mixed);
+ mixed.onTransitionConsumed(transition, false, null);
return true;
} else {
// Keyguard handler cannot handle it, process through original mixed
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 07f0c39..5379ca6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -24,6 +24,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT;
@@ -53,6 +54,7 @@
import android.view.WindowManagerGlobal;
import android.window.InputTransferToken;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
@@ -398,12 +400,17 @@
float rawX = e.getRawX(0);
float rawY = e.getRawY(0);
int ctrlType = mDragResizeWindowGeometry.calculateCtrlType(isTouch, x, y);
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE,
+ "%s: Handling action down, update ctrlType to %d", TAG, ctrlType);
mDragStartTaskBounds = mCallback.onDragPositioningStart(ctrlType,
rawX, rawY);
// Increase the input sink region to cover the whole screen; this is to
// prevent input and focus from going to other tasks during a drag resize.
updateInputSinkRegionForDrag(mDragStartTaskBounds);
result = true;
+ } else {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE,
+ "%s: Handling action down, but ignore event", TAG);
}
break;
}
@@ -498,6 +505,8 @@
// where views in the task can receive input events because we can't set touch regions
// of input sinks to have rounded corners.
if (mLastCursorType != cursorType || cursorType != PointerIcon.TYPE_DEFAULT) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: update pointer icon from %d to %d",
+ TAG, mLastCursorType, cursorType);
mInputManager.setPointerIcon(PointerIcon.getSystemIcon(mContext, cursorType),
displayId, deviceId, pointerId, mInputChannel.getToken());
mLastCursorType = cursorType;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index eafb569..4f513f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -33,6 +33,9 @@
import android.util.Size;
import android.view.MotionEvent;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
import com.android.wm.shell.R;
import java.util.Objects;
@@ -41,6 +44,11 @@
* Geometry for a drag resize region for a particular window.
*/
final class DragResizeWindowGeometry {
+ // TODO(b/337264971) clean up when no longer needed
+ @VisibleForTesting static final boolean DEBUG = true;
+ // The additional width to apply to edge resize bounds just for logging when a touch is
+ // close.
+ @VisibleForTesting static final int EDGE_DEBUG_BUFFER = 15;
private final int mTaskCornerRadius;
private final Size mTaskSize;
// The size of the handle applied to the edges of the window, for the user to drag resize.
@@ -51,10 +59,9 @@
// The task corners to permit drag resizing with a fine input, such as stylus or cursor.
private final @NonNull TaskCorners mFineTaskCorners;
// The bounds for each edge drag region, which can resize the task in one direction.
- private final @NonNull Rect mTopEdgeBounds;
- private final @NonNull Rect mLeftEdgeBounds;
- private final @NonNull Rect mRightEdgeBounds;
- private final @NonNull Rect mBottomEdgeBounds;
+ private final @NonNull TaskEdges mTaskEdges;
+ // Extra-large edge bounds for logging to help debug when an edge resize is ignored.
+ private final @Nullable TaskEdges mDebugTaskEdges;
DragResizeWindowGeometry(int taskCornerRadius, @NonNull Size taskSize,
int resizeHandleThickness, int fineCornerSize, int largeCornerSize) {
@@ -66,26 +73,12 @@
mFineTaskCorners = new TaskCorners(mTaskSize, fineCornerSize);
// Save touch areas for each edge.
- mTopEdgeBounds = new Rect(
- -mResizeHandleThickness,
- -mResizeHandleThickness,
- mTaskSize.getWidth() + mResizeHandleThickness,
- 0);
- mLeftEdgeBounds = new Rect(
- -mResizeHandleThickness,
- 0,
- 0,
- mTaskSize.getHeight());
- mRightEdgeBounds = new Rect(
- mTaskSize.getWidth(),
- 0,
- mTaskSize.getWidth() + mResizeHandleThickness,
- mTaskSize.getHeight());
- mBottomEdgeBounds = new Rect(
- -mResizeHandleThickness,
- mTaskSize.getHeight(),
- mTaskSize.getWidth() + mResizeHandleThickness,
- mTaskSize.getHeight() + mResizeHandleThickness);
+ mTaskEdges = new TaskEdges(mTaskSize, mResizeHandleThickness);
+ if (DEBUG) {
+ mDebugTaskEdges = new TaskEdges(mTaskSize, mResizeHandleThickness + EDGE_DEBUG_BUFFER);
+ } else {
+ mDebugTaskEdges = null;
+ }
}
/**
@@ -127,10 +120,13 @@
*/
void union(@NonNull Region region) {
// Apply the edge resize regions.
- region.union(mTopEdgeBounds);
- region.union(mLeftEdgeBounds);
- region.union(mRightEdgeBounds);
- region.union(mBottomEdgeBounds);
+ if (inDebugMode()) {
+ // Use the larger edge sizes if we are debugging, to be able to log if we ignored a
+ // touch due to the size of the edge region.
+ mDebugTaskEdges.union(region);
+ } else {
+ mTaskEdges.union(region);
+ }
if (enableWindowingEdgeDragResize()) {
// Apply the corners as well for the larger corners, to ensure we capture all possible
@@ -216,6 +212,10 @@
@DragPositioningCallback.CtrlType
private int calculateEdgeResizeCtrlType(float x, float y) {
+ if (inDebugMode() && (mDebugTaskEdges.contains((int) x, (int) y)
+ && !mTaskEdges.contains((int) x, (int) y))) {
+ return CTRL_TYPE_UNDEFINED;
+ }
int ctrlType = CTRL_TYPE_UNDEFINED;
// mTaskCornerRadius is only used in comparing with corner regions. Comparisons with
// sides will use the bounds specified in setGeometry and not go into task bounds.
@@ -306,10 +306,9 @@
&& this.mResizeHandleThickness == other.mResizeHandleThickness
&& this.mFineTaskCorners.equals(other.mFineTaskCorners)
&& this.mLargeTaskCorners.equals(other.mLargeTaskCorners)
- && this.mTopEdgeBounds.equals(other.mTopEdgeBounds)
- && this.mLeftEdgeBounds.equals(other.mLeftEdgeBounds)
- && this.mRightEdgeBounds.equals(other.mRightEdgeBounds)
- && this.mBottomEdgeBounds.equals(other.mBottomEdgeBounds);
+ && (inDebugMode()
+ ? this.mDebugTaskEdges.equals(other.mDebugTaskEdges)
+ : this.mTaskEdges.equals(other.mTaskEdges));
}
@Override
@@ -320,10 +319,11 @@
mResizeHandleThickness,
mFineTaskCorners,
mLargeTaskCorners,
- mTopEdgeBounds,
- mLeftEdgeBounds,
- mRightEdgeBounds,
- mBottomEdgeBounds);
+ (inDebugMode() ? mDebugTaskEdges : mTaskEdges));
+ }
+
+ private boolean inDebugMode() {
+ return DEBUG && mDebugTaskEdges != null;
}
/**
@@ -431,4 +431,92 @@
mRightBottomCornerBounds);
}
}
+
+ /**
+ * Representation of the drag resize regions at the edges of the window.
+ */
+ private static class TaskEdges {
+ private final @NonNull Rect mTopEdgeBounds;
+ private final @NonNull Rect mLeftEdgeBounds;
+ private final @NonNull Rect mRightEdgeBounds;
+ private final @NonNull Rect mBottomEdgeBounds;
+ private final @NonNull Region mRegion;
+
+ private TaskEdges(@NonNull Size taskSize, int resizeHandleThickness) {
+ // Save touch areas for each edge.
+ mTopEdgeBounds = new Rect(
+ -resizeHandleThickness,
+ -resizeHandleThickness,
+ taskSize.getWidth() + resizeHandleThickness,
+ 0);
+ mLeftEdgeBounds = new Rect(
+ -resizeHandleThickness,
+ 0,
+ 0,
+ taskSize.getHeight());
+ mRightEdgeBounds = new Rect(
+ taskSize.getWidth(),
+ 0,
+ taskSize.getWidth() + resizeHandleThickness,
+ taskSize.getHeight());
+ mBottomEdgeBounds = new Rect(
+ -resizeHandleThickness,
+ taskSize.getHeight(),
+ taskSize.getWidth() + resizeHandleThickness,
+ taskSize.getHeight() + resizeHandleThickness);
+
+ mRegion = new Region();
+ mRegion.union(mTopEdgeBounds);
+ mRegion.union(mLeftEdgeBounds);
+ mRegion.union(mRightEdgeBounds);
+ mRegion.union(mBottomEdgeBounds);
+ }
+
+ /**
+ * Returns {@code true} if the edges contain the given point.
+ */
+ private boolean contains(int x, int y) {
+ return mRegion.contains(x, y);
+ }
+
+ /**
+ * Updates the region to include all four corners.
+ */
+ private void union(Region region) {
+ region.union(mTopEdgeBounds);
+ region.union(mLeftEdgeBounds);
+ region.union(mRightEdgeBounds);
+ region.union(mBottomEdgeBounds);
+ }
+
+ @Override
+ public String toString() {
+ return "TaskEdges for the"
+ + " top " + mTopEdgeBounds
+ + " left " + mLeftEdgeBounds
+ + " right " + mRightEdgeBounds
+ + " bottom " + mBottomEdgeBounds;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (this == obj) return true;
+ if (!(obj instanceof TaskEdges other)) return false;
+
+ return this.mTopEdgeBounds.equals(other.mTopEdgeBounds)
+ && this.mLeftEdgeBounds.equals(other.mLeftEdgeBounds)
+ && this.mRightEdgeBounds.equals(other.mRightEdgeBounds)
+ && this.mBottomEdgeBounds.equals(other.mBottomEdgeBounds);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mTopEdgeBounds,
+ mLeftEdgeBounds,
+ mRightEdgeBounds,
+ mBottomEdgeBounds);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
index 82e5a1c..5464508 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
@@ -56,6 +56,8 @@
private static final Size TASK_SIZE = new Size(500, 1000);
private static final int TASK_CORNER_RADIUS = 10;
private static final int EDGE_RESIZE_THICKNESS = 15;
+ private static final int EDGE_RESIZE_DEBUG_THICKNESS = EDGE_RESIZE_THICKNESS
+ + (DragResizeWindowGeometry.DEBUG ? DragResizeWindowGeometry.EDGE_DEBUG_BUFFER : 0);
private static final int FINE_CORNER_SIZE = EDGE_RESIZE_THICKNESS * 2 + 10;
private static final int LARGE_CORNER_SIZE = FINE_CORNER_SIZE + 10;
private static final DragResizeWindowGeometry GEOMETRY = new DragResizeWindowGeometry(
@@ -90,13 +92,14 @@
EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE, LARGE_CORNER_SIZE),
new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE, LARGE_CORNER_SIZE))
- .addEqualityGroup(
+ .addEqualityGroup(new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
+ EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE, LARGE_CORNER_SIZE + 5),
new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
- EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE,
- LARGE_CORNER_SIZE + 5),
+ EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE, LARGE_CORNER_SIZE + 5))
+ .addEqualityGroup(new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
+ EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE + 4, LARGE_CORNER_SIZE),
new DragResizeWindowGeometry(TASK_CORNER_RADIUS, TASK_SIZE,
- EDGE_RESIZE_THICKNESS + 10, FINE_CORNER_SIZE,
- LARGE_CORNER_SIZE + 5))
+ EDGE_RESIZE_THICKNESS, FINE_CORNER_SIZE + 4, LARGE_CORNER_SIZE))
.testEquals();
}
@@ -122,21 +125,21 @@
private static void verifyHorizontalEdge(@NonNull Region region, @NonNull Point point) {
assertThat(region.contains(point.x, point.y)).isTrue();
// Horizontally along the edge is still contained.
- assertThat(region.contains(point.x + EDGE_RESIZE_THICKNESS, point.y)).isTrue();
- assertThat(region.contains(point.x - EDGE_RESIZE_THICKNESS, point.y)).isTrue();
+ assertThat(region.contains(point.x + EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isTrue();
+ assertThat(region.contains(point.x - EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isTrue();
// Vertically along the edge is not contained.
- assertThat(region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS)).isFalse();
- assertThat(region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS)).isFalse();
+ assertThat(region.contains(point.x, point.y - EDGE_RESIZE_DEBUG_THICKNESS)).isFalse();
+ assertThat(region.contains(point.x, point.y + EDGE_RESIZE_DEBUG_THICKNESS)).isFalse();
}
private static void verifyVerticalEdge(@NonNull Region region, @NonNull Point point) {
assertThat(region.contains(point.x, point.y)).isTrue();
// Horizontally along the edge is not contained.
- assertThat(region.contains(point.x + EDGE_RESIZE_THICKNESS, point.y)).isFalse();
- assertThat(region.contains(point.x - EDGE_RESIZE_THICKNESS, point.y)).isFalse();
+ assertThat(region.contains(point.x + EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isFalse();
+ assertThat(region.contains(point.x - EDGE_RESIZE_DEBUG_THICKNESS, point.y)).isFalse();
// Vertically along the edge is contained.
- assertThat(region.contains(point.x, point.y - EDGE_RESIZE_THICKNESS)).isTrue();
- assertThat(region.contains(point.x, point.y + EDGE_RESIZE_THICKNESS)).isTrue();
+ assertThat(region.contains(point.x, point.y - EDGE_RESIZE_DEBUG_THICKNESS)).isTrue();
+ assertThat(region.contains(point.x, point.y + EDGE_RESIZE_DEBUG_THICKNESS)).isTrue();
}
/**
@@ -148,7 +151,10 @@
public void testRegionUnion_edgeDragResizeEnabled_containsLargeCorners() {
Region region = new Region();
GEOMETRY.union(region);
- final int cornerRadius = LARGE_CORNER_SIZE / 2;
+ // Make sure we're choosing a point outside of any debug region buffer.
+ final int cornerRadius = DragResizeWindowGeometry.DEBUG
+ ? Math.max(LARGE_CORNER_SIZE / 2, EDGE_RESIZE_DEBUG_THICKNESS)
+ : LARGE_CORNER_SIZE / 2;
new TestPoints(TASK_SIZE, cornerRadius).validateRegion(region);
}
@@ -162,7 +168,9 @@
public void testRegionUnion_edgeDragResizeDisabled_containsFineCorners() {
Region region = new Region();
GEOMETRY.union(region);
- final int cornerRadius = FINE_CORNER_SIZE / 2;
+ final int cornerRadius = DragResizeWindowGeometry.DEBUG
+ ? Math.max(LARGE_CORNER_SIZE / 2, EDGE_RESIZE_DEBUG_THICKNESS)
+ : LARGE_CORNER_SIZE / 2;
new TestPoints(TASK_SIZE, cornerRadius).validateRegion(region);
}
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 6a46544..5cf5a1d 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -117,7 +117,7 @@
return {mLocked.pointerX, mLocked.pointerY};
}
-int32_t MouseCursorController::getDisplayId() const {
+ui::LogicalDisplayId MouseCursorController::getDisplayId() const {
std::scoped_lock lock(mLock);
return mLocked.viewport.displayId;
}
@@ -467,10 +467,10 @@
std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
/*
- * Using -1 for displayId here to avoid removing the callback
+ * Using ui::ADISPLAY_ID_NONE for displayId here to avoid removing the callback
* if a TouchSpotController with the same display is removed.
*/
- mContext.addAnimationCallback(-1, func);
+ mContext.addAnimationCallback(ui::ADISPLAY_ID_NONE, func);
}
} // namespace android
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 00dc085..dc7e8ca 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -47,7 +47,7 @@
void move(float deltaX, float deltaY);
void setPosition(float x, float y);
FloatPoint getPosition() const;
- int32_t getDisplayId() const;
+ ui::LogicalDisplayId getDisplayId() const;
void fade(PointerControllerInterface::Transition transition);
void unfade(PointerControllerInterface::Transition transition);
void setDisplayViewport(const DisplayViewport& viewport, bool getAdditionalMouseResources);
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index f97992f..cca1b07 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -142,7 +142,7 @@
}
void PointerController::move(float deltaX, float deltaY) {
- const int32_t displayId = mCursorController.getDisplayId();
+ const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
vec2 transformed;
{
std::scoped_lock lock(getLock());
@@ -153,7 +153,7 @@
}
void PointerController::setPosition(float x, float y) {
- const int32_t displayId = mCursorController.getDisplayId();
+ const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
vec2 transformed;
{
std::scoped_lock lock(getLock());
@@ -164,7 +164,7 @@
}
FloatPoint PointerController::getPosition() const {
- const int32_t displayId = mCursorController.getDisplayId();
+ const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
const auto p = mCursorController.getPosition();
{
std::scoped_lock lock(getLock());
@@ -173,7 +173,7 @@
}
}
-int32_t PointerController::getDisplayId() const {
+ui::LogicalDisplayId PointerController::getDisplayId() const {
return mCursorController.getDisplayId();
}
@@ -202,7 +202,7 @@
}
void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
- BitSet32 spotIdBits, int32_t displayId) {
+ BitSet32 spotIdBits, ui::LogicalDisplayId displayId) {
std::scoped_lock lock(getLock());
std::array<PointerCoords, MAX_POINTERS> outSpotCoords{};
const ui::Transform& transform = getTransformForDisplayLocked(displayId);
@@ -286,7 +286,7 @@
mCursorController.setCustomPointerIcon(icon);
}
-void PointerController::setSkipScreenshot(int32_t displayId, bool skip) {
+void PointerController::setSkipScreenshot(ui::LogicalDisplayId displayId, bool skip) {
std::scoped_lock lock(getLock());
if (skip) {
mLocked.displaysToSkipScreenshot.insert(displayId);
@@ -300,14 +300,14 @@
}
void PointerController::onDisplayViewportsUpdated(const std::vector<DisplayViewport>& viewports) {
- std::unordered_set<int32_t> displayIdSet;
+ std::unordered_set<ui::LogicalDisplayId> displayIdSet;
for (const DisplayViewport& viewport : viewports) {
displayIdSet.insert(viewport.displayId);
}
std::scoped_lock lock(getLock());
for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
- int32_t displayId = it->first;
+ ui::LogicalDisplayId displayId = it->first;
if (!displayIdSet.count(displayId)) {
/*
* Ensures that an in-progress animation won't dereference
@@ -326,7 +326,8 @@
mLocked.mDisplayInfos = displayInfo;
}
-const ui::Transform& PointerController::getTransformForDisplayLocked(int displayId) const {
+const ui::Transform& PointerController::getTransformForDisplayLocked(
+ ui::LogicalDisplayId displayId) const {
const auto& di = mLocked.mDisplayInfos;
auto it = std::find_if(di.begin(), di.end(), [displayId](const gui::DisplayInfo& info) {
return info.displayId == displayId;
@@ -339,7 +340,8 @@
std::scoped_lock lock(getLock());
dump += StringPrintf(INDENT2 "Presentation: %s\n",
ftl::enum_string(mLocked.presentation).c_str());
- dump += StringPrintf(INDENT2 "Pointer Display ID: %" PRIu32 "\n", mLocked.pointerDisplayId);
+ dump += StringPrintf(INDENT2 "Pointer Display ID: %s\n",
+ mLocked.pointerDisplayId.toString().c_str());
dump += StringPrintf(INDENT2 "Viewports:\n");
for (const auto& info : mLocked.mDisplayInfos) {
info.dump(dump, INDENT3);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index eaf34d5..70e5c24 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -55,18 +55,18 @@
void move(float deltaX, float deltaY) override;
void setPosition(float x, float y) override;
FloatPoint getPosition() const override;
- int32_t getDisplayId() const override;
+ ui::LogicalDisplayId getDisplayId() const override;
void fade(Transition transition) override;
void unfade(Transition transition) override;
void setDisplayViewport(const DisplayViewport& viewport) override;
void setPresentation(Presentation presentation) override;
void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
- BitSet32 spotIdBits, int32_t displayId) override;
+ BitSet32 spotIdBits, ui::LogicalDisplayId displayId) override;
void clearSpots() override;
void updatePointerIcon(PointerIconStyle iconId) override;
void setCustomPointerIcon(const SpriteIcon& icon) override;
- void setSkipScreenshot(int32_t displayId, bool skip) override;
+ void setSkipScreenshot(ui::LogicalDisplayId displayId, bool skip) override;
virtual void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void doInactivityTimeout();
@@ -109,11 +109,11 @@
struct Locked {
Presentation presentation;
- int32_t pointerDisplayId = ADISPLAY_ID_NONE;
+ ui::LogicalDisplayId pointerDisplayId = ui::ADISPLAY_ID_NONE;
std::vector<gui::DisplayInfo> mDisplayInfos;
- std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers;
- std::unordered_set<int32_t /* displayId */> displaysToSkipScreenshot;
+ std::unordered_map<ui::LogicalDisplayId, TouchSpotController> spotControllers;
+ std::unordered_set<ui::LogicalDisplayId> displaysToSkipScreenshot;
} mLocked GUARDED_BY(getLock());
class DisplayInfoListener : public gui::WindowInfosListener {
@@ -132,7 +132,8 @@
sp<DisplayInfoListener> mDisplayInfoListener;
const WindowListenerUnregisterConsumer mUnregisterWindowInfosListener;
- const ui::Transform& getTransformForDisplayLocked(int displayId) const REQUIRES(getLock());
+ const ui::Transform& getTransformForDisplayLocked(ui::LogicalDisplayId displayId) const
+ REQUIRES(getLock());
void clearSpotsLocked() REQUIRES(getLock());
};
@@ -148,7 +149,7 @@
void setPresentation(Presentation) override {
LOG_ALWAYS_FATAL("Should not be called");
}
- void setSpots(const PointerCoords*, const uint32_t*, BitSet32, int32_t) override {
+ void setSpots(const PointerCoords*, const uint32_t*, BitSet32, ui::LogicalDisplayId) override {
LOG_ALWAYS_FATAL("Should not be called");
}
void clearSpots() override {
@@ -176,7 +177,7 @@
FloatPoint getPosition() const override {
LOG_ALWAYS_FATAL("Should not be called");
}
- int32_t getDisplayId() const override {
+ ui::LogicalDisplayId getDisplayId() const override {
LOG_ALWAYS_FATAL("Should not be called");
}
void fade(Transition) override {
@@ -212,7 +213,7 @@
void setPresentation(Presentation) override {
LOG_ALWAYS_FATAL("Should not be called");
}
- void setSpots(const PointerCoords*, const uint32_t*, BitSet32, int32_t) override {
+ void setSpots(const PointerCoords*, const uint32_t*, BitSet32, ui::LogicalDisplayId) override {
LOG_ALWAYS_FATAL("Should not be called");
}
void clearSpots() override {
diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp
index 15c3517..747eb8e 100644
--- a/libs/input/PointerControllerContext.cpp
+++ b/libs/input/PointerControllerContext.cpp
@@ -138,12 +138,12 @@
return 1; // keep the callback
}
-void PointerControllerContext::addAnimationCallback(int32_t displayId,
+void PointerControllerContext::addAnimationCallback(ui::LogicalDisplayId displayId,
std::function<bool(nsecs_t)> callback) {
mAnimator.addCallback(displayId, callback);
}
-void PointerControllerContext::removeAnimationCallback(int32_t displayId) {
+void PointerControllerContext::removeAnimationCallback(ui::LogicalDisplayId displayId) {
mAnimator.removeCallback(displayId);
}
@@ -161,14 +161,14 @@
}
}
-void PointerControllerContext::PointerAnimator::addCallback(int32_t displayId,
+void PointerControllerContext::PointerAnimator::addCallback(ui::LogicalDisplayId displayId,
std::function<bool(nsecs_t)> callback) {
std::scoped_lock lock(mLock);
mLocked.callbacks[displayId] = callback;
startAnimationLocked();
}
-void PointerControllerContext::PointerAnimator::removeCallback(int32_t displayId) {
+void PointerControllerContext::PointerAnimator::removeCallback(ui::LogicalDisplayId displayId) {
std::scoped_lock lock(mLock);
auto it = mLocked.callbacks.find(displayId);
if (it == mLocked.callbacks.end()) {
diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h
index e893c49..d422148 100644
--- a/libs/input/PointerControllerContext.h
+++ b/libs/input/PointerControllerContext.h
@@ -72,12 +72,13 @@
virtual ~PointerControllerPolicyInterface() {}
public:
- virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0;
- virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0;
+ virtual void loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId displayId) = 0;
+ virtual void loadPointerResources(PointerResources* outResources,
+ ui::LogicalDisplayId displayId) = 0;
virtual void loadAdditionalMouseResources(
std::map<PointerIconStyle, SpriteIcon>* outResources,
std::map<PointerIconStyle, PointerAnimation>* outAnimationResources,
- int32_t displayId) = 0;
+ ui::LogicalDisplayId displayId) = 0;
virtual PointerIconStyle getDefaultPointerIconId() = 0;
virtual PointerIconStyle getDefaultStylusIconId() = 0;
virtual PointerIconStyle getCustomPointerIconId() = 0;
@@ -102,7 +103,7 @@
nsecs_t getAnimationTime();
- void clearSpotsByDisplay(int32_t displayId);
+ void clearSpotsByDisplay(ui::LogicalDisplayId displayId);
void setHandlerController(std::shared_ptr<PointerController> controller);
void setCallbackController(std::shared_ptr<PointerController> controller);
@@ -112,8 +113,9 @@
void handleDisplayEvents();
- void addAnimationCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
- void removeAnimationCallback(int32_t displayId);
+ void addAnimationCallback(ui::LogicalDisplayId displayId,
+ std::function<bool(nsecs_t)> callback);
+ void removeAnimationCallback(ui::LogicalDisplayId displayId);
class MessageHandler : public virtual android::MessageHandler {
public:
@@ -136,8 +138,8 @@
public:
PointerAnimator(PointerControllerContext& context);
- void addCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
- void removeCallback(int32_t displayId);
+ void addCallback(ui::LogicalDisplayId displayId, std::function<bool(nsecs_t)> callback);
+ void removeCallback(ui::LogicalDisplayId displayId);
void handleVsyncEvents();
nsecs_t getAnimationTimeLocked();
@@ -148,7 +150,7 @@
bool animationPending{false};
nsecs_t animationTime{systemTime(SYSTEM_TIME_MONOTONIC)};
- std::unordered_map<int32_t, std::function<bool(nsecs_t)>> callbacks;
+ std::unordered_map<ui::LogicalDisplayId, std::function<bool(nsecs_t)>> callbacks;
} mLocked GUARDED_BY(mLock);
DisplayEventReceiver mDisplayEventReceiver;
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 0baa929..af49939 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -19,9 +19,9 @@
#include "SpriteController.h"
-#include <log/log.h>
-#include <utils/String8.h>
+#include <android-base/logging.h>
#include <gui/Surface.h>
+#include <utils/String8.h>
namespace android {
@@ -340,13 +340,14 @@
}
}
-sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height, int32_t displayId,
+sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height,
+ ui::LogicalDisplayId displayId,
bool hideOnMirrored) {
ensureSurfaceComposerClient();
const sp<SurfaceControl> parent = mParentSurfaceProvider(displayId);
if (parent == nullptr) {
- ALOGE("Failed to get the parent surface for pointers on display %d", displayId);
+ LOG(ERROR) << "Failed to get the parent surface for pointers on display " << displayId;
}
int32_t createFlags = ISurfaceComposerClient::eHidden | ISurfaceComposerClient::eCursorWindow;
@@ -475,7 +476,7 @@
}
}
-void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
+void SpriteController::SpriteImpl::setDisplayId(ui::LogicalDisplayId displayId) {
AutoMutex _l(mController.mLock);
if (mLocked.state.displayId != displayId) {
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index fdb15506..070c90c 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -95,7 +95,7 @@
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
/* Sets the id of the display where the sprite should be shown. */
- virtual void setDisplayId(int32_t displayId) = 0;
+ virtual void setDisplayId(ui::LogicalDisplayId displayId) = 0;
/* Sets the flag to hide sprite on mirrored displays.
* This will add ISurfaceComposerClient::eSkipScreenshot flag to the sprite. */
@@ -115,7 +115,7 @@
*/
class SpriteController {
public:
- using ParentSurfaceProvider = std::function<sp<SurfaceControl>(int /*displayId*/)>;
+ using ParentSurfaceProvider = std::function<sp<SurfaceControl>(ui::LogicalDisplayId)>;
SpriteController(const sp<Looper>& looper, int32_t overlayLayer, ParentSurfaceProvider parent);
SpriteController(const SpriteController&) = delete;
SpriteController& operator=(const SpriteController&) = delete;
@@ -174,7 +174,7 @@
int32_t layer{0};
float alpha{1.0f};
SpriteTransformationMatrix transformationMatrix;
- int32_t displayId{ADISPLAY_ID_DEFAULT};
+ ui::LogicalDisplayId displayId{ui::ADISPLAY_ID_DEFAULT};
sp<SurfaceControl> surfaceControl;
int32_t surfaceWidth{0};
@@ -208,7 +208,7 @@
virtual void setLayer(int32_t layer);
virtual void setAlpha(float alpha);
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
- virtual void setDisplayId(int32_t displayId);
+ virtual void setDisplayId(ui::LogicalDisplayId displayId);
virtual void setSkipScreenshot(bool skip);
inline const SpriteState& getStateLocked() const {
@@ -273,7 +273,7 @@
void doDisposeSurfaces();
void ensureSurfaceComposerClient();
- sp<SurfaceControl> obtainSurface(int32_t width, int32_t height, int32_t displayId,
+ sp<SurfaceControl> obtainSurface(int32_t width, int32_t height, ui::LogicalDisplayId displayId,
bool hideOnMirrored);
};
diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp
index 530d541..7462481 100644
--- a/libs/input/TouchSpotController.cpp
+++ b/libs/input/TouchSpotController.cpp
@@ -40,7 +40,7 @@
// --- Spot ---
void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float newX, float newY,
- int32_t displayId, bool skipScreenshot) {
+ ui::LogicalDisplayId displayId, bool skipScreenshot) {
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
sprite->setAlpha(alpha);
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
@@ -69,7 +69,8 @@
// --- TouchSpotController ---
-TouchSpotController::TouchSpotController(int32_t displayId, PointerControllerContext& context)
+TouchSpotController::TouchSpotController(ui::LogicalDisplayId displayId,
+ PointerControllerContext& context)
: mDisplayId(displayId), mContext(context) {
mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
}
@@ -94,7 +95,7 @@
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y),
- c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), mDisplayId);
+ c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), mDisplayId.id);
}
#endif
@@ -274,7 +275,7 @@
out += prefix;
out += "SpotController:\n";
out += prefix;
- StringAppendF(&out, INDENT "DisplayId: %" PRId32 "\n", mDisplayId);
+ StringAppendF(&out, INDENT "DisplayId: %s\n", mDisplayId.toString().c_str());
std::scoped_lock lock(mLock);
out += prefix;
StringAppendF(&out, INDENT "Animating: %s\n", toString(mLocked.animating));
diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h
index 608653c..ac37fa4 100644
--- a/libs/input/TouchSpotController.h
+++ b/libs/input/TouchSpotController.h
@@ -29,7 +29,7 @@
*/
class TouchSpotController {
public:
- TouchSpotController(int32_t displayId, PointerControllerContext& context);
+ TouchSpotController(ui::LogicalDisplayId displayId, PointerControllerContext& context);
~TouchSpotController();
void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
BitSet32 spotIdBits, bool skipScreenshot);
@@ -59,7 +59,7 @@
y(0.0f),
mLastIcon(nullptr) {}
- void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId,
+ void updateSprite(const SpriteIcon* icon, float x, float y, ui::LogicalDisplayId displayId,
bool skipScreenshot);
void dump(std::string& out, const char* prefix = "") const;
@@ -67,7 +67,7 @@
const SpriteIcon* mLastIcon;
};
- int32_t mDisplayId;
+ ui::LogicalDisplayId mDisplayId;
mutable std::mutex mLock;
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 3bc0e24..7a13380 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -52,12 +52,13 @@
class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface {
public:
- virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) override;
- virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) override;
+ virtual void loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId displayId) override;
+ virtual void loadPointerResources(PointerResources* outResources,
+ ui::LogicalDisplayId displayId) override;
virtual void loadAdditionalMouseResources(
std::map<PointerIconStyle, SpriteIcon>* outResources,
std::map<PointerIconStyle, PointerAnimation>* outAnimationResources,
- int32_t displayId) override;
+ ui::LogicalDisplayId displayId) override;
virtual PointerIconStyle getDefaultPointerIconId() override;
virtual PointerIconStyle getDefaultStylusIconId() override;
virtual PointerIconStyle getCustomPointerIconId() override;
@@ -73,13 +74,13 @@
bool additionalMouseResourcesLoaded{false};
};
-void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) {
+void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId) {
loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
pointerIconLoaded = true;
}
void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
- int32_t) {
+ ui::LogicalDisplayId) {
loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
@@ -88,7 +89,7 @@
void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
std::map<PointerIconStyle, SpriteIcon>* outResources,
- std::map<PointerIconStyle, PointerAnimation>* outAnimationResources, int32_t) {
+ std::map<PointerIconStyle, PointerAnimation>* outAnimationResources, ui::LogicalDisplayId) {
SpriteIcon icon;
PointerAnimation anim;
@@ -165,7 +166,7 @@
PointerControllerTest();
~PointerControllerTest();
- void ensureDisplayViewportIsSet(int32_t displayId = ADISPLAY_ID_DEFAULT);
+ void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_DEFAULT);
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
@@ -204,7 +205,7 @@
mThread.join();
}
-void PointerControllerTest::ensureDisplayViewportIsSet(int32_t displayId) {
+void PointerControllerTest::ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId) {
DisplayViewport viewport;
viewport.displayId = displayId;
viewport.logicalRight = 1600;
@@ -334,23 +335,23 @@
// Update spots to sync state with sprite
mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
- ADISPLAY_ID_DEFAULT);
+ ui::ADISPLAY_ID_DEFAULT);
testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
// Marking the display to skip screenshot should update sprite as well
- mPointerController->setSkipScreenshot(ADISPLAY_ID_DEFAULT, true);
+ mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, true);
EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(true));
// Update spots to sync state with sprite
mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
- ADISPLAY_ID_DEFAULT);
+ ui::ADISPLAY_ID_DEFAULT);
testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
// Reset flag and verify again
- mPointerController->setSkipScreenshot(ADISPLAY_ID_DEFAULT, false);
+ mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, false);
EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
- ADISPLAY_ID_DEFAULT);
+ ui::ADISPLAY_ID_DEFAULT);
testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
}
diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h
index 0867221..21628fb 100644
--- a/libs/input/tests/mocks/MockSprite.h
+++ b/libs/input/tests/mocks/MockSprite.h
@@ -33,7 +33,7 @@
MOCK_METHOD(void, setLayer, (int32_t), (override));
MOCK_METHOD(void, setAlpha, (float), (override));
MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override));
- MOCK_METHOD(void, setDisplayId, (int32_t), (override));
+ MOCK_METHOD(void, setDisplayId, (ui::LogicalDisplayId), (override));
MOCK_METHOD(void, setSkipScreenshot, (bool), (override));
};
diff --git a/libs/input/tests/mocks/MockSpriteController.h b/libs/input/tests/mocks/MockSpriteController.h
index 62f1d65..9ef6b7c 100644
--- a/libs/input/tests/mocks/MockSpriteController.h
+++ b/libs/input/tests/mocks/MockSpriteController.h
@@ -27,7 +27,7 @@
public:
MockSpriteController(sp<Looper> looper)
- : SpriteController(looper, 0, [](int) { return nullptr; }) {}
+ : SpriteController(looper, 0, [](ui::LogicalDisplayId) { return nullptr; }) {}
~MockSpriteController() {}
MOCK_METHOD(sp<Sprite>, createSprite, (), (override));
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 bca8fde..30b6c6c 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
@@ -36,6 +36,7 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.displayCutoutPadding
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -68,6 +69,8 @@
import com.android.compose.modifiers.thenIf
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
+import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
@@ -152,6 +155,8 @@
modifier: Modifier = Modifier,
shadeSession: SaveableSession,
) {
+ val cutoutLocation = LocalDisplayCutout.current.location
+
val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
val contentAlpha by
animateFloatAsState(
@@ -183,6 +188,9 @@
// scene (and not the one under it) during a scene transition.
Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
}
+ .thenIf(cutoutLocation != CutoutLocation.CENTER) {
+ Modifier.displayCutoutPadding()
+ },
) {
val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
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 36b60d6..10fe0cab 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
@@ -31,6 +31,7 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.displayCutoutPadding
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -67,6 +68,8 @@
import com.android.compose.modifiers.padding
import com.android.compose.modifiers.thenIf
import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
+import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.controls.ui.composable.MediaCarousel
@@ -208,6 +211,8 @@
modifier: Modifier = Modifier,
shadeSession: SaveableSession,
) {
+ val cutoutLocation = LocalDisplayCutout.current.location
+
val maxNotifScrimTop = remember { mutableStateOf(0f) }
val tileSquishiness by
animateSceneFloatAsState(
@@ -243,9 +248,15 @@
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier =
- Modifier.fillMaxWidth().thenIf(isClickable) {
- Modifier.clickable(onClick = { viewModel.onContentClicked() })
- }
+ Modifier.fillMaxWidth()
+ .thenIf(isClickable) {
+ Modifier.clickable(
+ onClick = { viewModel.onContentClicked() }
+ )
+ }
+ .thenIf(cutoutLocation != CutoutLocation.CENTER) {
+ Modifier.displayCutoutPadding()
+ },
) {
CollapsedShadeHeader(
viewModel = viewModel.shadeHeaderViewModel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 21dc953..f06e04b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -33,7 +33,10 @@
import com.android.systemui.flags.parameterizeSceneContainerFlag
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -69,7 +72,7 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
-
+ private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val mockDarkAnimator = mock<ObjectAnimator>()
private lateinit var underTest: StatusBarStateControllerImpl
@@ -98,6 +101,7 @@
uiEventLogger,
{ kosmos.interactionJankMonitor },
JavaAdapter(testScope.backgroundScope),
+ { kosmos.keyguardTransitionInteractor },
{ kosmos.shadeInteractor },
{ kosmos.deviceUnlockedInteractor },
{ kosmos.sceneInteractor },
@@ -330,4 +334,25 @@
assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)
}
+
+ @Test
+ fun leaveOpenOnKeyguard_whenGone_isFalse() =
+ testScope.runTest {
+ underTest.start()
+ underTest.setLeaveOpenOnKeyguardHide(true)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.LOCKSCREEN,
+ testScope = testScope,
+ )
+ assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(true)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope = testScope,
+ )
+ assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(false)
+ }
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a1daebd..5857692 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -285,6 +285,9 @@
the amount by the view is positioned above the screen before the animation starts. -->
<dimen name="heads_up_appear_y_above_screen">32dp</dimen>
+ <!-- padding between the old and new heads up notifications for the hun cycling animation -->
+ <dimen name="heads_up_cycling_padding">8dp</dimen>
+
<!-- padding between the heads up and the statusbar -->
<dimen name="heads_up_status_bar_padding">8dp</dimen>
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
index 422f02f..8979ef1 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
@@ -16,7 +16,6 @@
package com.android.systemui.biometrics
import android.Manifest
-import android.annotation.IntDef
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
@@ -39,14 +38,9 @@
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import com.android.internal.widget.LockPatternUtils
-import java.lang.annotation.Retention
-import java.lang.annotation.RetentionPolicy
+import com.android.systemui.biometrics.shared.model.PromptKind
object Utils {
- const val CREDENTIAL_PIN = 1
- const val CREDENTIAL_PATTERN = 2
- const val CREDENTIAL_PASSWORD = 3
-
/** Base set of layout flags for fingerprint overlay widgets. */
const val FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
@@ -91,17 +85,16 @@
(promptInfo.authenticators and Authenticators.BIOMETRIC_WEAK) != 0
@JvmStatic
- @CredentialType
- fun getCredentialType(utils: LockPatternUtils, userId: Int): Int =
+ fun getCredentialType(utils: LockPatternUtils, userId: Int): PromptKind =
when (utils.getKeyguardStoredPasswordQuality(userId)) {
- PASSWORD_QUALITY_SOMETHING -> CREDENTIAL_PATTERN
+ PASSWORD_QUALITY_SOMETHING -> PromptKind.Pattern
PASSWORD_QUALITY_NUMERIC,
- PASSWORD_QUALITY_NUMERIC_COMPLEX -> CREDENTIAL_PIN
+ PASSWORD_QUALITY_NUMERIC_COMPLEX -> PromptKind.Pin
PASSWORD_QUALITY_ALPHABETIC,
PASSWORD_QUALITY_ALPHANUMERIC,
PASSWORD_QUALITY_COMPLEX,
- PASSWORD_QUALITY_MANAGED -> CREDENTIAL_PASSWORD
- else -> CREDENTIAL_PASSWORD
+ PASSWORD_QUALITY_MANAGED -> PromptKind.Password
+ else -> PromptKind.Password
}
@JvmStatic
@@ -129,8 +122,4 @@
return windowMetrics?.windowInsets?.getInsets(WindowInsets.Type.navigationBars())
?: Insets.NONE
}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD)
- annotation class CredentialType
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
similarity index 69%
rename from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
index a97e2dc..8782962 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -16,16 +16,20 @@
package com.android.systemui.biometrics.shared.model
-import com.android.systemui.biometrics.Utils
-
-// TODO(b/251476085): this should eventually replace Utils.CredentialType
-/** Credential options for biometric prompt. Shadows [Utils.CredentialType]. */
sealed interface PromptKind {
+ object None : PromptKind
+
data class Biometric(
val activeModalities: BiometricModalities = BiometricModalities(),
+ // TODO(b/330908557): Use this value to decide whether to show two pane layout, instead of
+ // simply depending on rotations.
+ val showTwoPane: Boolean = false
) : PromptKind
object Pin : PromptKind
object Pattern : PromptKind
object Password : PromptKind
+
+ fun isBiometric() = this is Biometric
+ fun isCredential() = (this is Pin) or (this is Pattern) or (this is Password)
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 460779c..f33acf2 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -43,6 +43,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -432,6 +433,7 @@
listenForDozeAmountTransition(this)
listenForAnyStateToAodTransition(this)
listenForAnyStateToLockscreenTransition(this)
+ listenForAnyStateToDozingTransition(this)
} else {
listenForDozeAmount(this)
}
@@ -578,6 +580,21 @@
}
}
+ /**
+ * When keyguard is displayed due to pulsing notifications when AOD is off,
+ * we should make sure clock is in dozing state instead of LS state
+ */
+ @VisibleForTesting
+ internal fun listenForAnyStateToDozingTransition(scope: CoroutineScope): Job {
+ return scope.launch {
+ keyguardTransitionInteractor
+ .transitionStepsToState(DOZING)
+ .filter { it.transitionState == TransitionState.FINISHED }
+ .collect { handleDoze(1f) }
+ }
+ }
+
+
@VisibleForTesting
internal fun listenForDozing(scope: CoroutineScope): Job {
return scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 5ba0b2d..9ba41ef 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -76,6 +76,7 @@
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
import com.android.systemui.biometrics.shared.model.BiometricModalities;
+import com.android.systemui.biometrics.shared.model.PromptKind;
import com.android.systemui.biometrics.ui.BiometricPromptLayout;
import com.android.systemui.biometrics.ui.CredentialView;
import com.android.systemui.biometrics.ui.binder.BiometricViewBinder;
@@ -500,24 +501,18 @@
private void addCredentialView(boolean animatePanel, boolean animateContents) {
final LayoutInflater factory = LayoutInflater.from(mContext);
- @Utils.CredentialType final int credentialType = Utils.getCredentialType(
- mLockPatternUtils, mEffectiveUserId);
-
- switch (credentialType) {
- case Utils.CREDENTIAL_PATTERN:
- mCredentialView = factory.inflate(
- R.layout.auth_credential_pattern_view, null, false);
- break;
- case Utils.CREDENTIAL_PIN:
- mCredentialView = factory.inflate(R.layout.auth_credential_pin_view, null, false);
- break;
- case Utils.CREDENTIAL_PASSWORD:
- mCredentialView = factory.inflate(
- R.layout.auth_credential_password_view, null, false);
- break;
- default:
- throw new IllegalStateException("Unknown credential type: " + credentialType);
+ PromptKind credentialType = Utils.getCredentialType(mLockPatternUtils, mEffectiveUserId);
+ final int layoutResourceId;
+ if (credentialType instanceof PromptKind.Pattern) {
+ layoutResourceId = R.layout.auth_credential_pattern_view;
+ } else if (credentialType instanceof PromptKind.Pin) {
+ layoutResourceId = R.layout.auth_credential_pin_view;
+ } else if (credentialType instanceof PromptKind.Password) {
+ layoutResourceId = R.layout.auth_credential_password_view;
+ } else {
+ throw new IllegalStateException("Unknown credential type: " + credentialType);
}
+ mCredentialView = factory.inflate(layoutResourceId, null, false);
// The background is used for detecting taps / cancelling authentication. Since the
// credential view is full-screen and should not be canceled from background taps,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
index 9ad3f43..f659ff0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
@@ -125,7 +125,7 @@
private val _userId: MutableStateFlow<Int?> = MutableStateFlow(null)
override val userId = _userId.asStateFlow()
- private val _kind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.Biometric())
+ private val _kind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None)
override val kind = _kind.asStateFlow()
private val _opPackageName: MutableStateFlow<String?> = MutableStateFlow(null)
@@ -149,7 +149,7 @@
override val showBpWithoutIconForCredential = _showBpWithoutIconForCredential.asStateFlow()
override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) {
- val hasCredentialViewShown = kind.value !is PromptKind.Biometric
+ val hasCredentialViewShown = kind.value.isCredential()
val showBpForCredential =
Flags.customBiometricPrompt() &&
constraintBp() &&
@@ -178,7 +178,7 @@
_promptInfo.value = null
_userId.value = null
_challenge.value = null
- _kind.value = PromptKind.Biometric()
+ _kind.value = PromptKind.None
_opPackageName.value = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
index b7c0fa8..f8fb7bb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
@@ -16,10 +16,8 @@
package com.android.systemui.biometrics.domain.interactor
-import android.hardware.biometrics.PromptInfo
import com.android.internal.widget.LockPatternView
import com.android.internal.widget.LockscreenCredential
-import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.data.repository.PromptRepository
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
@@ -42,12 +40,6 @@
* Business logic for BiometricPrompt's CredentialViews, which primarily includes checking a users
* PIN, pattern, or password credential instead of a biometric.
*
- * This is used to cache the calling app's options that were given to the underlying authenticate
- * APIs and should be set before any UI is shown to the user.
- *
- * There can be at most one request active at a given time. Use [resetPrompt] when no request is
- * active to clear the cache.
- *
* Views that use any biometric should use [PromptSelectorInteractor] instead.
*/
class PromptCredentialInteractor
@@ -137,28 +129,6 @@
private val _verificationError = MutableStateFlow<CredentialStatus.Fail?>(null)
val verificationError: Flow<CredentialStatus.Fail?> = _verificationError.asStateFlow()
- /** Update the current request to use credential-based authentication instead of biometrics. */
- fun useCredentialsForAuthentication(
- promptInfo: PromptInfo,
- @Utils.CredentialType kind: Int,
- userId: Int,
- challenge: Long,
- opPackageName: String,
- ) {
- biometricPromptRepository.setPrompt(
- promptInfo,
- userId,
- challenge,
- kind.asBiometricPromptCredential(),
- opPackageName,
- )
- }
-
- /** Unset the current authentication request. */
- fun resetPrompt() {
- biometricPromptRepository.unsetPrompt()
- }
-
/**
* Check a credential and return the attestation token (HAT) if successful.
*
@@ -231,13 +201,3 @@
_verificationError.value = null
}
}
-
-// TODO(b/251476085): remove along with Utils.CredentialType
-/** Convert a [Utils.CredentialType] to the corresponding [PromptKind]. */
-private fun @receiver:Utils.CredentialType Int.asBiometricPromptCredential(): PromptKind =
- when (this) {
- Utils.CREDENTIAL_PIN -> PromptKind.Pin
- Utils.CREDENTIAL_PASSWORD -> PromptKind.Password
- Utils.CREDENTIAL_PATTERN -> PromptKind.Pattern
- else -> PromptKind.Biometric()
- }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index 45816c1..deb47d3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -18,7 +18,6 @@
import android.hardware.biometrics.PromptInfo
import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.Utils.getCredentialType
import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
@@ -95,7 +94,7 @@
/** Use credential-based authentication instead of biometrics. */
fun useCredentialsForAuthentication(
promptInfo: PromptInfo,
- @Utils.CredentialType kind: Int,
+ kind: PromptKind,
userId: Int,
challenge: Long,
opPackageName: String,
@@ -152,14 +151,7 @@
override val credentialKind: Flow<PromptKind> =
combine(prompt, isCredentialAllowed) { prompt, isAllowed ->
if (prompt != null && isAllowed) {
- when (
- getCredentialType(lockPatternUtils, prompt.userInfo.deviceCredentialOwnerId)
- ) {
- Utils.CREDENTIAL_PIN -> PromptKind.Pin
- Utils.CREDENTIAL_PASSWORD -> PromptKind.Password
- Utils.CREDENTIAL_PATTERN -> PromptKind.Pattern
- else -> PromptKind.Biometric()
- }
+ getCredentialType(lockPatternUtils, prompt.userInfo.deviceCredentialOwnerId)
} else {
PromptKind.Biometric()
}
@@ -191,7 +183,7 @@
override fun useCredentialsForAuthentication(
promptInfo: PromptInfo,
- @Utils.CredentialType kind: Int,
+ kind: PromptKind,
userId: Int,
challenge: Long,
opPackageName: String,
@@ -200,7 +192,7 @@
promptInfo = promptInfo,
userId = userId,
gatekeeperChallenge = challenge,
- kind = kind.asBiometricPromptCredential(),
+ kind = kind,
opPackageName = opPackageName,
)
}
@@ -209,13 +201,3 @@
promptRepository.unsetPrompt()
}
}
-
-// TODO(b/251476085): remove along with Utils.CredentialType
-/** Convert a [Utils.CredentialType] to the corresponding [PromptKind]. */
-private fun @receiver:Utils.CredentialType Int.asBiometricPromptCredential(): PromptKind =
- when (this) {
- Utils.CREDENTIAL_PIN -> PromptKind.Pin
- Utils.CREDENTIAL_PASSWORD -> PromptKind.Password
- Utils.CREDENTIAL_PATTERN -> PromptKind.Pattern
- else -> PromptKind.Biometric()
- }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 933065b..295b293 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -442,7 +442,7 @@
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.GET_SHARED_LIBRARY_FILES));
int resId = resources.getIdentifier(
- "gesture_blocking_activities", "array", recentsPackageName);
+ "back_gesture_blocking_activities", "array", recentsPackageName);
if (resId == 0) {
Log.e(TAG, "No resource found for gesture-blocking activities");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 6fb5174..5720f76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -125,7 +125,10 @@
public void setNumPages(int numPages) {
setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
- if (numPages == getChildCount()) {
+ int childCount = getChildCount();
+ // We're checking if the width needs to be updated as it's possible that the number of pages
+ // was changed while the page indicator was not visible, automatically skipping onMeasure.
+ if (numPages == childCount && calculateWidth(childCount) == getMeasuredWidth()) {
return;
}
if (mAnimating) {
@@ -295,6 +298,10 @@
}
}
+ private int calculateWidth(int numPages) {
+ return (mPageIndicatorWidth - mPageDotWidth) * (numPages - 1) + mPageDotWidth;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int N = getChildCount();
@@ -309,7 +316,7 @@
for (int i = 0; i < N; i++) {
getChildAt(i).measure(widthChildSpec, heightChildSpec);
}
- int width = (mPageIndicatorWidth - mPageDotWidth) * (N - 1) + mPageDotWidth;
+ int width = calculateWidth(N);
setMeasuredDimension(width, mPageIndicatorHeight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
index 6539cf3..86cc6f5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
@@ -23,10 +23,12 @@
import androidx.compose.animation.graphics.res.animatedVectorResource
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
import androidx.compose.animation.graphics.vector.AnimatedImageVector
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
@@ -71,7 +73,7 @@
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.unit.dp
-import com.android.compose.modifiers.background
+import com.android.compose.animation.Expandable
import com.android.compose.theme.colorAttr
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
@@ -134,7 +136,7 @@
}
}
- @OptIn(ExperimentalCoroutinesApi::class)
+ @OptIn(ExperimentalCoroutinesApi::class, ExperimentalFoundationApi::class)
@Composable
private fun Tile(
tile: TileViewModel,
@@ -147,28 +149,39 @@
.collectAsState(initial = tile.currentState.toUiState())
val context = LocalContext.current
- Row(
- modifier = modifier.clickable { tile.onClick(null) }.tileModifier(state.colors),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = tileHorizontalArrangement(iconOnly)
+ Expandable(
+ color = colorAttr(state.colors.background),
+ shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius)),
) {
- val icon =
- remember(state.icon) {
- state.icon.get().let {
- if (it is QSTileImpl.ResourceIcon) {
- Icon.Resource(it.resId, null)
- } else {
- Icon.Loaded(it.getDrawable(context), null)
+ Row(
+ modifier =
+ modifier
+ .combinedClickable(
+ onClick = { tile.onClick(it) },
+ onLongClick = { tile.onLongClick(it) }
+ )
+ .tileModifier(state.colors),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = tileHorizontalArrangement(iconOnly),
+ ) {
+ val icon =
+ remember(state.icon) {
+ state.icon.get().let {
+ if (it is QSTileImpl.ResourceIcon) {
+ Icon.Resource(it.resId, null)
+ } else {
+ Icon.Loaded(it.getDrawable(context), null)
+ }
}
}
- }
- TileContent(
- label = state.label.toString(),
- secondaryLabel = state.secondaryLabel.toString(),
- icon = icon,
- colors = state.colors,
- iconOnly = iconOnly
- )
+ TileContent(
+ label = state.label.toString(),
+ secondaryLabel = state.secondaryLabel?.toString(),
+ icon = icon,
+ colors = state.colors,
+ iconOnly = iconOnly
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 259a8bf..b971781 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -56,9 +56,8 @@
}
// TODO(b/298525212): remove once Compose exposes window inset bounds.
- override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets? {
- val insets = super.onApplyWindowInsets(windowInsets)
- this.windowInsets.value = insets
- return insets
+ override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets {
+ this.windowInsets.value = windowInsets
+ return windowInsets
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 70632d5..79218ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -18,6 +18,7 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_TO_AOD;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE;
import static com.android.systemui.util.kotlin.JavaAdapterKt.combineFlows;
import android.animation.Animator;
@@ -49,6 +50,7 @@
import com.android.systemui.deviceentry.shared.model.DeviceUnlockStatus;
import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.res.R;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
@@ -108,6 +110,7 @@
private final UiEventLogger mUiEventLogger;
private final Lazy<InteractionJankMonitor> mInteractionJankMonitorLazy;
private final JavaAdapter mJavaAdapter;
+ private final Lazy<KeyguardTransitionInteractor> mKeyguardTransitionInteractorLazy;
private final Lazy<ShadeInteractor> mShadeInteractorLazy;
private final Lazy<DeviceUnlockedInteractor> mDeviceUnlockedInteractorLazy;
private final Lazy<SceneInteractor> mSceneInteractorLazy;
@@ -175,6 +178,7 @@
UiEventLogger uiEventLogger,
Lazy<InteractionJankMonitor> interactionJankMonitorLazy,
JavaAdapter javaAdapter,
+ Lazy<KeyguardTransitionInteractor> keyguardTransitionInteractor,
Lazy<ShadeInteractor> shadeInteractorLazy,
Lazy<DeviceUnlockedInteractor> deviceUnlockedInteractorLazy,
Lazy<SceneInteractor> sceneInteractorLazy,
@@ -182,6 +186,7 @@
mUiEventLogger = uiEventLogger;
mInteractionJankMonitorLazy = interactionJankMonitorLazy;
mJavaAdapter = javaAdapter;
+ mKeyguardTransitionInteractorLazy = keyguardTransitionInteractor;
mShadeInteractorLazy = shadeInteractorLazy;
mDeviceUnlockedInteractorLazy = deviceUnlockedInteractorLazy;
mSceneInteractorLazy = sceneInteractorLazy;
@@ -193,6 +198,14 @@
@Override
public void start() {
+ mJavaAdapter.alwaysCollectFlow(
+ mKeyguardTransitionInteractorLazy.get().isFinishedInState(GONE),
+ (Boolean isFinishedInState) -> {
+ if (isFinishedInState) {
+ setLeaveOpenOnKeyguardHide(false);
+ }
+ });
+
mJavaAdapter.alwaysCollectFlow(mShadeInteractorLazy.get().isAnyExpanded(),
this::onShadeOrQsExpanded);
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 6a38f8d..d2d0aaa 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
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.notification.row;
import static com.android.systemui.Flags.notificationBackgroundTintOptimization;
+import static com.android.systemui.statusbar.notification.row.ExpandableView.ClipSide.BOTTOM;
+import static com.android.systemui.statusbar.notification.row.ExpandableView.ClipSide.TOP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -43,6 +45,7 @@
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.SourceType;
+import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -354,12 +357,13 @@
@Override
public long performRemoveAnimation(long duration, long delay, float translationDirection,
boolean isHeadsUpAnimation, Runnable onStartedRunnable, Runnable onFinishedRunnable,
- AnimatorListenerAdapter animationListener) {
+ AnimatorListenerAdapter animationListener, ClipSide clipSide) {
enableAppearDrawing(true);
mIsHeadsUpAnimation = isHeadsUpAnimation;
if (mDrawingAppearAnimation) {
startAppearAnimation(false /* isAppearing */, translationDirection,
- delay, duration, onStartedRunnable, onFinishedRunnable, animationListener);
+ delay, duration, onStartedRunnable, onFinishedRunnable, animationListener,
+ clipSide);
} else {
if (onStartedRunnable != null) {
onStartedRunnable.run();
@@ -378,13 +382,13 @@
mIsHeadsUpAnimation = isHeadsUpAppear;
if (mDrawingAppearAnimation) {
startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay,
- duration, null, null, null);
+ duration, null, null, null, ClipSide.BOTTOM);
}
}
private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
long duration, final Runnable onStartedRunnable, final Runnable onFinishedRunnable,
- AnimatorListenerAdapter animationListener) {
+ AnimatorListenerAdapter animationListener, ClipSide clipSide) {
mAnimationTranslationY = translationDirection * getActualHeight();
cancelAppearAnimation();
if (mAppearAnimationFraction == -1.0f) {
@@ -406,9 +410,16 @@
mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE;
targetValue = 0.0f;
}
+
+ if (NotificationHeadsUpCycling.isEnabled()) {
+ // TODO(b/316404716): add avalanche filtering
+ mCurrentAppearInterpolator = Interpolators.LINEAR;
+ }
+
mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
targetValue);
- if (NotificationsImprovedHunAnimation.isEnabled()) {
+ if (NotificationsImprovedHunAnimation.isEnabled()
+ || NotificationHeadsUpCycling.isEnabled()) {
mAppearAnimator.setInterpolator(mCurrentAppearInterpolator);
} else {
mAppearAnimator.setInterpolator(Interpolators.LINEAR);
@@ -418,7 +429,12 @@
mAppearAnimator.addUpdateListener(animation -> {
mAppearAnimationFraction = (float) animation.getAnimatedValue();
updateAppearAnimationAlpha();
- updateAppearRect();
+ if (NotificationHeadsUpCycling.isEnabled()) {
+ // For cycling out, we want the HUN to be clipped from the top.
+ updateAppearRect(clipSide);
+ } else {
+ updateAppearRect();
+ }
invalidate();
});
if (animationListener != null) {
@@ -426,7 +442,11 @@
}
// we need to apply the initial state already to avoid drawn frames in the wrong state
updateAppearAnimationAlpha();
- updateAppearRect();
+ if (NotificationHeadsUpCycling.isEnabled()) {
+ updateAppearRect(clipSide);
+ } else {
+ updateAppearRect();
+ }
mAppearAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mRunWithoutInterruptions;
@@ -508,14 +528,18 @@
enableAppearDrawing(false);
}
- private void updateAppearRect() {
+ /**
+ * Update the View's Rect clipping to fit the appear animation
+ * @param clipSide Which side if view we want to clip from
+ */
+ private void updateAppearRect(ClipSide clipSide) {
float interpolatedFraction =
- NotificationsImprovedHunAnimation.isEnabled() ? mAppearAnimationFraction
+ NotificationsImprovedHunAnimation.isEnabled()
+ || NotificationHeadsUpCycling.isEnabled() ? mAppearAnimationFraction
: mCurrentAppearInterpolator.getInterpolation(mAppearAnimationFraction);
mAppearAnimationTranslation = (1.0f - interpolatedFraction) * mAnimationTranslationY;
- final int actualHeight = getActualHeight();
- float bottom = actualHeight * interpolatedFraction;
-
+ final int fullHeight = getActualHeight();
+ float height = fullHeight * interpolatedFraction;
if (mTargetPoint != null) {
int width = getWidth();
float fraction = 1 - mAppearAnimationFraction;
@@ -524,13 +548,26 @@
mAnimationTranslationY
+ (mAnimationTranslationY - mTargetPoint.y) * fraction,
width - (width - mTargetPoint.x) * fraction,
- actualHeight - (actualHeight - mTargetPoint.y) * fraction);
+ fullHeight - (fullHeight - mTargetPoint.y) * fraction);
} else {
- setOutlineRect(0, mAppearAnimationTranslation, getWidth(),
- bottom + mAppearAnimationTranslation);
+ if (clipSide == TOP) {
+ setOutlineRect(
+ 0,
+ /* top= */ fullHeight - height,
+ getWidth(),
+ /* bottom= */ fullHeight
+ );
+ } else if (clipSide == BOTTOM) {
+ setOutlineRect(0, mAppearAnimationTranslation, getWidth(),
+ height + mAppearAnimationTranslation);
+ }
}
}
+ private void updateAppearRect() {
+ updateAppearRect(ClipSide.BOTTOM);
+ }
+
private float getInterpolatedAppearAnimationFraction() {
if (mAppearAnimationFraction >= 0) {
@@ -540,11 +577,36 @@
}
private void updateAppearAnimationAlpha() {
- float contentAlphaProgress = MathUtils.constrain(mAppearAnimationFraction,
- ALPHA_APPEAR_START_FRACTION, ALPHA_APPEAR_END_FRACTION);
- float range = ALPHA_APPEAR_END_FRACTION - ALPHA_APPEAR_START_FRACTION;
- float alpha = (contentAlphaProgress - ALPHA_APPEAR_START_FRACTION) / range;
- setContentAlpha(Interpolators.ALPHA_IN.getInterpolation(alpha));
+ updateAppearAnimationContentAlpha(
+ mAppearAnimationFraction,
+ ALPHA_APPEAR_START_FRACTION,
+ ALPHA_APPEAR_END_FRACTION,
+ Interpolators.ALPHA_IN
+ );
+ }
+
+ /**
+ * Update the alpha value of the content view during the appear animation. We suppose that the
+ * content alpha changes from 0 to 1 during some part of the appear animation.
+ * @param appearFraction the current appearFraction, should be in the range of [0, 1], where
+ * 1 represents fully appeared
+ * @param startFraction the appear fraction when the content view should be
+ * * fully transparent
+ * @param endFraction the appear fraction when the content view should be
+ * fully in-transparent, should be greater or equals to startFraction
+ * @param interpolator the interpolator to update the alpha
+ */
+ private void updateAppearAnimationContentAlpha(
+ float appearFraction,
+ float startFraction,
+ float endFraction,
+ Interpolator interpolator
+ ) {
+ float contentAlphaProgress = MathUtils.constrain(appearFraction, startFraction,
+ endFraction);
+ float range = endFraction - startFraction;
+ float alpha = (contentAlphaProgress - startFraction) / range;
+ setContentAlpha(interpolator.getInterpolation(alpha));
}
private void setContentAlpha(float contentAlpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 23c0a0d..747cb3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3076,7 +3076,7 @@
boolean isHeadsUpAnimation,
Runnable onStartedRunnable,
Runnable onFinishedRunnable,
- AnimatorListenerAdapter animationListener) {
+ AnimatorListenerAdapter animationListener, ClipSide clipSide) {
if (mMenuRow != null && mMenuRow.isMenuVisible()) {
Animator anim = getTranslateViewAnimator(0f, null /* listener */);
if (anim != null) {
@@ -3092,7 +3092,7 @@
public void onAnimationEnd(Animator animation) {
ExpandableNotificationRow.super.performRemoveAnimation(
duration, delay, translationDirection, isHeadsUpAnimation,
- null, onFinishedRunnable, animationListener);
+ null, onFinishedRunnable, animationListener, ClipSide.BOTTOM);
}
});
anim.start();
@@ -3100,7 +3100,8 @@
}
}
return super.performRemoveAnimation(duration, delay, translationDirection,
- isHeadsUpAnimation, onStartedRunnable, onFinishedRunnable, animationListener);
+ isHeadsUpAnimation, onStartedRunnable, onFinishedRunnable, animationListener,
+ clipSide);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 05e8717..2af119f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -362,17 +362,17 @@
/**
* Perform a remove animation on this view.
- * @param duration The duration of the remove animation.
- * @param delay The delay of the animation
+ *
+ * @param duration The duration of the remove animation.
+ * @param delay The delay of the animation
* @param translationDirection The direction value from [-1 ... 1] indicating in which the
* animation should be performed. A value of -1 means that The
* remove animation should be performed upwards,
* such that the child appears to be going away to the top. 1
* Should mean the opposite.
- * @param isHeadsUpAnimation Is this a headsUp animation.
- * @param onFinishedRunnable A runnable which should be run when the animation is finished.
- * @param animationListener An animation listener to add to the animation.
- *
+ * @param isHeadsUpAnimation Is this a headsUp animation.
+ * @param onFinishedRunnable A runnable which should be run when the animation is finished.
+ * @param animationListener An animation listener to add to the animation.
* @return The additional delay, in milliseconds, that this view needs to add before the
* animation starts.
*/
@@ -380,7 +380,12 @@
long delay, float translationDirection, boolean isHeadsUpAnimation,
Runnable onStartedRunnable,
Runnable onFinishedRunnable,
- AnimatorListenerAdapter animationListener);
+ AnimatorListenerAdapter animationListener, ClipSide clipSide);
+
+ public enum ClipSide {
+ TOP,
+ BOTTOM
+ }
public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
performAddAnimation(delay, duration, isHeadsUpAppear, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 162e8af..291dc13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -252,7 +252,7 @@
float translationDirection, boolean isHeadsUpAnimation,
Runnable onStartedRunnable,
Runnable onFinishedRunnable,
- AnimatorListenerAdapter animationListener) {
+ AnimatorListenerAdapter animationListener, ClipSide clipSide) {
// TODO: Use duration
if (onStartedRunnable != null) {
onStartedRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
index 0344b32..d4f8ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
@@ -33,7 +33,12 @@
/** Is the heads-up cycling animation enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.notificationContentAlphaOptimization()
+ get() = Flags.notificationHeadsUpCycling()
+
+ /** Whether to animate the bottom line when transiting from a tall HUN to a short HUN */
+ @JvmStatic
+ inline val animateTallToShort
+ get() = false
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index e520957..5f4e832 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -293,6 +293,8 @@
}
String getAvalancheShowingHunKey() {
+ // If we don't have a previous showing hun, we don't consider the showing hun as avalanche
+ if (isNullAvalancheKey(getAvalanchePreviousHunKey())) return "";
return mAvalancheController.getShowingHunKey();
}
@@ -300,6 +302,11 @@
return mAvalancheController.getPreviousHunKey();
}
+ boolean isNullAvalancheKey(String key) {
+ if (key == null || key.isEmpty()) return true;
+ return key.equals("HeadsUpEntry null") || key.equals("HeadsUpEntry.mEntry null");
+ }
+
void setOverExpansion(float overExpansion) {
mOverExpansion = overExpansion;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
index 5551ab4..bd7bd59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
@@ -70,13 +70,14 @@
}
override fun performRemoveAnimation(
- duration: Long,
- delay: Long,
- translationDirection: Float,
- isHeadsUpAnimation: Boolean,
- onStartedRunnable: Runnable?,
- onFinishedRunnable: Runnable?,
- animationListener: AnimatorListenerAdapter?
+ duration: Long,
+ delay: Long,
+ translationDirection: Float,
+ isHeadsUpAnimation: Boolean,
+ onStartedRunnable: Runnable?,
+ onFinishedRunnable: Runnable?,
+ animationListener: AnimatorListenerAdapter?,
+ clipSide: ClipSide
): Long {
return 0
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 232b4e9..bfc7425 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -112,6 +112,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor;
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation;
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
@@ -151,7 +152,6 @@
public class NotificationStackScrollLayout
extends ViewGroup
implements Dumpable, NotificationScrollView {
-
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
private static final boolean SPEW = Log.isLoggable(TAG, Log.VERBOSE);
@@ -3144,6 +3144,11 @@
type = row.wasJustClicked()
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
: AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+ if (NotificationHeadsUpCycling.isEnabled()) {
+ if (mStackScrollAlgorithm.isCyclingOut(row, mAmbientState)) {
+ type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_CYCLING_OUT;
+ }
+ }
if (row.isChildInGroup()) {
// We can otherwise get stuck in there if it was just isolated
row.setHeadsUpAnimatingAway(false);
@@ -3164,6 +3169,11 @@
if (pinnedAndClosed || shouldHunAppearFromTheBottom) {
// Our custom add animation
type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
+ if (NotificationHeadsUpCycling.isEnabled()) {
+ if (mStackScrollAlgorithm.isCyclingIn(row, mAmbientState)) {
+ type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_CYCLING_IN;
+ }
+ }
} else {
// Normal add animation
type = AnimationEvent.ANIMATION_TYPE_ADD;
@@ -6135,6 +6145,22 @@
.animateTopInset()
.animateY()
.animateZ(),
+
+ // ANIMATION_TYPE_HEADS_UP_CYCLING_OUT
+ new AnimationFilter()
+ .animateHeight()
+ .animateTopInset()
+ .animateY()
+ .animateZ()
+ .hasDelays(),
+
+ // ANIMATION_TYPE_HEADS_UP_CYCLING_IN
+ new AnimationFilter()
+ .animateHeight()
+ .animateTopInset()
+ .animateY()
+ .animateZ()
+ .hasDelays(),
};
static int[] LENGTHS = new int[]{
@@ -6186,6 +6212,12 @@
// ANIMATION_TYPE_EVERYTHING
StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_HEADS_UP_CYCLING_OUT
+ StackStateAnimator.ANIMATION_DURATION_HEADS_UP_CYCLING,
+
+ // ANIMATION_TYPE_HEADS_UP_CYCLING_IN
+ StackStateAnimator.ANIMATION_DURATION_HEADS_UP_CYCLING,
};
static final int ANIMATION_TYPE_ADD = 0;
@@ -6204,6 +6236,8 @@
static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK = 13;
static final int ANIMATION_TYPE_HEADS_UP_OTHER = 14;
static final int ANIMATION_TYPE_EVERYTHING = 15;
+ static final int ANIMATION_TYPE_HEADS_UP_CYCLING_OUT = 16;
+ static final int ANIMATION_TYPE_HEADS_UP_CYCLING_IN = 17;
final long eventStartTime;
final ExpandableView mChangingView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index d0cebae..0fcfc4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation;
import java.util.ArrayList;
@@ -75,6 +76,7 @@
private float mSmallCornerRadius;
private float mLargeCornerRadius;
private int mHeadsUpAppearHeightBottom;
+ private int mHeadsUpCyclingPadding;
public StackScrollAlgorithm(
Context context,
@@ -99,6 +101,8 @@
R.dimen.heads_up_status_bar_padding);
mHeadsUpAppearStartAboveScreen = res.getDimensionPixelSize(
R.dimen.heads_up_appear_y_above_screen);
+ mHeadsUpCyclingPadding = context.getResources()
+ .getDimensionPixelSize(R.dimen.heads_up_cycling_padding);
mPinnedZTranslationExtra = res.getDimensionPixelSize(
R.dimen.heads_up_pinned_elevation);
mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height);
@@ -348,7 +352,8 @@
&& !firstHeadsUp
&& (isHeadsUp || child.isHeadsUpAnimatingAway())
&& newNotificationEnd > firstHeadsUpEnd
- && !ambientState.isShadeExpanded()) {
+ && !ambientState.isShadeExpanded()
+ && !skipClipBottomForCycling(child, ambientState)) {
// The bottom of this view is peeking out from under the previous view.
// Clip the part that is peeking out.
float overlapAmount = newNotificationEnd - firstHeadsUpEnd;
@@ -370,6 +375,44 @@
}
}
+ /**
+ * @return Should we skip clipping the bottom clipping when new hun has lower bottom line for
+ * the hun cycling animation.
+ */
+ private boolean skipClipBottomForCycling(ExpandableView view, AmbientState ambientState) {
+ if (!NotificationHeadsUpCycling.isEnabled()) return false;
+ if (!isCyclingOut(view, ambientState)) return false;
+ // skip bottom clipping if we animate the bottom line
+ return NotificationHeadsUpCycling.getAnimateTallToShort();
+ }
+
+ /**
+ * Whether the view is the hun that is cycling out by the notification avalanche.
+ */
+ public boolean isCyclingOut(ExpandableView view, AmbientState ambientState) {
+ if (!NotificationHeadsUpCycling.isEnabled()) return false;
+ if (!(view instanceof ExpandableNotificationRow)) return false;
+ return isCyclingOut((ExpandableNotificationRow) view, ambientState);
+ }
+
+ /**
+ * Whether the row is the hun that is cycling out by the notification avalanche.
+ */
+ public boolean isCyclingOut(ExpandableNotificationRow row, AmbientState ambientState) {
+ if (!NotificationHeadsUpCycling.isEnabled()) return false;
+ String cyclingOutKey = ambientState.getAvalanchePreviousHunKey();
+ return row.getEntry().getKey().equals(cyclingOutKey);
+ }
+
+ /**
+ * Whether the row is the hun that is cycling in by the notification avalanche.
+ */
+ public boolean isCyclingIn(ExpandableNotificationRow row, AmbientState ambientState) {
+ if (!NotificationHeadsUpCycling.isEnabled()) return false;
+ String cyclingInKey = ambientState.getAvalancheShowingHunKey();
+ return row.getEntry().getKey().equals(cyclingInKey);
+ }
+
/** Updates the dimmed and hiding sensitive states of the children. */
private void updateDimmedAndHideSensitive(AmbientState ambientState,
StackScrollAlgorithmState algorithmState) {
@@ -799,6 +842,7 @@
}
ExpandableNotificationRow topHeadsUpEntry = null;
+ int cyclingInHunHeight = -1;
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
if (!(child instanceof ExpandableNotificationRow row)) {
@@ -839,6 +883,13 @@
childState.setYTranslation(
Math.max(childState.getYTranslation(), headsUpTranslation));
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
+ if (NotificationHeadsUpCycling.isEnabled()) {
+ if (isCyclingIn(row, ambientState)) {
+ if (cyclingInHunHeight == -1) {
+ cyclingInHunHeight = childState.height;
+ }
+ }
+ }
childState.hidden = false;
ExpandableViewState topState =
topHeadsUpEntry == null ? null : topHeadsUpEntry.getViewState();
@@ -860,6 +911,26 @@
}
}
if (row.isHeadsUpAnimatingAway()) {
+ if (NotificationHeadsUpCycling.isEnabled() && isCyclingOut(row, ambientState)) {
+ // If the two HUNs in the cycling animation have different heights, we need
+ // an extra y translation to align the animation.
+ int extraTranslation;
+ if (NotificationHeadsUpCycling.getAnimateTallToShort()) {
+ if (cyclingInHunHeight > 0) {
+ extraTranslation = cyclingInHunHeight - childState.height;
+ } else {
+ extraTranslation = 0;
+ }
+ } else {
+ extraTranslation = cyclingInHunHeight >= childState.height
+ ? cyclingInHunHeight - childState.height : 0;
+ }
+ extraTranslation += mHeadsUpCyclingPadding;
+ float inSpaceTranslation = Math.max(childState.getYTranslation(),
+ headsUpTranslation);
+ childState.setYTranslation(inSpaceTranslation + extraTranslation);
+ cyclingInHunHeight = -1;
+ } else
if (NotificationsImprovedHunAnimation.isEnabled() && !ambientState.isDozing()) {
if (shouldHunAppearFromBottom(ambientState, childState)) {
// move to the bottom of the screen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 5963d35..5dc5449 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_CYCLING_IN;
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_CYCLING_OUT;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK;
@@ -57,6 +59,7 @@
public static final int ANIMATION_DURATION_CLOSE_REMOTE_INPUT = 150;
public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 400;
public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 400;
+ public static final int ANIMATION_DURATION_HEADS_UP_CYCLING = 400;
public static final int ANIMATION_DURATION_FOLD_TO_AOD =
AnimatableClockView.ANIMATION_DURATION_FOLD_TO_AOD;
public static final int ANIMATION_DURATION_PRIORITY_CHANGE = 500;
@@ -68,6 +71,8 @@
@VisibleForTesting int mGoToFullShadeAppearingTranslation;
@VisibleForTesting float mHeadsUpAppearStartAboveScreen;
+ // Padding between the old and new heads up notifications for the hun cycling animation
+ private float mHeadsUpCyclingPadding;
private final ExpandableViewState mTmpState = new ExpandableViewState();
private final AnimationProperties mAnimationProperties;
public NotificationStackScrollLayout mHostLayout;
@@ -125,6 +130,8 @@
R.dimen.go_to_full_shade_appearing_translation);
mHeadsUpAppearStartAboveScreen = context.getResources()
.getDimensionPixelSize(R.dimen.heads_up_appear_y_above_screen);
+ mHeadsUpCyclingPadding = context.getResources()
+ .getDimensionPixelSize(R.dimen.heads_up_cycling_padding);
}
protected void setLogger(StackStateLogger logger) {
@@ -449,7 +456,8 @@
}
changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR,
0 /* delay */, translationDirection, false /* isHeadsUpAppear */,
- startAnimation, postAnimation, getGlobalAnimationFinishedListener());
+ startAnimation, postAnimation, getGlobalAnimationFinishedListener(),
+ ExpandableView.ClipSide.BOTTOM);
needsCustomAnimation = true;
} else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
@@ -464,6 +472,27 @@
.AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) {
ExpandableNotificationRow row = (ExpandableNotificationRow) event.mChangingView;
row.prepareExpansionChanged();
+ } else if (event.animationType == ANIMATION_TYPE_HEADS_UP_CYCLING_IN) {
+ mHeadsUpAppearChildren.add(changingView);
+
+ mTmpState.copyFrom(changingView.getViewState());
+ mTmpState.setYTranslation(changingView.getViewState().getYTranslation()
+ + getHeadsUpCyclingInYTranslationStart(event.headsUpFromBottom));
+ mTmpState.applyToView(changingView);
+
+ // TODO(b/339519404): use a different interpolator
+ Runnable onAnimationEnd = null;
+ if (loggable) {
+ // This only captures HEADS_UP_APPEAR animations, but HUNs can appear with
+ // normal ADD animations, which would not be logged here.
+ String finalKey = key;
+ mLogger.logHUNViewAppearing(key);
+ onAnimationEnd = () -> {
+ mLogger.appearAnimationEnded(finalKey);
+ };
+ }
+ changingView.performAddAnimation(0, ANIMATION_DURATION_HEADS_UP_CYCLING,
+ /* isHeadsUpAppear= */ true, onAnimationEnd);
} else if (NotificationsImprovedHunAnimation.isEnabled()
&& (event.animationType == ANIMATION_TYPE_HEADS_UP_APPEAR)) {
mHeadsUpAppearChildren.add(changingView);
@@ -486,6 +515,87 @@
}
changingView.performAddAnimation(0, ANIMATION_DURATION_HEADS_UP_APPEAR,
/* isHeadsUpAppear= */ true, onAnimationEnd);
+ } else if (event.animationType == ANIMATION_TYPE_HEADS_UP_CYCLING_OUT) {
+ mHeadsUpDisappearChildren.add(changingView);
+ Runnable endRunnable = null;
+ mTmpState.copyFrom(changingView.getViewState());
+
+ if (changingView.getParent() == null) {
+ // This notification was actually removed, so we need to add it
+ // transiently
+ mHostLayout.addTransientView(changingView, 0);
+ changingView.setTransientContainer(mHostLayout);
+ // TODO(b/316404716): remove the hard-coded height
+ // StackScrollAlgorithm cannot find this view because it has been removed
+ // from the NSSL. To correctly translate the view to the top or bottom of
+ // the screen (where it animated from), we need to update its translation.
+ mTmpState.setYTranslation(
+ mTmpState.getYTranslation() + 10
+ );
+ endRunnable = changingView::removeFromTransientContainer;
+ }
+
+ boolean needsAnimation = true;
+ if (changingView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row =
+ (ExpandableNotificationRow) changingView;
+ if (row.isDismissed()) {
+ needsAnimation = false;
+ }
+ }
+ if (needsAnimation) {
+ // We need to add the global animation listener, since once no animations are
+ // running anymore, the panel will instantly hide itself. We need to wait until
+ // the animation is fully finished for this though.
+ final Runnable tmpEndRunnable = endRunnable;
+ Runnable postAnimation;
+ Runnable startAnimation;
+ if (loggable) {
+ String finalKey1 = key;
+ final boolean finalIsHeadsUp = isHeadsUp;
+ final String type = "ANIMATION_TYPE_HEADS_UP_CYCLING_OUT";
+ startAnimation = () -> {
+ mLogger.animationStart(finalKey1, type, finalIsHeadsUp);
+ changingView.setInRemovalAnimation(true);
+ };
+ postAnimation = () -> {
+ mLogger.animationEnd(finalKey1, type, finalIsHeadsUp);
+ changingView.setInRemovalAnimation(false);
+ if (tmpEndRunnable != null) {
+ tmpEndRunnable.run();
+ }
+
+ };
+ } else {
+ postAnimation = () -> {
+ changingView.setInRemovalAnimation(false);
+ if (tmpEndRunnable != null) {
+ tmpEndRunnable.run();
+ }
+ };
+ startAnimation = () -> {
+ changingView.setInRemovalAnimation(true);
+ };
+ }
+ long removeAnimationDelay = changingView.performRemoveAnimation(
+ ANIMATION_DURATION_HEADS_UP_CYCLING,
+ /* delay= */ 0,
+ // It's a shame that translationDirection isn't where we do the y
+ // translation, the actual translation is in StackScrollAlgorithm.
+ /* translationDirection= */ 0.0f,
+ /* isHeadsUpAnimation= */ true,
+ startAnimation, postAnimation,
+ getGlobalAnimationFinishedListener(), ExpandableView.ClipSide.TOP);
+ mAnimationProperties.delay += removeAnimationDelay;
+ mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_CYCLING;
+ mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y,
+ Interpolators.LINEAR);
+ mAnimationProperties.getAnimationFilter().animateY = true;
+ mTmpState.animateTo(changingView, mAnimationProperties);
+ } else if (endRunnable != null) {
+ endRunnable.run();
+ }
+ needsCustomAnimation |= needsAnimation;
} else if (event.animationType == ANIMATION_TYPE_HEADS_UP_APPEAR) {
NotificationsImprovedHunAnimation.assertInLegacyMode();
// This item is added, initialize its properties.
@@ -565,21 +675,21 @@
}
};
} else {
+ startAnimation = () -> {
+ changingView.setInRemovalAnimation(true);
+ };
postAnimation = () -> {
changingView.setInRemovalAnimation(false);
if (tmpEndRunnable != null) {
tmpEndRunnable.run();
}
};
- startAnimation = () -> {
- changingView.setInRemovalAnimation(true);
- };
}
long removeAnimationDelay = changingView.performRemoveAnimation(
ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
0, 0.0f, true /* isHeadsUpAppear */,
startAnimation, postAnimation,
- getGlobalAnimationFinishedListener());
+ getGlobalAnimationFinishedListener(), ExpandableView.ClipSide.BOTTOM);
mAnimationProperties.delay += removeAnimationDelay;
if (NotificationsImprovedHunAnimation.isEnabled()) {
mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR;
@@ -607,6 +717,38 @@
return -mStackTopMargin - mHeadsUpAppearStartAboveScreen;
}
+ /**
+ * @param headsUpFromBottom Whether we are showing the HUNs at the bottom of the screen
+ * @return The start y translation of the HUN cycling in animation
+ */
+ private float getHeadsUpCyclingInYTranslationStart(boolean headsUpFromBottom) {
+ if (headsUpFromBottom) {
+ // start from the bottom of the screen
+ return mHeadsUpAppearHeightBottom + mHeadsUpCyclingPadding;
+ }
+ // start from the top of the screen
+ return -mHeadsUpCyclingPadding;
+ }
+
+ /**
+ * @param headsUpFromBottom Whether we are showing the HUNs at the bottom of the screen
+ * @param oldHunHeight Height of the old HUN
+ * @param newHunHeight Height of the new HUN
+ * @return The y translation target value of the HUN cycling out animation
+ */
+ private float getHeadsUpCyclingOutYTranslation(
+ boolean headsUpFromBottom,
+ int oldHunHeight,
+ int newHunHeight
+ ) {
+ final float translationDistance = mHeadsUpCyclingPadding + newHunHeight - oldHunHeight;
+ if (headsUpFromBottom) {
+ // start from the bottom of the screen
+ return mHeadsUpAppearHeightBottom - translationDistance;
+ }
+ return translationDistance;
+ }
+
public void animateOverScrollToAmount(float targetAmount, final boolean onTop,
final boolean isRubberbanded) {
final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index be6bef7..23674b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2184,7 +2184,9 @@
}
if (mStatusBarStateController.leaveOpenOnKeyguardHide()) {
if (!mStatusBarStateController.isKeyguardRequested()) {
- mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
+ if (!MigrateClocksToBlueprint.isEnabled()) {
+ mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
+ }
}
long delay = mKeyguardStateController.calculateGoingToFullShadeDelay();
mLockscreenShadeTransitionController.onHideKeyguard(delay, previousState);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index e72027a..6f550ba 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -371,7 +371,7 @@
}
@Test
- fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToOne() =
+ fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToZero() =
runBlocking(IMMEDIATE) {
val transitionStep = MutableStateFlow(TransitionStep())
whenever(keyguardTransitionInteractor.transitionStepsToState(KeyguardState.LOCKSCREEN))
@@ -434,6 +434,27 @@
}
@Test
+ fun listenForAnyStateToDozingTransition_UpdatesClockDozeAmountToOne() =
+ runBlocking(IMMEDIATE) {
+ val transitionStep = MutableStateFlow(TransitionStep())
+ whenever(keyguardTransitionInteractor.transitionStepsToState(KeyguardState.DOZING))
+ .thenReturn(transitionStep)
+
+ val job = underTest.listenForAnyStateToDozingTransition(this)
+ transitionStep.value =
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DOZING,
+ transitionState = TransitionState.STARTED,
+ )
+ yield()
+
+ verify(animations, times(2)).doze(1f)
+
+ job.cancel()
+ }
+
+ @Test
fun unregisterListeners_validate() =
runBlocking(IMMEDIATE) {
underTest.unregisterListeners()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
index 2172bc5..8695c01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
@@ -5,12 +5,12 @@
import android.hardware.biometrics.PromptVerticalListContentView
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
import com.android.systemui.biometrics.promptInfo
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
+import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -110,7 +110,7 @@
it.description = description
it.subtitle = subtitle
},
- kind = Utils.CREDENTIAL_PIN,
+ kind = PromptKind.Pin,
userId = USER_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
@@ -135,7 +135,7 @@
it.subtitle = subtitle
it.contentView = contentView
},
- kind = Utils.CREDENTIAL_PIN,
+ kind = PromptKind.Pin,
userId = USER_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
@@ -163,7 +163,7 @@
it.subtitle = subtitle
it.contentView = contentView
},
- kind = Utils.CREDENTIAL_PIN,
+ kind = PromptKind.Pin,
userId = USER_ID,
challenge = OPERATION_ID,
opPackageName = OP_PACKAGE_NAME
@@ -171,13 +171,13 @@
assertThat(showTitleOnly).isFalse()
}
- @Test fun usePinCredentialForPrompt() = useCredentialForPrompt(Utils.CREDENTIAL_PIN)
+ @Test fun usePinCredentialForPrompt() = useCredentialForPrompt(PromptKind.Pin)
- @Test fun usePasswordCredentialForPrompt() = useCredentialForPrompt(Utils.CREDENTIAL_PASSWORD)
+ @Test fun usePasswordCredentialForPrompt() = useCredentialForPrompt(PromptKind.Password)
- @Test fun usePatternCredentialForPrompt() = useCredentialForPrompt(Utils.CREDENTIAL_PATTERN)
+ @Test fun usePatternCredentialForPrompt() = useCredentialForPrompt(PromptKind.Pattern)
- private fun useCredentialForPrompt(kind: Int) =
+ private fun useCredentialForPrompt(kind: PromptKind) =
testScope.runTest {
val isStealth = false
credentialInteractor.stealthMode = isStealth
@@ -211,11 +211,10 @@
assertThat(prompt)
.isInstanceOf(
when (kind) {
- Utils.CREDENTIAL_PIN -> BiometricPromptRequest.Credential.Pin::class.java
- Utils.CREDENTIAL_PASSWORD ->
+ PromptKind.Pin -> BiometricPromptRequest.Credential.Pin::class.java
+ PromptKind.Password ->
BiometricPromptRequest.Credential.Password::class.java
- Utils.CREDENTIAL_PATTERN ->
- BiometricPromptRequest.Credential.Pattern::class.java
+ PromptKind.Pattern -> BiometricPromptRequest.Credential.Pattern::class.java
else -> throw Exception("wrong kind")
}
)
@@ -341,6 +340,28 @@
job.cancel()
}
+
+ /** Update the current request to use credential-based authentication instead of biometrics. */
+ private fun PromptCredentialInteractor.useCredentialsForAuthentication(
+ promptInfo: PromptInfo,
+ kind: PromptKind,
+ userId: Int,
+ challenge: Long,
+ opPackageName: String,
+ ) {
+ biometricPromptRepository.setPrompt(
+ promptInfo,
+ userId,
+ challenge,
+ kind,
+ opPackageName,
+ )
+ }
+
+ /** Unset the current authentication request. */
+ private fun PromptCredentialInteractor.resetPrompt() {
+ biometricPromptRepository.unsetPrompt()
+ }
}
private fun pinRequest(): BiometricPromptRequest.Credential.Pin =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 2817780..c308507 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.faceSensorPropertiesInternal
@@ -143,21 +142,20 @@
}
@Test
- fun usePinCredentialAndReset() =
- testScope.runTest { useCredentialAndReset(Utils.CREDENTIAL_PIN) }
+ fun usePinCredentialAndReset() = testScope.runTest { useCredentialAndReset(PromptKind.Pin) }
@Test
fun usePatternCredentialAndReset() =
- testScope.runTest { useCredentialAndReset(Utils.CREDENTIAL_PATTERN) }
+ testScope.runTest { useCredentialAndReset(PromptKind.Pattern) }
@Test
fun usePasswordCredentialAndReset() =
- testScope.runTest { useCredentialAndReset(Utils.CREDENTIAL_PASSWORD) }
+ testScope.runTest { useCredentialAndReset(PromptKind.Password) }
- private fun TestScope.useCredentialAndReset(@Utils.CredentialType kind: Int) {
+ private fun TestScope.useCredentialAndReset(kind: PromptKind) {
setUserCredentialType(
- isPin = kind == Utils.CREDENTIAL_PIN,
- isPassword = kind == Utils.CREDENTIAL_PASSWORD,
+ isPin = kind == PromptKind.Pin,
+ isPassword = kind == PromptKind.Password,
)
val info =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 3793970..5b47c94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -446,6 +446,7 @@
mUiEventLogger,
() -> mKosmos.getInteractionJankMonitor(),
mJavaAdapter,
+ () -> mKeyguardTransitionInteractor,
() -> mShadeInteractor,
() -> mKosmos.getDeviceUnlockedInteractor(),
() -> mKosmos.getSceneInteractor(),
@@ -600,6 +601,7 @@
new UiEventLoggerFake(),
() -> mKosmos.getInteractionJankMonitor(),
mJavaAdapter,
+ () -> mKeyguardTransitionInteractor,
() -> mShadeInteractor,
() -> mKosmos.getDeviceUnlockedInteractor(),
() -> mKosmos.getSceneInteractor(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
index 4f0f91a..926c35f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
@@ -134,7 +134,8 @@
/* isHeadsUpAnimation= */ eq(true),
/* onStartedRunnable= */ any(),
/* onFinishedRunnable= */ runnableCaptor.capture(),
- /* animationListener= */ any()
+ /* animationListener= */ any(),
+ /* clipSide= */ eq(ExpandableView.ClipSide.BOTTOM),
)
animatorTestRule.advanceTimeBy(disappearDuration) // move to the end of SSA animations
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
index 3762497..ec56327 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -33,6 +34,7 @@
uiEventLogger,
{ interactionJankMonitor },
mock(),
+ { keyguardTransitionInteractor },
{ shadeInteractor },
{ deviceUnlockedInteractor },
{ sceneInteractor },
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 9c84b12..c4b461f 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -564,6 +564,18 @@
});
}
+ /** Sets focused_autofill_id using view id */
+ public void maybeSetFocusedId(AutofillId id) {
+ maybeSetFocusedId(id.getViewId());
+ }
+
+ /** Sets focused_autofill_id as long as mEventInternal is present */
+ public void maybeSetFocusedId(int id) {
+ mEventInternal.ifPresent(event -> {
+ event.mFocusedId = id;
+ });
+ }
+
public void logAndEndEvent() {
if (!mEventInternal.isPresent()) {
Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
@@ -608,7 +620,8 @@
+ " mIsCredentialRequest=" + event.mIsCredentialRequest
+ " mWebviewRequestedCredential=" + event.mWebviewRequestedCredential
+ " mViewFillableTotalCount=" + event.mViewFillableTotalCount
- + " mViewFillFailureCount=" + event.mViewFillFailureCount);
+ + " mViewFillFailureCount=" + event.mViewFillFailureCount
+ + " mFocusedId=" + event.mFocusedId);
}
// TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
@@ -651,7 +664,8 @@
event.mIsCredentialRequest,
event.mWebviewRequestedCredential,
event.mViewFillableTotalCount,
- event.mViewFillFailureCount);
+ event.mViewFillFailureCount,
+ event.mFocusedId);
mEventInternal = Optional.empty();
}
@@ -689,6 +703,7 @@
boolean mWebviewRequestedCredential = false;
int mViewFillableTotalCount = -1;
int mViewFillFailureCount = -1;
+ int mFocusedId = -1;
PresentationStatsEventInternal() {}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8b13c4b7..03cf74f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -4669,6 +4669,7 @@
mFieldClassificationIdSnapshot);
mPresentationStatsEventLogger.maybeSetAvailableCount(
response.getDatasets(), mCurrentViewId);
+ mPresentationStatsEventLogger.maybeSetFocusedId(mCurrentViewId);
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 748253f..1a8c3b0 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -35,7 +35,6 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
-import android.os.Bundle;
import android.os.BundleMerger;
import android.os.Debug;
import android.os.DropBoxManager;
@@ -176,6 +175,16 @@
}
};
+ private static final BundleMerger sDropboxEntryAddedExtrasMerger;
+ static {
+ sDropboxEntryAddedExtrasMerger = new BundleMerger();
+ sDropboxEntryAddedExtrasMerger.setDefaultMergeStrategy(BundleMerger.STRATEGY_FIRST);
+ sDropboxEntryAddedExtrasMerger.setMergeStrategy(DropBoxManager.EXTRA_TIME,
+ BundleMerger.STRATEGY_COMPARABLE_MAX);
+ sDropboxEntryAddedExtrasMerger.setMergeStrategy(DropBoxManager.EXTRA_DROPPED_COUNT,
+ BundleMerger.STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD);
+ }
+
private final IDropBoxManagerService.Stub mStub = new IDropBoxManagerService.Stub() {
@Override
public void addData(String tag, byte[] data, int flags) {
@@ -284,7 +293,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SEND_BROADCAST:
- prepareAndSendBroadcast((Intent) msg.obj, null);
+ prepareAndSendBroadcast((Intent) msg.obj, false);
break;
case MSG_SEND_DEFERRED_BROADCAST:
Intent deferredIntent;
@@ -292,31 +301,42 @@
deferredIntent = mDeferredMap.remove((String) msg.obj);
}
if (deferredIntent != null) {
- prepareAndSendBroadcast(deferredIntent,
- createBroadcastOptions(deferredIntent));
+ prepareAndSendBroadcast(deferredIntent, true);
}
break;
}
}
- private void prepareAndSendBroadcast(Intent intent, Bundle options) {
+ private void prepareAndSendBroadcast(Intent intent, boolean deferrable) {
if (!DropBoxManagerService.this.mBooted) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
if (Flags.enableReadDropboxPermission()) {
- BroadcastOptions unbundledOptions = (options == null)
- ? BroadcastOptions.makeBasic() : BroadcastOptions.fromBundle(options);
-
- unbundledOptions.setRequireCompatChange(ENFORCE_READ_DROPBOX_DATA, true);
+ options.setRequireCompatChange(ENFORCE_READ_DROPBOX_DATA, true);
+ if (deferrable) {
+ final String matchingKey = intent.getStringExtra(DropBoxManager.EXTRA_TAG)
+ + "-READ_DROPBOX_DATA";
+ setBroadcastOptionsForDeferral(options, matchingKey);
+ }
getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
- Manifest.permission.READ_DROPBOX_DATA, unbundledOptions.toBundle());
+ Manifest.permission.READ_DROPBOX_DATA, options.toBundle());
- unbundledOptions.setRequireCompatChange(ENFORCE_READ_DROPBOX_DATA, false);
+ options.setRequireCompatChange(ENFORCE_READ_DROPBOX_DATA, false);
+ if (deferrable) {
+ final String matchingKey = intent.getStringExtra(DropBoxManager.EXTRA_TAG)
+ + "-READ_LOGS";
+ setBroadcastOptionsForDeferral(options, matchingKey);
+ }
getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
- Manifest.permission.READ_LOGS, unbundledOptions.toBundle());
+ Manifest.permission.READ_LOGS, options.toBundle());
} else {
+ if (deferrable) {
+ final String matchingKey = intent.getStringExtra(DropBoxManager.EXTRA_TAG);
+ setBroadcastOptionsForDeferral(options, matchingKey);
+ }
getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.READ_LOGS, options);
+ android.Manifest.permission.READ_LOGS, options.toBundle());
}
}
@@ -328,21 +348,12 @@
return dropboxIntent;
}
- private Bundle createBroadcastOptions(Intent intent) {
- final BundleMerger extrasMerger = new BundleMerger();
- extrasMerger.setDefaultMergeStrategy(BundleMerger.STRATEGY_FIRST);
- extrasMerger.setMergeStrategy(DropBoxManager.EXTRA_TIME,
- BundleMerger.STRATEGY_COMPARABLE_MAX);
- extrasMerger.setMergeStrategy(DropBoxManager.EXTRA_DROPPED_COUNT,
- BundleMerger.STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD);
-
- return BroadcastOptions.makeBasic()
- .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED)
+ private void setBroadcastOptionsForDeferral(BroadcastOptions options, String matchingKey) {
+ options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED)
.setDeliveryGroupMatchingKey(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED,
- intent.getStringExtra(DropBoxManager.EXTRA_TAG))
- .setDeliveryGroupExtrasMerger(extrasMerger)
- .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
- .toBundle();
+ matchingKey)
+ .setDeliveryGroupExtrasMerger(sDropboxEntryAddedExtrasMerger)
+ .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE);
}
/**
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index cc6ae5c..8647750 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3277,7 +3277,13 @@
}
final int curSchedGroup = state.getCurrentSchedulingGroup();
- if (state.getSetSchedGroup() != curSchedGroup) {
+ if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
+ && ActivityManager.isProcStateBackground(state.getCurProcState())
+ && !state.hasStartedServices()) {
+ app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
+ success = false;
+ } else if (state.getSetSchedGroup() != curSchedGroup) {
int oldSchedGroup = state.getSetSchedGroup();
state.setSetSchedGroup(curSchedGroup);
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
@@ -3285,74 +3291,66 @@
+ " to " + curSchedGroup + ": " + state.getAdjType();
reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
}
- if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
- && ActivityManager.isProcStateBackground(state.getSetProcState())
- && !state.hasStartedServices()) {
- app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
- success = false;
- } else {
- int processGroup;
- switch (curSchedGroup) {
- case SCHED_GROUP_BACKGROUND:
- processGroup = THREAD_GROUP_BACKGROUND;
- break;
- case SCHED_GROUP_TOP_APP:
- case SCHED_GROUP_TOP_APP_BOUND:
- processGroup = THREAD_GROUP_TOP_APP;
- break;
- case SCHED_GROUP_RESTRICTED:
- processGroup = THREAD_GROUP_RESTRICTED;
- break;
- default:
- processGroup = THREAD_GROUP_DEFAULT;
- break;
- }
- mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
- 0 /* unused */, app.getPid(), processGroup, app.processName));
- try {
- final int renderThreadTid = app.getRenderThreadTid();
- if (curSchedGroup == SCHED_GROUP_TOP_APP) {
- // do nothing if we already switched to RT
- if (oldSchedGroup != SCHED_GROUP_TOP_APP) {
- app.getWindowProcessController().onTopProcChanged();
- if (app.useFifoUiScheduling()) {
- // Switch UI pipeline for app to SCHED_FIFO
- state.setSavedPriority(Process.getThreadPriority(app.getPid()));
- ActivityManagerService.setFifoPriority(app, true /* enable */);
- } else {
- // Boost priority for top app UI and render threads
- setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
- if (renderThreadTid != 0) {
- try {
- setThreadPriority(renderThreadTid,
- THREAD_PRIORITY_TOP_APP_BOOST);
- } catch (IllegalArgumentException e) {
- // thread died, ignore
- }
+ int processGroup;
+ switch (curSchedGroup) {
+ case SCHED_GROUP_BACKGROUND:
+ processGroup = THREAD_GROUP_BACKGROUND;
+ break;
+ case SCHED_GROUP_TOP_APP:
+ case SCHED_GROUP_TOP_APP_BOUND:
+ processGroup = THREAD_GROUP_TOP_APP;
+ break;
+ case SCHED_GROUP_RESTRICTED:
+ processGroup = THREAD_GROUP_RESTRICTED;
+ break;
+ default:
+ processGroup = THREAD_GROUP_DEFAULT;
+ break;
+ }
+ mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
+ 0 /* unused */, app.getPid(), processGroup, app.processName));
+ try {
+ final int renderThreadTid = app.getRenderThreadTid();
+ if (curSchedGroup == SCHED_GROUP_TOP_APP) {
+ // do nothing if we already switched to RT
+ if (oldSchedGroup != SCHED_GROUP_TOP_APP) {
+ app.getWindowProcessController().onTopProcChanged();
+ if (app.useFifoUiScheduling()) {
+ // Switch UI pipeline for app to SCHED_FIFO
+ state.setSavedPriority(Process.getThreadPriority(app.getPid()));
+ ActivityManagerService.setFifoPriority(app, true /* enable */);
+ } else {
+ // Boost priority for top app UI and render threads
+ setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
+ if (renderThreadTid != 0) {
+ try {
+ setThreadPriority(renderThreadTid,
+ THREAD_PRIORITY_TOP_APP_BOOST);
+ } catch (IllegalArgumentException e) {
+ // thread died, ignore
}
}
}
- } else if (oldSchedGroup == SCHED_GROUP_TOP_APP
- && curSchedGroup != SCHED_GROUP_TOP_APP) {
- app.getWindowProcessController().onTopProcChanged();
- if (app.useFifoUiScheduling()) {
- // Reset UI pipeline to SCHED_OTHER
- ActivityManagerService.setFifoPriority(app, false /* enable */);
- setThreadPriority(app.getPid(), state.getSavedPriority());
- } else {
- // Reset priority for top app UI and render threads
- setThreadPriority(app.getPid(), 0);
- }
+ }
+ } else if (oldSchedGroup == SCHED_GROUP_TOP_APP
+ && curSchedGroup != SCHED_GROUP_TOP_APP) {
+ app.getWindowProcessController().onTopProcChanged();
+ if (app.useFifoUiScheduling()) {
+ // Reset UI pipeline to SCHED_OTHER
+ ActivityManagerService.setFifoPriority(app, false /* enable */);
+ setThreadPriority(app.getPid(), state.getSavedPriority());
+ } else {
+ // Reset priority for top app UI and render threads
+ setThreadPriority(app.getPid(), 0);
+ }
- if (renderThreadTid != 0) {
- setThreadPriority(renderThreadTid, THREAD_PRIORITY_DISPLAY);
- }
+ if (renderThreadTid != 0) {
+ setThreadPriority(renderThreadTid, THREAD_PRIORITY_DISPLAY);
}
- } catch (Exception e) {
- if (DEBUG_ALL) {
- Slog.w(TAG, "Failed setting thread priority of " + app.getPid(), e);
- }
+ }
+ } catch (Exception e) {
+ if (DEBUG_ALL) {
+ Slog.w(TAG, "Failed setting thread priority of " + app.getPid(), e);
}
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 85eb044..1db3483 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2912,10 +2912,12 @@
final int proxyUid = attributionSource.getUid();
final String proxyPackageName = attributionSource.getPackageName();
final String proxyAttributionTag = attributionSource.getAttributionTag();
- final int proxiedUid = attributionSource.getNextUid();
final int proxyVirtualDeviceId = attributionSource.getDeviceId();
+
+ final int proxiedUid = attributionSource.getNextUid();
final String proxiedPackageName = attributionSource.getNextPackageName();
final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
+ final int proxiedVirtualDeviceId = attributionSource.getNextDeviceId();
verifyIncomingProxyUid(attributionSource);
verifyIncomingOp(code);
@@ -2952,7 +2954,8 @@
final SyncNotedAppOp proxyReturn = noteOperationUnchecked(code, proxyUid,
resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId,
- Process.INVALID_UID, null, null, proxyFlags, !isProxyTrusted,
+ Process.INVALID_UID, null, null,
+ Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted,
"proxy " + message, shouldCollectMessage);
if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
@@ -2970,9 +2973,9 @@
final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
- proxiedAttributionTag, proxyVirtualDeviceId, proxyUid, resolveProxyPackageName,
- proxyAttributionTag, proxiedFlags, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName,
+ proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp,
+ message, shouldCollectMessage);
}
@Override
@@ -3023,14 +3026,14 @@
}
return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
virtualDeviceId, Process.INVALID_UID, null, null,
- AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp,
+ message, shouldCollectMessage);
}
private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag, int virtualDeviceId, int proxyUid,
- String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags,
- boolean shouldCollectAsyncNotedOp, @Nullable String message,
+ String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId,
+ @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message,
boolean shouldCollectMessage) {
PackageVerificationResult pvr;
try {
@@ -3161,8 +3164,9 @@
}
scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag,
virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED);
+
attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
- uidState.getState(), flags);
+ getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags);
if (shouldCollectAsyncNotedOp) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
@@ -3528,9 +3532,9 @@
}
return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
- virtualDeviceId, Process.INVALID_UID, null, null, OP_FLAG_SELF,
- startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- attributionFlags, attributionChainId);
+ virtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT,
+ OP_FLAG_SELF, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ shouldCollectMessage, attributionFlags, attributionChainId);
}
/** @deprecated Use {@link #startProxyOperationWithState} instead. */
@@ -3568,18 +3572,32 @@
final int proxyUid = attributionSource.getUid();
final String proxyPackageName = attributionSource.getPackageName();
final String proxyAttributionTag = attributionSource.getAttributionTag();
- final int proxiedUid = attributionSource.getNextUid();
final int proxyVirtualDeviceId = attributionSource.getDeviceId();
+
+ final int proxiedUid = attributionSource.getNextUid();
final String proxiedPackageName = attributionSource.getNextPackageName();
final String proxiedAttributionTag = attributionSource.getNextAttributionTag();
+ final int proxiedVirtualDeviceId = attributionSource.getNextDeviceId();
verifyIncomingProxyUid(attributionSource);
verifyIncomingOp(code);
if (!isValidVirtualDeviceId(proxyVirtualDeviceId)) {
- Slog.w(TAG, "startProxyOperationImpl returned MODE_IGNORED as virtualDeviceId "
- + proxyVirtualDeviceId + " is invalid");
- return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag,
- proxiedPackageName);
+ Slog.w(
+ TAG,
+ "startProxyOperationImpl returned MODE_IGNORED as proxyVirtualDeviceId "
+ + proxyVirtualDeviceId
+ + " is invalid");
+ return new SyncNotedAppOp(
+ AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag, proxiedPackageName);
+ }
+ if (!isValidVirtualDeviceId(proxiedVirtualDeviceId)) {
+ Slog.w(
+ TAG,
+ "startProxyOperationImpl returned MODE_IGNORED as proxiedVirtualDeviceId "
+ + proxiedVirtualDeviceId
+ + " is invalid");
+ return new SyncNotedAppOp(
+ AppOpsManager.MODE_IGNORED, code, proxiedAttributionTag, proxiedPackageName);
}
if (!isIncomingPackageValid(proxyPackageName, UserHandle.getUserId(proxyUid))
|| !isIncomingPackageValid(proxiedPackageName, UserHandle.getUserId(proxiedUid))) {
@@ -3621,7 +3639,7 @@
// Test if the proxied operation will succeed before starting the proxy operation
final SyncNotedAppOp testProxiedOp = startOperationDryRun(code,
proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag,
- proxyVirtualDeviceId, resolvedProxyPackageName, proxiedFlags,
+ proxiedVirtualDeviceId, resolvedProxyPackageName, proxiedFlags,
startIfModeDefault);
if (!shouldStartForMode(testProxiedOp.getOpMode(), startIfModeDefault)) {
@@ -3633,7 +3651,7 @@
final SyncNotedAppOp proxyAppOp = startOperationUnchecked(clientId, code, proxyUid,
resolvedProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId,
- Process.INVALID_UID, null, null, proxyFlags,
+ Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, proxyFlags,
startIfModeDefault, !isProxyTrusted, "proxy " + message,
shouldCollectMessage, proxyAttributionFlags, attributionChainId);
if (!shouldStartForMode(proxyAppOp.getOpMode(), startIfModeDefault)) {
@@ -3642,9 +3660,10 @@
}
return startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
- proxiedAttributionTag, proxyVirtualDeviceId, proxyUid, resolvedProxyPackageName,
- proxyAttributionTag, proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage, proxiedAttributionFlags, attributionChainId);
+ proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolvedProxyPackageName,
+ proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, startIfModeDefault,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, proxiedAttributionFlags,
+ attributionChainId);
}
private boolean shouldStartForMode(int mode, boolean startIfModeDefault) {
@@ -3654,9 +3673,10 @@
private SyncNotedAppOp startOperationUnchecked(IBinder clientId, int code, int uid,
@NonNull String packageName, @Nullable String attributionTag, int virtualDeviceId,
int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag,
- @OpFlags int flags, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
- @Nullable String message, boolean shouldCollectMessage,
- @AttributionFlags int attributionFlags, int attributionChainId) {
+ int proxyVirtualDeviceId, @OpFlags int flags, boolean startIfModeDefault,
+ boolean shouldCollectAsyncNotedOp, @Nullable String message,
+ boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
+ int attributionChainId) {
PackageVerificationResult pvr;
try {
pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
@@ -3751,13 +3771,13 @@
+ " flags: " + AppOpsManager.flagsToString(flags));
try {
if (isRestricted) {
- attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
- proxyAttributionTag, virtualDeviceId, uidState.getState(), flags,
- attributionFlags, attributionChainId);
+ attributedOp.createPaused(clientId, virtualDeviceId, proxyUid, proxyPackageName,
+ proxyAttributionTag, getPersistentId(proxyVirtualDeviceId),
+ uidState.getState(), flags, attributionFlags, attributionChainId);
} else {
- attributedOp.started(clientId, proxyUid, proxyPackageName,
- proxyAttributionTag, virtualDeviceId, uidState.getState(), flags,
- attributionFlags, attributionChainId);
+ attributedOp.started(clientId, virtualDeviceId, proxyUid, proxyPackageName,
+ proxyAttributionTag, getPersistentId(proxyVirtualDeviceId),
+ uidState.getState(), flags, attributionFlags, attributionChainId);
startType = START_TYPE_STARTED;
}
} catch (RemoteException e) {
@@ -4946,7 +4966,7 @@
if (accessTime > 0) {
attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
- proxyAttributionTag, uidState, opFlags);
+ proxyAttributionTag, PERSISTENT_DEVICE_ID_DEFAULT, uidState, opFlags);
}
if (rejectTime > 0) {
attributedOp.rejected(rejectTime, uidState, opFlags);
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 2285826..2760ccf 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -24,7 +24,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
-import android.companion.virtual.VirtualDeviceManager;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -95,16 +94,17 @@
*
* @param proxyUid The uid of the proxy
* @param proxyPackageName The package name of the proxy
- * @param proxyAttributionTag the attributionTag in the proxies package
+ * @param proxyAttributionTag The attributionTag in the proxies package
+ * @param proxyDeviceId The device Id of the proxy
* @param uidState UID state of the app noteOp/startOp was called for
* @param flags OpFlags of the call
*/
public void accessed(int proxyUid, @Nullable String proxyPackageName,
- @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
- @AppOpsManager.OpFlags int flags) {
+ @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
+ @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) {
long accessTime = System.currentTimeMillis();
- accessed(accessTime, -1, proxyUid, proxyPackageName,
- proxyAttributionTag, uidState, flags);
+ accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId,
+ uidState, flags);
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, tag, uidState, flags, accessTime,
@@ -118,14 +118,16 @@
* @param duration The duration of the event
* @param proxyUid The uid of the proxy
* @param proxyPackageName The package name of the proxy
- * @param proxyAttributionTag the attributionTag in the proxies package
+ * @param proxyAttributionTag The attributionTag in the proxies package
+ * @param proxyDeviceId The device Id of the proxy
* @param uidState UID state of the app noteOp/startOp was called for
* @param flags OpFlags of the call
*/
@SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
public void accessed(long noteTime, long duration, int proxyUid,
@Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
- @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) {
+ @Nullable String proxyDeviceId, @AppOpsManager.UidState int uidState,
+ @AppOpsManager.OpFlags int flags) {
long key = makeKey(uidState, flags);
if (mAccessEvents == null) {
@@ -135,7 +137,7 @@
AppOpsManager.OpEventProxyInfo proxyInfo = null;
if (proxyUid != Process.INVALID_UID) {
proxyInfo = mAppOpsService.mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
- proxyAttributionTag, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ proxyAttributionTag, proxyDeviceId);
}
AppOpsManager.NoteOpEvent existingEvent = mAccessEvents.get(key);
@@ -189,35 +191,36 @@
* Update state when start was called
*
* @param clientId Id of the startOp caller
+ * @param virtualDeviceId The virtual device id of the startOp caller
* @param proxyUid The UID of the proxy app
* @param proxyPackageName The package name of the proxy app
* @param proxyAttributionTag The attribution tag of the proxy app
+ * @param proxyDeviceId The device id of the proxy app
* @param uidState UID state of the app startOp is called for
* @param flags The proxy flags
* @param attributionFlags The attribution flags associated with this operation.
- * @param attributionChainId The if of the attribution chain this operations is a part of.
+ * @param attributionChainId The if of the attribution chain this operations is a part of
*/
- public void started(@NonNull IBinder clientId, int proxyUid,
+ public void started(@NonNull IBinder clientId, int virtualDeviceId, int proxyUid,
@Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
- int proxyVirtualDeviceId, @AppOpsManager.UidState int uidState,
+ @Nullable String proxyDeviceId, @AppOpsManager.UidState int uidState,
@AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags int attributionFlags,
int attributionChainId) throws RemoteException {
- startedOrPaused(clientId, proxyUid, proxyPackageName,
- proxyAttributionTag, proxyVirtualDeviceId, uidState, flags,
- /* triggeredByUidStateChange */ false, /* isStarted */ true, attributionFlags,
- attributionChainId);
+ startedOrPaused(clientId, virtualDeviceId, proxyUid, proxyPackageName, proxyAttributionTag,
+ proxyDeviceId, uidState, flags, attributionFlags, attributionChainId, false,
+ true);
}
@SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
- private void startedOrPaused(@NonNull IBinder clientId, int proxyUid,
+ private void startedOrPaused(@NonNull IBinder clientId, int virtualDeviceId, int proxyUid,
@Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
- int proxyVirtualDeviceId, @AppOpsManager.UidState int uidState,
- @AppOpsManager.OpFlags int flags, boolean triggeredByUidStateChange,
- boolean isStarted, @AppOpsManager.AttributionFlags int attributionFlags,
- int attributionChainId) throws RemoteException {
+ @Nullable String proxyDeviceId, @AppOpsManager.UidState int uidState,
+ @AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags int attributionFlags,
+ int attributionChainId, boolean triggeredByUidStateChange, boolean isStarted)
+ throws RemoteException {
if (!triggeredByUidStateChange && !parent.isRunning() && isStarted) {
mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
- parent.packageName, tag, proxyVirtualDeviceId, true, attributionFlags,
+ parent.packageName, tag, virtualDeviceId, true, attributionFlags,
attributionChainId);
}
@@ -233,9 +236,9 @@
InProgressStartOpEvent event = events.get(clientId);
if (event == null) {
event = mAppOpsService.mInProgressStartOpEventPool.acquire(startTime,
- SystemClock.elapsedRealtime(), clientId, tag, proxyVirtualDeviceId,
+ SystemClock.elapsedRealtime(), clientId, tag, virtualDeviceId,
PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
- proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags,
+ proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId, uidState, flags,
attributionFlags, attributionChainId);
events.put(clientId, event);
} else {
@@ -366,15 +369,14 @@
/**
* Create an event that will be started, if the op is unpaused.
*/
- public void createPaused(@NonNull IBinder clientId, int proxyUid,
- @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
- int proxyVirtualDeviceId, @AppOpsManager.UidState int uidState,
- @AppOpsManager.OpFlags int flags,
- @AppOpsManager.AttributionFlags int attributionFlags,
+ public void createPaused(@NonNull IBinder clientId, int virtualDeviceId,
+ int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
+ @Nullable String proxyDeviceId, @AppOpsManager.UidState int uidState,
+ @AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags int attributionFlags,
int attributionChainId) throws RemoteException {
- startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
- proxyVirtualDeviceId, uidState, flags, false, false,
- attributionFlags, attributionChainId);
+ startedOrPaused(clientId, virtualDeviceId, proxyUid, proxyPackageName, proxyAttributionTag,
+ proxyDeviceId, uidState, flags, attributionFlags, attributionChainId, false,
+ false);
}
/**
@@ -496,16 +498,16 @@
// Call started() to add a new start event object and then add the
// previously removed unfinished start counts back
if (proxy != null) {
- startedOrPaused(event.getClientId(), proxy.getUid(),
- proxy.getPackageName(), proxy.getAttributionTag(),
- event.getVirtualDeviceId(), newState, event.getFlags(),
- true, isRunning,
- event.getAttributionFlags(), event.getAttributionChainId());
+ startedOrPaused(event.getClientId(), event.getVirtualDeviceId(),
+ proxy.getUid(), proxy.getPackageName(), proxy.getAttributionTag(),
+ proxy.getDeviceId(), newState, event.getFlags(),
+ event.getAttributionFlags(), event.getAttributionChainId(), true,
+ isRunning);
} else {
- startedOrPaused(event.getClientId(), Process.INVALID_UID, null, null,
- event.getVirtualDeviceId(), newState, event.getFlags(), true,
- isRunning, event.getAttributionFlags(),
- event.getAttributionChainId());
+ startedOrPaused(event.getClientId(), event.getVirtualDeviceId(),
+ Process.INVALID_UID, null, null, null,
+ newState, event.getFlags(), event.getAttributionFlags(),
+ event.getAttributionChainId(), true, isRunning);
}
events = isRunning ? mInProgressEvents : mPausedInProgressEvents;
@@ -847,7 +849,8 @@
InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
@Nullable String attributionTag, int virtualDeviceId, @NonNull Runnable onDeath,
int proxyUid, @Nullable String proxyPackageName,
- @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
+ @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
+ @AppOpsManager.UidState int uidState,
@AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags
int attributionFlags, int attributionChainId) throws RemoteException {
@@ -856,7 +859,7 @@
AppOpsManager.OpEventProxyInfo proxyInfo = null;
if (proxyUid != Process.INVALID_UID) {
proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
- proxyAttributionTag, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ proxyAttributionTag, proxyDeviceId);
}
if (recycled != null) {
@@ -880,7 +883,8 @@
super(maxUnusedPooledObjects);
}
- AppOpsManager.OpEventProxyInfo acquire(@IntRange(from = 0) int uid,
+ AppOpsManager.OpEventProxyInfo acquire(
+ @IntRange(from = 0) int uid,
@Nullable String packageName,
@Nullable String attributionTag,
@Nullable String deviceId) {
@@ -890,7 +894,7 @@
return recycled;
}
- return new AppOpsManager.OpEventProxyInfo(uid, packageName, attributionTag);
+ return new AppOpsManager.OpEventProxyInfo(uid, packageName, attributionTag, deviceId);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java b/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java
index 3e8acee..7cf2d30 100644
--- a/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java
+++ b/services/core/java/com/android/server/biometrics/BiometricDanglingReceiver.java
@@ -16,6 +16,7 @@
package com.android.server.biometrics;
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
+import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
@@ -63,7 +64,7 @@
intentFilter.addAction(ACTION_FACE_RE_ENROLL_LAUNCH);
intentFilter.addAction(ACTION_FACE_RE_ENROLL_DISMISS);
}
- context.registerReceiver(this, intentFilter);
+ context.registerReceiver(this, intentFilter, Context.RECEIVER_NOT_EXPORTED);
}
@Override
@@ -84,7 +85,8 @@
}
private void launchBiometricEnrollActivity(Context context, String action) {
- context.sendBroadcast(new Intent(ACTION_CLOSE_SYSTEM_DIALOGS));
+ context.sendBroadcast(
+ new Intent(ACTION_CLOSE_SYSTEM_DIALOGS).setFlags(FLAG_RECEIVER_FOREGROUND));
final Intent intent = new Intent(action);
intent.setPackage(SETTINGS_PACKAGE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d7a7dd4..70a1014 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1442,6 +1442,9 @@
// If there's an offload session, we need to set the initial doze brightness before
// the offload session starts controlling the brightness.
+ // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy
+ // will be selected again, meaning that no new brightness will be sent to the hardware and
+ // the display will stay at the brightness level set by the offload session.
if (Float.isNaN(brightnessState) && mFlags.isDisplayOffloadEnabled()
&& Display.isDozeState(state) && mDisplayOffloadSession != null) {
if (mAutomaticBrightnessController != null
@@ -1459,6 +1462,15 @@
if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
brightnessState = clampScreenBrightness(rawBrightnessState);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
+
+ if (mAutomaticBrightnessController != null
+ && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
+ // Keep the brightness in the setting so that we can use it after the screen
+ // turns on, until a lux sample becomes available. We don't do this when
+ // auto-brightness is disabled - in that situation we still want to use
+ // the last brightness from when the screen was on.
+ updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index 2703a2c0..7e18d84 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -158,9 +158,11 @@
mTargetAddress, cecKeycodeAndParams), new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error != SendMessageResult.SUCCESS) {
+ // Disable System Audio Mode, if the AVR doesn't acknowledge
+ // a <User Control Pressed> message.
+ if (error == SendMessageResult.NACK) {
HdmiLogger.debug(
- "AVR did not respond to <User Control Pressed>");
+ "AVR did not acknowledge <User Control Pressed>");
localDevice().mService.setSystemAudioActivated(false);
}
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index a2f1942..17f8abe 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -335,6 +335,10 @@
if (Flags.reliableMessageDuplicateDetectionService()
&& didEventHappen(MESSAGE_DUPLICATION_PROBABILITY_PERCENT)) {
+ Log.i(TAG, "[TEST MODE] Duplicating message ("
+ + NUM_MESSAGES_TO_DUPLICATE
+ + " sends) with message sequence number: "
+ + message.getMessageSequenceNumber());
for (int i = 0; i < NUM_MESSAGES_TO_DUPLICATE; ++i) {
handleClientMessageCallback(contextHubId, hostEndpointId,
message, nanoappPermissions, messagePermissions);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 42ec1c3..61054a9 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -11271,6 +11271,9 @@
// Lifetime extended notifications don't need to alert on state change.
record.setPostSilently(true);
+ // We also set FLAG_ONLY_ALERT_ONCE to avoid the notification from HUN-ing again.
+ record.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
+
mHandler.post(new EnqueueNotificationRunnable(record.getUser().getIdentifier(),
record, isAppForeground,
mPostNotificationTrackerFactory.newTracker(null)));
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1309e44..41d6288 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2139,10 +2139,17 @@
continue;
}
+ ComponentName unflattenOriginalComponentName = ComponentName.unflattenFromString(
+ originalComponentName);
+ if (unflattenOriginalComponentName == null) {
+ Slog.d(TAG, "Incorrect component name from the attributes");
+ continue;
+ }
+
activityInfos.add(
new ArchiveState.ArchiveActivityInfo(
title,
- ComponentName.unflattenFromString(originalComponentName),
+ unflattenOriginalComponentName,
iconPath,
monochromeIconPath));
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 62f5b89..ba89fda 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -272,22 +272,23 @@
void setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray);
base::Result<std::unique_ptr<InputChannel>> createInputChannel(const std::string& name);
- base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
+ base::Result<std::unique_ptr<InputChannel>> createInputMonitor(ui::LogicalDisplayId displayId,
const std::string& name,
gui::Pid pid);
status_t removeInputChannel(const sp<IBinder>& connectionToken);
status_t pilferPointers(const sp<IBinder>& token);
- void displayRemoved(JNIEnv* env, int32_t displayId);
- void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
- void setFocusedDisplay(int32_t displayId);
+ void displayRemoved(JNIEnv* env, ui::LogicalDisplayId displayId);
+ void setFocusedApplication(JNIEnv* env, ui::LogicalDisplayId displayId,
+ jobject applicationHandleObj);
+ void setFocusedDisplay(ui::LogicalDisplayId displayId);
void setMinTimeBetweenUserActivityPokes(int64_t intervalMillis);
void setInputDispatchMode(bool enabled, bool frozen);
void setSystemUiLightsOut(bool lightsOut);
- void setPointerDisplayId(int32_t displayId);
+ void setPointerDisplayId(ui::LogicalDisplayId displayId);
int32_t getMousePointerSpeed();
void setPointerSpeed(int32_t speed);
- void setMousePointerAccelerationEnabled(int32_t displayId, bool enabled);
+ void setMousePointerAccelerationEnabled(ui::LogicalDisplayId displayId, bool enabled);
void setTouchpadPointerSpeed(int32_t speed);
void setTouchpadNaturalScrollingEnabled(bool enabled);
void setTouchpadTapToClickEnabled(bool enabled);
@@ -300,13 +301,13 @@
void reloadPointerIcons();
void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled);
bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
- int32_t displayId, DeviceId deviceId, int32_t pointerId,
+ ui::LogicalDisplayId displayId, DeviceId deviceId, int32_t pointerId,
const sp<IBinder>& inputToken);
- void setPointerIconVisibility(int32_t displayId, bool visible);
+ void setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible);
void setMotionClassifierEnabled(bool enabled);
std::optional<std::string> getBluetoothAddress(int32_t deviceId);
void setStylusButtonMotionEventsEnabled(bool enabled);
- FloatPoint getMouseCursorPosition(int32_t displayId);
+ FloatPoint getMouseCursorPosition(ui::LogicalDisplayId displayId);
void setStylusPointerIconEnabled(bool enabled);
void setInputMethodConnectionIsActive(bool isActive);
@@ -325,7 +326,7 @@
void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
bool isInputMethodConnectionActive() override;
std::optional<DisplayViewport> getPointerViewportForAssociatedDisplay(
- int32_t associatedDisplayId) override;
+ ui::LogicalDisplayId associatedDisplayId) override;
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -348,13 +349,15 @@
void notifyVibratorState(int32_t deviceId, bool isOn) override;
bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override;
void interceptKeyBeforeQueueing(const KeyEvent& keyEvent, uint32_t& policyFlags) override;
- void interceptMotionBeforeQueueing(int32_t displayId, uint32_t source, int32_t action,
- nsecs_t when, uint32_t& policyFlags) override;
+ void interceptMotionBeforeQueueing(ui::LogicalDisplayId displayId, uint32_t source,
+ int32_t action, nsecs_t when,
+ uint32_t& policyFlags) override;
nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, const KeyEvent& keyEvent,
uint32_t policyFlags) override;
std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent& keyEvent,
uint32_t policyFlags) override;
- void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override;
+ void pokeUserActivity(nsecs_t eventTime, int32_t eventType,
+ ui::LogicalDisplayId displayId) override;
void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
void setPointerCapture(const PointerCaptureRequest& request) override;
void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
@@ -363,11 +366,13 @@
/* --- PointerControllerPolicyInterface implementation --- */
- virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId);
- virtual void loadPointerResources(PointerResources* outResources, int32_t displayId);
+ virtual void loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId displayId);
+ virtual void loadPointerResources(PointerResources* outResources,
+ ui::LogicalDisplayId displayId);
virtual void loadAdditionalMouseResources(
std::map<PointerIconStyle, SpriteIcon>* outResources,
- std::map<PointerIconStyle, PointerAnimation>* outAnimationResources, int32_t displayId);
+ std::map<PointerIconStyle, PointerAnimation>* outAnimationResources,
+ ui::LogicalDisplayId displayId);
virtual PointerIconStyle getDefaultPointerIconId();
virtual PointerIconStyle getDefaultStylusIconId();
virtual PointerIconStyle getCustomPointerIconId();
@@ -375,7 +380,8 @@
/* --- PointerChoreographerPolicyInterface implementation --- */
std::shared_ptr<PointerControllerInterface> createPointerController(
PointerControllerInterface::ControllerType type) override;
- void notifyPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) override;
+ void notifyPointerDisplayIdChanged(ui::LogicalDisplayId displayId,
+ const FloatPoint& position) override;
/* --- InputFilterPolicyInterface implementation --- */
void notifyStickyModifierStateChanged(uint32_t modifierState,
@@ -399,7 +405,7 @@
int32_t pointerSpeed{0};
// Displays on which its associated mice will have pointer acceleration disabled.
- std::set<int32_t> displaysWithMousePointerAccelerationDisabled{};
+ std::set<ui::LogicalDisplayId> displaysWithMousePointerAccelerationDisabled{};
// True if pointer gestures are enabled.
bool pointerGesturesEnabled{true};
@@ -417,7 +423,7 @@
std::set<int32_t> disabledInputDevices{};
// Associated Pointer controller display.
- int32_t pointerDisplayId{ADISPLAY_ID_DEFAULT};
+ ui::LogicalDisplayId pointerDisplayId{ui::ADISPLAY_ID_DEFAULT};
// True if stylus button reporting through motion events is enabled.
bool stylusButtonMotionEventsEnabled{true};
@@ -450,7 +456,7 @@
void updateInactivityTimeoutLocked();
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
void ensureSpriteControllerLocked();
- sp<SurfaceControl> getParentSurfaceForPointers(int displayId);
+ sp<SurfaceControl> getParentSurfaceForPointers(ui::LogicalDisplayId displayId);
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
template <typename T>
std::unordered_map<std::string, T> readMapFromInterleavedJavaArray(
@@ -459,7 +465,7 @@
void forEachPointerControllerLocked(std::function<void(PointerController&)> apply)
REQUIRES(mLock);
- PointerIcon loadPointerIcon(JNIEnv* env, int32_t displayId, PointerIconStyle type);
+ PointerIcon loadPointerIcon(JNIEnv* env, ui::LogicalDisplayId displayId, PointerIconStyle type);
static inline JNIEnv* jniEnv() { return AndroidRuntime::getJNIEnv(); }
};
@@ -490,7 +496,9 @@
toString(mLocked.systemUiLightsOut));
dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed);
dump += StringPrintf(INDENT "Display with Mouse Pointer Acceleration Disabled: %s\n",
- dumpSet(mLocked.displaysWithMousePointerAccelerationDisabled).c_str());
+ dumpSet(mLocked.displaysWithMousePointerAccelerationDisabled,
+ streamableToString)
+ .c_str());
dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n",
toString(mLocked.pointerGesturesEnabled));
dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
@@ -552,7 +560,7 @@
}
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
- int32_t displayId, const std::string& name, gui::Pid pid) {
+ ui::LogicalDisplayId displayId, const std::string& name, gui::Pid pid) {
ATRACE_CALL();
return mInputManager->getDispatcher().createInputMonitor(displayId, name, pid);
}
@@ -735,7 +743,7 @@
}
}
-PointerIcon NativeInputManager::loadPointerIcon(JNIEnv* env, int32_t displayId,
+PointerIcon NativeInputManager::loadPointerIcon(JNIEnv* env, ui::LogicalDisplayId displayId,
PointerIconStyle type) {
if (type == PointerIconStyle::TYPE_CUSTOM) {
LOG(FATAL) << __func__ << ": Cannot load non-system icon type";
@@ -766,7 +774,7 @@
return pc;
}
-void NativeInputManager::notifyPointerDisplayIdChanged(int32_t pointerDisplayId,
+void NativeInputManager::notifyPointerDisplayIdChanged(ui::LogicalDisplayId pointerDisplayId,
const FloatPoint& position) {
// Notify the Reader so that devices can be reconfigured.
{ // acquire lock
@@ -775,7 +783,7 @@
return;
}
mLocked.pointerDisplayId = pointerDisplayId;
- ALOGI("%s: pointer displayId set to: %d", __func__, pointerDisplayId);
+ ALOGI("%s: pointer displayId set to: %s", __func__, pointerDisplayId.toString().c_str());
} // release lock
mInputManager->getReader().requestRefreshConfiguration(
InputReaderConfiguration::Change::DISPLAY_INFO);
@@ -795,7 +803,7 @@
checkAndClearExceptionFromCallback(env, "notifyStickyModifierStateChanged");
}
-sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(int displayId) {
+sp<SurfaceControl> NativeInputManager::getParentSurfaceForPointers(ui::LogicalDisplayId displayId) {
JNIEnv* env = jniEnv();
jlong nativeSurfaceControlPtr =
env->CallLongMethod(mServiceObj, gServiceClassInfo.getParentSurfaceForPointers,
@@ -817,9 +825,10 @@
layer = -1;
}
mLocked.spriteController =
- std::make_shared<SpriteController>(mLooper, layer, [this](int displayId) {
- return getParentSurfaceForPointers(displayId);
- });
+ std::make_shared<SpriteController>(mLooper, layer,
+ [this](ui::LogicalDisplayId displayId) {
+ return getParentSurfaceForPointers(displayId);
+ });
// The SpriteController needs to be shared pointer because the handler callback needs to hold
// a weak reference so that we can avoid racy conditions when the controller is being destroyed.
mLocked.spriteController->setHandlerController(mLocked.spriteController);
@@ -1021,8 +1030,7 @@
jobject tokenObj = javaObjectForIBinder(env, token);
if (tokenObj) {
- env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputChannelBroken,
- tokenObj);
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputChannelBroken, tokenObj);
checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken");
}
}
@@ -1108,12 +1116,12 @@
checkAndClearExceptionFromCallback(env, "notifyVibratorState");
}
-void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {
+void NativeInputManager::displayRemoved(JNIEnv* env, ui::LogicalDisplayId displayId) {
mInputManager->getDispatcher().displayRemoved(displayId);
}
-void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
- jobject applicationHandleObj) {
+void NativeInputManager::setFocusedApplication(JNIEnv* env, ui::LogicalDisplayId displayId,
+ jobject applicationHandleObj) {
if (!applicationHandleObj) {
return;
}
@@ -1123,7 +1131,7 @@
mInputManager->getDispatcher().setFocusedApplication(displayId, applicationHandle);
}
-void NativeInputManager::setFocusedDisplay(int32_t displayId) {
+void NativeInputManager::setFocusedDisplay(ui::LogicalDisplayId displayId) {
mInputManager->getDispatcher().setFocusedDisplay(displayId);
}
@@ -1151,7 +1159,7 @@
});
}
-void NativeInputManager::setPointerDisplayId(int32_t displayId) {
+void NativeInputManager::setPointerDisplayId(ui::LogicalDisplayId displayId) {
mInputManager->getChoreographer().setDefaultMouseDisplayId(displayId);
}
@@ -1176,7 +1184,8 @@
InputReaderConfiguration::Change::POINTER_SPEED);
}
-void NativeInputManager::setMousePointerAccelerationEnabled(int32_t displayId, bool enabled) {
+void NativeInputManager::setMousePointerAccelerationEnabled(ui::LogicalDisplayId displayId,
+ bool enabled) {
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -1186,8 +1195,8 @@
return;
}
- ALOGI("Setting mouse pointer acceleration to %s on display %d", toString(enabled),
- displayId);
+ ALOGI("Setting mouse pointer acceleration to %s on display %s", toString(enabled),
+ displayId.toString().c_str());
if (enabled) {
mLocked.displaysWithMousePointerAccelerationDisabled.erase(displayId);
} else {
@@ -1326,8 +1335,9 @@
}
bool NativeInputManager::setPointerIcon(
- std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId,
- DeviceId deviceId, int32_t pointerId, const sp<IBinder>& inputToken) {
+ std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
+ ui::LogicalDisplayId displayId, DeviceId deviceId, int32_t pointerId,
+ const sp<IBinder>& inputToken) {
if (!mInputManager->getDispatcher().isPointerInWindow(inputToken, displayId, deviceId,
pointerId)) {
LOG(WARNING) << "Attempted to change the pointer icon for deviceId " << deviceId
@@ -1339,7 +1349,7 @@
return mInputManager->getChoreographer().setPointerIcon(std::move(icon), displayId, deviceId);
}
-void NativeInputManager::setPointerIconVisibility(int32_t displayId, bool visible) {
+void NativeInputManager::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
mInputManager->getChoreographer().setPointerIconVisibility(displayId, visible);
}
@@ -1394,7 +1404,7 @@
}
std::optional<DisplayViewport> NativeInputManager::getPointerViewportForAssociatedDisplay(
- int32_t associatedDisplayId) {
+ ui::LogicalDisplayId associatedDisplayId) {
return mInputManager->getChoreographer().getViewportForPointerDevice(associatedDisplayId);
}
@@ -1469,9 +1479,9 @@
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
-void NativeInputManager::interceptMotionBeforeQueueing(int32_t displayId, uint32_t source,
- int32_t action, nsecs_t when,
- uint32_t& policyFlags) {
+void NativeInputManager::interceptMotionBeforeQueueing(ui::LogicalDisplayId displayId,
+ uint32_t source, int32_t action,
+ nsecs_t when, uint32_t& policyFlags) {
ATRACE_CALL();
// Policy:
// - Ignore untrusted events and pass them along.
@@ -1590,7 +1600,8 @@
return fallbackEvent;
}
-void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) {
+void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType,
+ ui::LogicalDisplayId displayId) {
ATRACE_CALL();
android_server_PowerManagerService_userActivity(eventTime, eventType, displayId);
}
@@ -1621,13 +1632,14 @@
InputReaderConfiguration::Change::POINTER_CAPTURE);
}
-void NativeInputManager::loadPointerIcon(SpriteIcon* icon, int32_t displayId) {
+void NativeInputManager::loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId displayId) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
*icon = toSpriteIcon(loadPointerIcon(env, displayId, PointerIconStyle::TYPE_ARROW));
}
-void NativeInputManager::loadPointerResources(PointerResources* outResources, int32_t displayId) {
+void NativeInputManager::loadPointerResources(PointerResources* outResources,
+ ui::LogicalDisplayId displayId) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
@@ -1641,7 +1653,8 @@
void NativeInputManager::loadAdditionalMouseResources(
std::map<PointerIconStyle, SpriteIcon>* outResources,
- std::map<PointerIconStyle, PointerAnimation>* outAnimationResources, int32_t displayId) {
+ std::map<PointerIconStyle, PointerAnimation>* outAnimationResources,
+ ui::LogicalDisplayId displayId) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
@@ -1708,7 +1721,7 @@
InputReaderConfiguration::Change::STYLUS_BUTTON_REPORTING);
}
-FloatPoint NativeInputManager::getMouseCursorPosition(int32_t displayId) {
+FloatPoint NativeInputManager::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
return mInputManager->getChoreographer().getMouseCursorPosition(displayId);
}
@@ -1874,7 +1887,7 @@
jstring nameObj, jint pid) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- if (displayId == ADISPLAY_ID_NONE) {
+ if (displayId == ui::ADISPLAY_ID_NONE.val()) {
std::string message = "InputChannel used as a monitor must be associated with a display";
jniThrowRuntimeException(env, message.c_str());
return nullptr;
@@ -1884,7 +1897,7 @@
std::string name = nameChars.c_str();
base::Result<std::unique_ptr<InputChannel>> inputChannel =
- im->createInputMonitor(displayId, name, gui::Pid{pid});
+ im->createInputMonitor(ui::LogicalDisplayId{displayId}, name, gui::Pid{pid});
if (!inputChannel.ok()) {
std::string message = inputChannel.error().message();
@@ -1931,7 +1944,8 @@
return im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode, gui::Pid{pid},
gui::Uid{static_cast<uid_t>(uid)},
- hasPermission, displayId);
+ hasPermission,
+ ui::LogicalDisplayId{displayId});
}
static void nativeSetMaximumObscuringOpacityForTouch(JNIEnv* env, jobject nativeImplObj,
@@ -2023,20 +2037,20 @@
static void nativeDisplayRemoved(JNIEnv* env, jobject nativeImplObj, jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->displayRemoved(env, displayId);
+ im->displayRemoved(env, ui::LogicalDisplayId{displayId});
}
static void nativeSetFocusedApplication(JNIEnv* env, jobject nativeImplObj, jint displayId,
jobject applicationHandleObj) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->setFocusedApplication(env, displayId, applicationHandleObj);
+ im->setFocusedApplication(env, ui::LogicalDisplayId{displayId}, applicationHandleObj);
}
static void nativeSetFocusedDisplay(JNIEnv* env, jobject nativeImplObj, jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->setFocusedDisplay(displayId);
+ im->setFocusedDisplay(ui::LogicalDisplayId{displayId});
}
static void nativeSetUserActivityPokeInterval(JNIEnv* env, jobject nativeImplObj,
@@ -2092,8 +2106,8 @@
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
if (im->getInputManager()->getDispatcher().transferTouchOnDisplay(destChannelToken,
- static_cast<int32_t>(
- displayId))) {
+ ui::LogicalDisplayId{
+ displayId})) {
return JNI_TRUE;
} else {
return JNI_FALSE;
@@ -2116,7 +2130,7 @@
jint displayId, jboolean enabled) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->setMousePointerAccelerationEnabled(displayId, enabled);
+ im->setMousePointerAccelerationEnabled(ui::LogicalDisplayId{displayId}, enabled);
}
static void nativeSetTouchpadPointerSpeed(JNIEnv* env, jobject nativeImplObj, jint speed) {
@@ -2486,7 +2500,7 @@
icon = pointerIcon.style;
}
- return im->setPointerIcon(std::move(icon), displayId, deviceId, pointerId,
+ return im->setPointerIcon(std::move(icon), ui::LogicalDisplayId{displayId}, deviceId, pointerId,
ibinderForJavaObject(env, inputTokenObj));
}
@@ -2494,13 +2508,14 @@
jboolean visible) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->setPointerIconVisibility(displayId, visible);
+ im->setPointerIconVisibility(ui::LogicalDisplayId{displayId}, visible);
}
static jboolean nativeCanDispatchToDisplay(JNIEnv* env, jobject nativeImplObj, jint deviceId,
jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- return im->getInputManager()->getReader().canDispatchToDisplay(deviceId, displayId);
+ return im->getInputManager()->getReader().canDispatchToDisplay(deviceId,
+ ui::LogicalDisplayId{displayId});
}
static void nativeNotifyPortAssociationsChanged(JNIEnv* env, jobject nativeImplObj) {
@@ -2512,8 +2527,9 @@
static void nativeSetDisplayEligibilityForPointerCapture(JNIEnv* env, jobject nativeImplObj,
jint displayId, jboolean isEligible) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->getInputManager()->getDispatcher().setDisplayEligibilityForPointerCapture(displayId,
- isEligible);
+ im->getInputManager()
+ ->getDispatcher()
+ .setDisplayEligibilityForPointerCapture(ui::LogicalDisplayId{displayId}, isEligible);
}
static void nativeChangeUniqueIdAssociation(JNIEnv* env, jobject nativeImplObj) {
@@ -2649,7 +2665,7 @@
static void nativeSetPointerDisplayId(JNIEnv* env, jobject nativeImplObj, jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- im->setPointerDisplayId(displayId);
+ im->setPointerDisplayId(ui::LogicalDisplayId{displayId});
}
static jstring nativeGetBluetoothAddress(JNIEnv* env, jobject nativeImplObj, jint deviceId) {
@@ -2667,7 +2683,7 @@
static jfloatArray nativeGetMouseCursorPosition(JNIEnv* env, jobject nativeImplObj,
jint displayId) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
- const auto p = im->getMouseCursorPosition(displayId);
+ const auto p = im->getMouseCursorPosition(ui::LogicalDisplayId{displayId});
const std::array<float, 2> arr = {{p.x, p.y}};
jfloatArray outArr = env->NewFloatArray(2);
env->SetFloatArrayRegion(outArr, 0, arr.size(), arr.data());
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index d0b290c..0733968 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -99,7 +99,7 @@
}
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType,
- int32_t displayId) {
+ ui::LogicalDisplayId displayId) {
if (gPowerManagerServiceObj) {
// Throttle calls into user activity by event type.
// We're a little conservative about argument checking here in case the caller
@@ -124,8 +124,8 @@
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(gPowerManagerServiceObj,
- gPowerManagerServiceClassInfo.userActivityFromNative,
- nanoseconds_to_milliseconds(eventTime), eventType, displayId, 0);
+ gPowerManagerServiceClassInfo.userActivityFromNative,
+ nanoseconds_to_milliseconds(eventTime), eventType, displayId.val(), 0);
checkAndClearExceptionFromCallback(env, "userActivityFromNative");
}
}
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index 36aaceb..ed7fa7c 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -19,6 +19,7 @@
#include <nativehelper/JNIHelp.h>
#include <powermanager/PowerManager.h>
+#include <ui/LogicalDisplayId.h>
#include <utils/Timers.h>
#include "jni.h"
@@ -26,7 +27,7 @@
namespace android {
extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType,
- int32_t displayId);
+ ui::LogicalDisplayId displayId);
} // namespace android
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 4bf3ff4..09eef45 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -196,19 +196,27 @@
Binder.withCleanCallingIdentity(() -> {
PackageManagerInternal pmi =
LocalServices.getService(PackageManagerInternal.class);
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+
pmi.setOwnerProtectedPackages(userId,
packages == null ? null : packages.stream().toList());
LocalServices.getService(UsageStatsManagerInternal.class)
.setAdminProtectedPackages(
packages == null ? null : new ArraySet<>(packages), userId);
- if (Flags.disallowUserControlBgUsageFix()) {
- if (packages == null) {
- return;
+ if (packages == null || packages.isEmpty()) {
+ return;
+ }
+
+ for (int user : resolveUsers(userId)) {
+ if (Flags.disallowUserControlBgUsageFix()) {
+ setBgUsageAppOp(packages, pmi, user, appOpsManager);
}
- final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
- resolveUsers(userId).forEach(
- user -> setBgUsageAppOp(packages, pmi, user, appOpsManager));
+ if (Flags.disallowUserControlStoppedStateFix()) {
+ for (String packageName : packages) {
+ pmi.setPackageStoppedState(packageName, false, user);
+ }
+ }
}
});
return true;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 80f38eb..e5685c7 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1790,6 +1790,7 @@
verify(mHolder.animator).animateTo(eq(brightness),
/* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
/* ignoreAnimationLimits= */ anyBoolean());
+ verify(mHolder.brightnessSetting).setBrightness(brightness);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java
new file mode 100644
index 0000000..7f2327aa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsDeviceAwareServiceTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2024 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.appop;
+
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.companion.virtual.VirtualDeviceManager;
+import android.companion.virtual.VirtualDeviceParams;
+import android.content.AttributionSource;
+import android.os.Process;
+import android.permission.PermissionManager;
+import android.permission.flags.Flags;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.testing.TestableContext;
+import android.virtualdevice.cts.common.VirtualDeviceRule;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Objects;
+
+@RunWith(AndroidJUnit4.class)
+public class AppOpsDeviceAwareServiceTest {
+
+ @Rule
+ public final TestableContext mContext =
+ new TestableContext(InstrumentationRegistry.getInstrumentation().getTargetContext());
+
+ @Rule
+ public VirtualDeviceRule virtualDeviceRule =
+ VirtualDeviceRule.withAdditionalPermissions(
+ Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+ Manifest.permission.CREATE_VIRTUAL_DEVICE,
+ Manifest.permission.GET_APP_OPS_STATS);
+
+ private static final String ATTRIBUTION_TAG_1 = "attributionTag1";
+ private static final String ATTRIBUTION_TAG_2 = "attributionTag2";
+ private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ private final PermissionManager mPermissionManager =
+ mContext.getSystemService(PermissionManager.class);
+
+ private VirtualDeviceManager.VirtualDevice mVirtualDevice;
+
+ @Before
+ public void setUp() {
+ mVirtualDevice =
+ virtualDeviceRule.createManagedVirtualDevice(
+ new VirtualDeviceParams.Builder()
+ .setDevicePolicy(POLICY_TYPE_CAMERA, DEVICE_POLICY_CUSTOM)
+ .build());
+
+ mPermissionManager.grantRuntimePermission(
+ mContext.getOpPackageName(),
+ Manifest.permission.CAMERA,
+ mVirtualDevice.getPersistentDeviceId());
+
+ mPermissionManager.grantRuntimePermission(
+ mContext.getOpPackageName(),
+ Manifest.permission.CAMERA,
+ VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_ID_IN_OP_PROXY_INFO_ENABLED)
+ @Test
+ public void noteProxyOp_proxyAppOnDefaultDevice() {
+ AppOpsManager.OpEventProxyInfo proxyInfo =
+ noteProxyOpWithDeviceId(TestableContext.DEVICE_ID_DEFAULT);
+ assertThat(proxyInfo.getDeviceId())
+ .isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_DEVICE_ID_IN_OP_PROXY_INFO_ENABLED)
+ @Test
+ public void noteProxyOp_proxyAppOnRemoteDevice() {
+ AppOpsManager.OpEventProxyInfo proxyInfo =
+ noteProxyOpWithDeviceId(mVirtualDevice.getDeviceId());
+ assertThat(proxyInfo.getDeviceId()).isEqualTo(mVirtualDevice.getPersistentDeviceId());
+ }
+
+ private AppOpsManager.OpEventProxyInfo noteProxyOpWithDeviceId(int proxyAppDeviceId) {
+ AttributionSource proxiedAttributionSource =
+ new AttributionSource.Builder(Process.myUid())
+ .setPackageName(mContext.getOpPackageName())
+ .setAttributionTag(ATTRIBUTION_TAG_2)
+ .setDeviceId(mVirtualDevice.getDeviceId())
+ .build();
+
+ AttributionSource proxyAttributionSource =
+ new AttributionSource.Builder(Process.myUid())
+ .setPackageName(mContext.getOpPackageName())
+ .setAttributionTag(ATTRIBUTION_TAG_1)
+ .setDeviceId(proxyAppDeviceId)
+ .setNextAttributionSource(proxiedAttributionSource)
+ .build();
+
+ int mode = mAppOpsManager.noteProxyOp(OP_CAMERA, proxyAttributionSource, null, false);
+ assertThat(mode).isEqualTo(AppOpsManager.MODE_ALLOWED);
+
+ List<AppOpsManager.PackageOps> packagesOps =
+ mAppOpsManager.getPackagesForOps(
+ new String[] {AppOpsManager.OPSTR_CAMERA},
+ mVirtualDevice.getPersistentDeviceId());
+
+ AppOpsManager.PackageOps packageOps =
+ packagesOps.stream()
+ .filter(
+ pkg ->
+ Objects.equals(
+ pkg.getPackageName(), mContext.getOpPackageName()))
+ .findFirst()
+ .orElseThrow();
+
+ AppOpsManager.OpEntry opEntry =
+ packageOps.getOps().stream()
+ .filter(op -> op.getOp() == OP_CAMERA)
+ .findFirst()
+ .orElseThrow();
+
+ return opEntry.getLastProxyInfo(OP_FLAGS_ALL_TRUSTED);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java
index 0716a5c..3698d6f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricDanglingReceiverTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
+import android.content.Context;
import android.content.Intent;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.UserHandle;
@@ -75,13 +76,15 @@
@Test
public void testFingerprintRegisterReceiver() {
initBroadcastReceiver(BiometricsProtoEnums.MODALITY_FINGERPRINT);
- verify(mContext).registerReceiver(eq(mBiometricDanglingReceiver), any());
+ verify(mContext).registerReceiver(eq(mBiometricDanglingReceiver), any(),
+ eq(Context.RECEIVER_NOT_EXPORTED));
}
@Test
public void testFaceRegisterReceiver() {
initBroadcastReceiver(BiometricsProtoEnums.MODALITY_FACE);
- verify(mContext).registerReceiver(eq(mBiometricDanglingReceiver), any());
+ verify(mContext).registerReceiver(eq(mBiometricDanglingReceiver), any(),
+ eq(Context.RECEIVER_NOT_EXPORTED));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 5e2fe6a..2d672b8 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5969,6 +5969,8 @@
assertThat(captor.getValue().getNotification().flags
& FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
+ assertThat(captor.getValue().getNotification().flags
+ & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
assertThat(captor.getValue().shouldPostSilently()).isTrue();
}
@@ -8798,6 +8800,8 @@
assertThat(captor.getValue().getNotification().flags
& FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(
FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY);
+ assertThat(captor.getValue().getNotification().flags
+ & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE);
assertThat(captor.getValue().shouldPostSilently()).isTrue();
}