diff options
59 files changed, 1367 insertions, 443 deletions
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index c72c4c8feb71..5567c085d205 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -1356,7 +1356,7 @@ public class PropertyInvalidatedCache<Query, Result> { @Nullable QueryHandler<Query, Result> computer) { mPropertyName = createPropertyName(args.mModule, args.mApi); mCacheName = cacheName; - mCacheNullResults = args.mCacheNulls && Flags.picCacheNulls(); + mCacheNullResults = args.mCacheNulls; mNonce = getNonceHandler(mPropertyName); mMaxEntries = args.mMaxEntries; mCache = new CacheMap<>(args.mIsolateUids, args.mTestMode); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4b579e7db9f8..219b20428d7a 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2322,10 +2322,10 @@ public class PackageParser { } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) { sa = res.obtainAttributes(parser, - com.android.internal.R.styleable.AndroidManifestOriginalPackage); + com.android.internal.R.styleable.AndroidManifestAdoptPermissions); String name = sa.getNonConfigurationString( - com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); + com.android.internal.R.styleable.AndroidManifestAdoptPermissions_name, 0); sa.recycle(); diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index aaa78aa0916a..313bad50e88e 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -196,4 +196,11 @@ flag { namespace: "input" description: "Allows the user to disable pointer acceleration for mouse and touchpads." bug: "349006858" -}
\ No newline at end of file +} + +flag { + name: "mouse_scrolling_acceleration" + namespace: "input" + description: "Allows the user to disable input scrolling acceleration for mouse." + bug: "383555305" +} diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index 4a14a8d0faf8..56a089aff78a 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -21,11 +21,13 @@ import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.os.SessionCreationConfig; -import android.hardware.power.CpuHeadroomResult; + import android.hardware.power.ChannelConfig; +import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; +import android.hardware.power.SupportInfo; /** {@hide} */ interface IHintManager { @@ -40,11 +42,6 @@ interface IHintManager { IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, in SessionCreationConfig creationConfig, out SessionConfig config); - /** - * Get preferred rate limit in nanoseconds. - */ - long getHintSessionPreferredRate(); - void setHintSessionThreads(in IHintSession hintSession, in int[] tids); int[] getHintSessionThreadIds(in IHintSession hintSession); @@ -61,13 +58,28 @@ interface IHintManager { long getGpuHeadroomMinIntervalMillis(); /** - * Get Maximum number of graphics pipeline threads allowed per-app. - */ - int getMaxGraphicsPipelineThreadsCount(); - - /** * Used by the JNI to pass an interface to the SessionManager; * for internal use only. */ oneway void passSessionManagerBinder(in IBinder sessionManager); + + parcelable HintManagerClientData { + int powerHalVersion; + int maxGraphicsPipelineThreads; + long preferredRateNanos; + SupportInfo supportInfo; + } + + interface IHintManagerClient { + /** + * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan. + */ + oneway void receiveChannelConfig(in ChannelConfig config); + } + + /** + * Set up an ADPF client, receiving a remote client binder interface and + * passing back a bundle of support and configuration information. + */ + HintManagerClientData registerClient(in IHintManagerClient client); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b9f2cfcd8ca8..132805da7c94 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -4197,12 +4197,21 @@ public class UserManager { android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) private boolean hasUserRestrictionForUser(@NonNull @UserRestrictionKey String restrictionKey, - @UserIdInt int userId) { - try { - return mService.hasUserRestriction(restrictionKey, userId); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + @NonNull @UserIdInt int userId) { + return getUserRestrictionFromQuery(new Pair(restrictionKey, userId)); + } + + /** @hide */ + @CachedProperty() + private boolean getUserRestrictionFromQuery(@NonNull Pair<String, Integer> restrictionPerUser) { + return UserManagerCache.getUserRestrictionFromQuery( + (Pair<String, Integer> q) -> mService.hasUserRestriction(q.first, q.second), + restrictionPerUser); + } + + /** @hide */ + public static final void invalidateUserRestriction() { + UserManagerCache.invalidateUserRestrictionFromQuery(); } /** @@ -6477,6 +6486,7 @@ public class UserManager { UserManagerCache.invalidateProfileParent(); } invalidateEnabledProfileIds(); + invalidateUserRestriction(); } /** diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 6caa20e29c17..1707e61b28e4 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -175,13 +175,6 @@ flag { } flag { - name: "enable_a11y_metrics" - namespace: "lse_desktop_experience" - description: "Whether to enable log collection for a11y actions in desktop windowing mode" - bug: "341319597" -} - -flag { name: "enable_caption_compat_inset_force_consumption" namespace: "lse_desktop_experience" description: "Enables force-consumption of caption bar insets for immersive apps in freeform" diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index c160b42f8b6b..5c08dc6be1a0 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -3133,9 +3133,9 @@ public class ParsingPackageUtils { private static ParseResult<ParsingPackage> parseAdoptPermissions(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser) { - TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage); + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAdoptPermissions); try { - String name = nonConfigString(0, R.styleable.AndroidManifestOriginalPackage_name, sa); + String name = nonConfigString(0, R.styleable.AndroidManifestAdoptPermissions_name, sa); if (name != null) { pkg.addAdoptPermission(name); } diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java index 70dd10f2c371..5fa8125ced10 100644 --- a/core/java/com/android/server/pm/pkg/AndroidPackage.java +++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java @@ -722,7 +722,7 @@ public interface AndroidPackage { * The names of packages to adopt ownership of permissions from, parsed under {@link * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}. * - * @see R.styleable#AndroidManifestOriginalPackage_name + * @see R.styleable#AndroidManifestAdoptPermissions_name * @hide */ @NonNull diff --git a/core/jni/android_view_SurfaceControlActivePictureListener.cpp b/core/jni/android_view_SurfaceControlActivePictureListener.cpp index 91849c1514cc..15132db2a569 100644 --- a/core/jni/android_view_SurfaceControlActivePictureListener.cpp +++ b/core/jni/android_view_SurfaceControlActivePictureListener.cpp @@ -106,12 +106,11 @@ struct SurfaceControlActivePictureListener : public gui::BnActivePictureListener } status_t startListening() { - // TODO(b/337330263): Make SF multiple-listener capable - return SurfaceComposerClient::setActivePictureListener(this); + return SurfaceComposerClient::addActivePictureListener(this); } status_t stopListening() { - return SurfaceComposerClient::setActivePictureListener(nullptr); + return SurfaceComposerClient::removeActivePictureListener(this); } protected: diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index a06d184fd147..8c6fd1dfc47e 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2892,6 +2892,17 @@ <attr name="name" /> </declare-styleable> + <!-- Private tag to declare the package name that the permissions of this package + is based on. Only used for packages installed in the system image. If + given, the permissions from the other package will be propagated into the + new package. + + <p>This appears as a child tag of the root + {@link #AndroidManifest manifest} tag. --> + <declare-styleable name="AndroidManifestAdoptPermissions" parent="AndroidManifest"> + <attr name="name" /> + </declare-styleable> + <!-- The <code>processes</code> tag specifies the processes the application will run code in and optionally characteristics of those processes. This tag is optional; if not specified, components will simply run in the processes they specify. If supplied, diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 20ae29659783..666f1cf39fe3 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -506,4 +506,10 @@ <!-- Whether to allow TN scanning during satellite session. --> <bool name="config_satellite_allow_tn_scanning_during_satellite_session">true</bool> <java-symbol type="bool" name="config_satellite_allow_tn_scanning_during_satellite_session" /> + + <!-- List of integer tag Ids representing VZW satellite coverage. --> + <integer-array name="config_verizon_satellite_enabled_tagids"> + </integer-array> + <java-symbol type="array" name="config_verizon_satellite_enabled_tagids" /> + </resources> diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java index bd273377984d..e9dfdd826572 100644 --- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java +++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java @@ -16,7 +16,6 @@ package android.app; -import static android.app.Flags.FLAG_PIC_CACHE_NULLS; import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID; import static android.app.PropertyInvalidatedCache.NONCE_UNSET; import static android.app.PropertyInvalidatedCache.MODULE_BLUETOOTH; @@ -711,7 +710,6 @@ public class PropertyInvalidatedCacheTests { } } - @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS) @Test public void testCachingNulls() { TestCache cache = new TestCache(new Args(MODULE_TEST) diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java index bb8356f7aebe..fc04e6438ac6 100644 --- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java +++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java @@ -16,7 +16,6 @@ package android.os; -import static android.app.Flags.FLAG_PIC_CACHE_NULLS; import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID; import static org.junit.Assert.assertEquals; @@ -511,7 +510,6 @@ public class IpcDataCacheTest { IpcDataCache.setTestMode(true); } - @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS) @Test public void testCachingNulls() { IpcDataCache.Config c = diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 2c542ec31a20..2398e7134b34 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -679,4 +679,8 @@ applications that come with the platform <permission name="android.permission.BATTERY_STATS"/> <permission name="android.permission.ENTER_TRADE_IN_MODE"/> </privapp-permissions> + + <privapp-permissions package="com.android.wm.shell"> + <permission name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" /> + </privapp-permissions> </permissions> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 0b919668f7fe..792f5cad3418 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -468,7 +468,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT case MotionEvent.ACTION_DOWN: { mDragPointerId = e.getPointerId(0); mDragPositioningCallback.onDragPositioningStart( - 0 /* ctrlType */, e.getRawX(0), e.getRawY(0)); + 0 /* ctrlType */, e.getDisplayId(), e.getRawX(0), e.getRawY(0)); mIsDragging = false; return false; } @@ -481,6 +481,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT if (decoration.isHandlingDragResize()) break; final int dragPointerIdx = e.findPointerIndex(mDragPointerId); mDragPositioningCallback.onDragPositioningMove( + e.getDisplayId(), e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); mIsDragging = true; return true; @@ -492,6 +493,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT } final int dragPointerIdx = e.findPointerIndex(mDragPointerId); final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd( + e.getDisplayId(), e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); DragPositioningCallbackUtility.snapTaskBoundsIfNecessary(newTaskBounds, mWindowDecorByTaskId.get(mTaskId).calculateValidDragArea()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 5a05861c3a88..7928e5ed4188 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -1140,7 +1140,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, if (dragAllowed) { mDragPointerId = e.getPointerId(0); final Rect initialBounds = mDragPositioningCallback.onDragPositioningStart( - 0 /* ctrlType */, e.getRawX(0), + 0 /* ctrlType */, e.getDisplayId(), e.getRawX(0), e.getRawY(0)); updateDragStatus(e.getActionMasked()); mOnDragStartInitialBounds.set(initialBounds); @@ -1161,6 +1161,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } final int dragPointerIdx = e.findPointerIndex(mDragPointerId); final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningMove( + e.getDisplayId(), e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); mDesktopTasksController.onDragPositioningMove(taskInfo, decoration.mTaskSurface, @@ -1191,6 +1192,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, (int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)), (int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx))); final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd( + e.getDisplayId(), e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); // Tasks bounds haven't actually been updated (only its leash), so pass to // DesktopTasksController to allow secondary transformations (i.e. snap resizing diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java index 421ffd929fb2..3eebdb048f0d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java @@ -41,25 +41,30 @@ public interface DragPositioningCallback { * * @param ctrlType {@link CtrlType} indicating the direction of resizing, use * {@code 0} to indicate it's a move + * @param displayId the ID of the display where the drag starts * @param x x coordinate in window decoration coordinate system where the drag starts * @param y y coordinate in window decoration coordinate system where the drag starts * @return the starting task bounds */ - Rect onDragPositioningStart(@CtrlType int ctrlType, float x, float y); + Rect onDragPositioningStart(@CtrlType int ctrlType, int displayId, float x, float y); /** * Called when the pointer moves during a drag-resize or drag-move. + * + * @param displayId the ID of the display where the pointer is currently located * @param x x coordinate in window decoration coordinate system of the new pointer location * @param y y coordinate in window decoration coordinate system of the new pointer location * @return the updated task bounds */ - Rect onDragPositioningMove(float x, float y); + Rect onDragPositioningMove(int displayId, float x, float y); /** * Called when a drag-resize or drag-move stops. + * + * @param displayId the ID of the display where the pointer is located when drag stops * @param x x coordinate in window decoration coordinate system where the drag resize stops * @param y y coordinate in window decoration coordinate system where the drag resize stops * @return the final bounds for the dragged task */ - Rect onDragPositioningEnd(float x, float y); + Rect onDragPositioningEnd(int displayId, float x, float y); } 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 a6d503d0d991..7d1471f44674 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 @@ -454,7 +454,7 @@ class DragResizeInputListener implements AutoCloseable { ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: Handling action down, update ctrlType to %d", TAG, ctrlType); mDragStartTaskBounds = mCallback.onDragPositioningStart(ctrlType, - rawX, rawY); + e.getDisplayId(), rawX, rawY); mLastMotionEventOnDown = e; mResizeTrigger = (ctrlType == CTRL_TYPE_BOTTOM || ctrlType == CTRL_TYPE_TOP || ctrlType == CTRL_TYPE_RIGHT || ctrlType == CTRL_TYPE_LEFT) @@ -489,7 +489,8 @@ class DragResizeInputListener implements AutoCloseable { } final float rawX = e.getRawX(dragPointerIndex); final float rawY = e.getRawY(dragPointerIndex); - final Rect taskBounds = mCallback.onDragPositioningMove(rawX, rawY); + final Rect taskBounds = mCallback.onDragPositioningMove(e.getDisplayId(), + rawX, rawY); updateInputSinkRegionForDrag(taskBounds); result = true; break; @@ -505,7 +506,7 @@ class DragResizeInputListener implements AutoCloseable { TAG, e.getActionMasked()); break; } - final Rect taskBounds = mCallback.onDragPositioningEnd( + final Rect taskBounds = mCallback.onDragPositioningEnd(e.getDisplayId(), e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex)); // If taskBounds has changed, setGeometry will be called and update the // sink region. Otherwise, we should revert it here. 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 c8aff78cbb36..5b027f3c039e 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 @@ -168,7 +168,10 @@ public final class DragResizeWindowGeometry { return (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; } - static boolean isEdgeResizePermitted(@NonNull MotionEvent e) { + /** + * Whether resizing a window from the edge is permitted based on the motion event. + */ + public static boolean isEdgeResizePermitted(@NonNull MotionEvent e) { if (ENABLE_WINDOWING_EDGE_DRAG_RESIZE.isTrue()) { return e.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS || e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt index 3885761d0742..ab30d617af54 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt @@ -47,10 +47,11 @@ class FixedAspectRatioTaskPositionerDecorator ( private var startingAspectRatio = 0f private var isTaskPortrait = false - override fun onDragPositioningStart(@CtrlType ctrlType: Int, x: Float, y: Float): Rect { + override fun onDragPositioningStart( + @CtrlType ctrlType: Int, displayId: Int, x: Float, y: Float): Rect { originalCtrlType = ctrlType if (!requiresFixedAspectRatio()) { - return super.onDragPositioningStart(originalCtrlType, x, y) + return super.onDragPositioningStart(originalCtrlType, displayId, x, y) } lastRepositionedBounds.set(getBounds(windowDecoration.mTaskInfo)) @@ -72,27 +73,27 @@ class FixedAspectRatioTaskPositionerDecorator ( val verticalMidPoint = lastRepositionedBounds.top + (startingBoundHeight / 2) edgeResizeCtrlType = originalCtrlType + if (y < verticalMidPoint) CTRL_TYPE_TOP else CTRL_TYPE_BOTTOM - super.onDragPositioningStart(edgeResizeCtrlType, x, y) + super.onDragPositioningStart(edgeResizeCtrlType, displayId, x, y) } CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> { val horizontalMidPoint = lastRepositionedBounds.left + (startingBoundWidth / 2) edgeResizeCtrlType = originalCtrlType + if (x < horizontalMidPoint) CTRL_TYPE_LEFT else CTRL_TYPE_RIGHT - super.onDragPositioningStart(edgeResizeCtrlType, x, y) + super.onDragPositioningStart(edgeResizeCtrlType, displayId, x, y) } // If resize is corner resize, no alteration to the ctrlType needs to be made. else -> { edgeResizeCtrlType = CTRL_TYPE_UNDEFINED - super.onDragPositioningStart(originalCtrlType, x, y) + super.onDragPositioningStart(originalCtrlType, displayId, x, y) } } ) return lastRepositionedBounds } - override fun onDragPositioningMove(x: Float, y: Float): Rect { + override fun onDragPositioningMove(displayId: Int, x: Float, y: Float): Rect { if (!requiresFixedAspectRatio()) { - return super.onDragPositioningMove(x, y) + return super.onDragPositioningMove(displayId, x, y) } val diffX = x - lastValidPoint.x @@ -103,7 +104,7 @@ class FixedAspectRatioTaskPositionerDecorator ( // Drag coordinate falls within valid region (90 - 180 degrees or 270- 360 // degrees from the corner the previous valid point). Allow resize with adjusted // coordinates to maintain aspect ratio. - lastRepositionedBounds.set(dragAdjustedMove(x, y)) + lastRepositionedBounds.set(dragAdjustedMove(displayId, x, y)) } } CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> { @@ -111,28 +112,28 @@ class FixedAspectRatioTaskPositionerDecorator ( // Drag coordinate falls within valid region (180 - 270 degrees or 0 - 90 // degrees from the corner the previous valid point). Allow resize with adjusted // coordinates to maintain aspect ratio. - lastRepositionedBounds.set(dragAdjustedMove(x, y)) + lastRepositionedBounds.set(dragAdjustedMove(displayId, x, y)) } } CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> { // If resize is on left or right edge, always adjust the y coordinate. val adjustedY = getScaledChangeForY(x) lastValidPoint.set(x, adjustedY) - lastRepositionedBounds.set(super.onDragPositioningMove(x, adjustedY)) + lastRepositionedBounds.set(super.onDragPositioningMove(displayId, x, adjustedY)) } CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> { // If resize is on top or bottom edge, always adjust the x coordinate. val adjustedX = getScaledChangeForX(y) lastValidPoint.set(adjustedX, y) - lastRepositionedBounds.set(super.onDragPositioningMove(adjustedX, y)) + lastRepositionedBounds.set(super.onDragPositioningMove(displayId, adjustedX, y)) } } return lastRepositionedBounds } - override fun onDragPositioningEnd(x: Float, y: Float): Rect { + override fun onDragPositioningEnd(displayId: Int, x: Float, y: Float): Rect { if (!requiresFixedAspectRatio()) { - return super.onDragPositioningEnd(x, y) + return super.onDragPositioningEnd(displayId, x, y) } val diffX = x - lastValidPoint.x @@ -144,55 +145,55 @@ class FixedAspectRatioTaskPositionerDecorator ( // Drag coordinate falls within valid region (90 - 180 degrees or 270- 360 // degrees from the corner the previous valid point). End resize with adjusted // coordinates to maintain aspect ratio. - return dragAdjustedEnd(x, y) + return dragAdjustedEnd(displayId, x, y) } // If end of resize is not within valid region, end resize from last valid // coordinates. - return super.onDragPositioningEnd(lastValidPoint.x, lastValidPoint.y) + return super.onDragPositioningEnd(displayId, lastValidPoint.x, lastValidPoint.y) } CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> { if ((diffX > 0 && diffY < 0) || (diffX < 0 && diffY > 0)) { // Drag coordinate falls within valid region (180 - 260 degrees or 0 - 90 // degrees from the corner the previous valid point). End resize with adjusted // coordinates to maintain aspect ratio. - return dragAdjustedEnd(x, y) + return dragAdjustedEnd(displayId, x, y) } // If end of resize is not within valid region, end resize from last valid // coordinates. - return super.onDragPositioningEnd(lastValidPoint.x, lastValidPoint.y) + return super.onDragPositioningEnd(displayId, lastValidPoint.x, lastValidPoint.y) } CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> { // If resize is on left or right edge, always adjust the y coordinate. - return super.onDragPositioningEnd(x, getScaledChangeForY(x)) + return super.onDragPositioningEnd(displayId, x, getScaledChangeForY(x)) } CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> { // If resize is on top or bottom edge, always adjust the x coordinate. - return super.onDragPositioningEnd(getScaledChangeForX(y), y) + return super.onDragPositioningEnd(displayId, getScaledChangeForX(y), y) } else -> { - return super.onDragPositioningEnd(x, y) + return super.onDragPositioningEnd(displayId, x, y) } } } - private fun dragAdjustedMove(x: Float, y: Float): Rect { + private fun dragAdjustedMove(displayId: Int, x: Float, y: Float): Rect { val absDiffX = abs(x - lastValidPoint.x) val absDiffY = abs(y - lastValidPoint.y) if (absDiffY < absDiffX) { lastValidPoint.set(getScaledChangeForX(y), y) - return super.onDragPositioningMove(getScaledChangeForX(y), y) + return super.onDragPositioningMove(displayId, getScaledChangeForX(y), y) } lastValidPoint.set(x, getScaledChangeForY(x)) - return super.onDragPositioningMove(x, getScaledChangeForY(x)) + return super.onDragPositioningMove(displayId, x, getScaledChangeForY(x)) } - private fun dragAdjustedEnd(x: Float, y: Float): Rect { + private fun dragAdjustedEnd(displayId: Int, x: Float, y: Float): Rect { val absDiffX = abs(x - lastValidPoint.x) val absDiffY = abs(y - lastValidPoint.y) if (absDiffY < absDiffX) { - return super.onDragPositioningEnd(getScaledChangeForX(y), y) + return super.onDragPositioningEnd(displayId, getScaledChangeForX(y), y) } - return super.onDragPositioningEnd(x, getScaledChangeForY(x)) + return super.onDragPositioningEnd(displayId, x, getScaledChangeForY(x)) } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java index 3efae9d6375a..2d6f7459e0ae 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java @@ -91,7 +91,7 @@ class FluidResizeTaskPositioner implements TaskPositioner, Transitions.Transitio } @Override - public Rect onDragPositioningStart(int ctrlType, float x, float y) { + public Rect onDragPositioningStart(int ctrlType, int displayId, float x, float y) { mCtrlType = ctrlType; mTaskBoundsAtDragStart.set( mWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds()); @@ -117,7 +117,7 @@ class FluidResizeTaskPositioner implements TaskPositioner, Transitions.Transitio } @Override - public Rect onDragPositioningMove(float x, float y) { + public Rect onDragPositioningMove(int displayId, float x, float y) { final WindowContainerTransaction wct = new WindowContainerTransaction(); PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint); if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType, @@ -147,7 +147,7 @@ class FluidResizeTaskPositioner implements TaskPositioner, Transitions.Transitio } @Override - public Rect onDragPositioningEnd(float x, float y) { + public Rect onDragPositioningEnd(int displayId, float x, float y) { // If task has been resized or task was dragged into area outside of // mDisallowedAreaForEndBounds, apply WCT to finish it. if (isResizing() && mHasDragResized) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 159759ede368..bb19a2cc2ad4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -694,7 +694,7 @@ class HandleMenu( setTextColor(style.textColor) compoundDrawableTintList = ColorStateList.valueOf(style.textColor) } - + openByDefaultBtn.isGone = isBrowserApp openByDefaultBtn.imageTintList = ColorStateList.valueOf(style.textColor) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java index 1f03d7568130..e011cc08903b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java @@ -104,7 +104,7 @@ public class VeiledResizeTaskPositioner implements TaskPositioner, Transitions.T } @Override - public Rect onDragPositioningStart(int ctrlType, float x, float y) { + public Rect onDragPositioningStart(int ctrlType, int displayId, float x, float y) { mCtrlType = ctrlType; mTaskBoundsAtDragStart.set( mDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds()); @@ -136,7 +136,7 @@ public class VeiledResizeTaskPositioner implements TaskPositioner, Transitions.T } @Override - public Rect onDragPositioningMove(float x, float y) { + public Rect onDragPositioningMove(int displayId, float x, float y) { if (Looper.myLooper() != mHandler.getLooper()) { // This method must run on the shell main thread to use the correct Choreographer // instance below. @@ -170,7 +170,7 @@ public class VeiledResizeTaskPositioner implements TaskPositioner, Transitions.T } @Override - public Rect onDragPositioningEnd(float x, float y) { + public Rect onDragPositioningEnd(int displayId, float x, float y) { PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint); if (isResizing()) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 0214da4660ad..aead0a7afb53 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -1015,11 +1015,11 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest onCaptionButtonTouchListener = onTouchListenerCaptor ) - whenever(mockTaskPositioner.onDragPositioningStart(any(), any(), any())) + whenever(mockTaskPositioner.onDragPositioningStart(any(), any(), any(), any())) .thenReturn(INITIAL_BOUNDS) - whenever(mockTaskPositioner.onDragPositioningMove(any(), any())) + whenever(mockTaskPositioner.onDragPositioningMove(any(), any(), any())) .thenReturn(INITIAL_BOUNDS) - whenever(mockTaskPositioner.onDragPositioningEnd(any(), any())) + whenever(mockTaskPositioner.onDragPositioningEnd(any(), any(), any())) .thenReturn(INITIAL_BOUNDS) val view = mock(View::class.java) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt index ce17c1df50bc..3c3d6b6bb258 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt @@ -68,9 +68,9 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ configuration.windowConfiguration.setBounds(PORTRAIT_BOUNDS) } doReturn(PORTRAIT_BOUNDS).`when`(mockTaskPositioner).onDragPositioningStart( - any(), any(), any()) - doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningMove(any(), any()) - doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningEnd(any(), any()) + any(), any(), any(), any()) + doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningMove(any(), any(), any()) + doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningEnd(any(), any(), any()) decoratedTaskPositioner = spy( FixedAspectRatioTaskPositionerDecorator( mockDesktopWindowDecoration, mockTaskPositioner) @@ -87,7 +87,8 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ isResizeable = testCase.isResizeable } - decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalY) + decoratedTaskPositioner.onDragPositioningStart( + testCase.ctrlType, DISPLAY_ID, originalX, originalY) val capturedValues = getLatestOnStartArguments() assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType) @@ -102,7 +103,8 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ val originalX = 0f val originalY = 0f - decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalY) + decoratedTaskPositioner.onDragPositioningStart( + testCase.ctrlType, DISPLAY_ID, originalX, originalY) val capturedValues = getLatestOnStartArguments() assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType) @@ -119,7 +121,7 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) val adjustedCtrlType = testCase.ctrlType + testCase.additionalEdgeCtrlType val capturedValues = getLatestOnStartArguments() @@ -134,13 +136,14 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ ) { val originalX = 0f val originalY = 0f - decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalX) + decoratedTaskPositioner.onDragPositioningStart( + testCase.ctrlType, DISPLAY_ID, originalX, originalX) mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { isResizeable = testCase.isResizeable } decoratedTaskPositioner.onDragPositioningMove( - originalX + SMALL_DELTA, originalY + SMALL_DELTA) + DISPLAY_ID, originalX + SMALL_DELTA, originalY + SMALL_DELTA) val capturedValues = getLatestOnMoveArguments() assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA) @@ -156,13 +159,14 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) val updatedBounds = decoratedTaskPositioner.onDragPositioningMove( + DISPLAY_ID, startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y) - verify(mockTaskPositioner, never()).onDragPositioningMove(any(), any()) + verify(mockTaskPositioner, never()).onDragPositioningMove(any(), any(), any()) assertThat(updatedBounds).isEqualTo(startingBounds) } @@ -176,10 +180,12 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) decoratedTaskPositioner.onDragPositioningMove( - startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y) + DISPLAY_ID, + startingPoint.x + testCase.dragDelta.x, + startingPoint.y + testCase.dragDelta.y) val adjustedDragDelta = calculateAdjustedDelta( testCase.ctrlType, testCase.dragDelta, orientation) @@ -202,9 +208,10 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) decoratedTaskPositioner.onDragPositioningMove( + DISPLAY_ID, startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y) @@ -227,13 +234,14 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ ) { val originalX = 0f val originalY = 0f - decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalX) + decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, DISPLAY_ID, + originalX, originalX) mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { isResizeable = testCase.isResizeable } decoratedTaskPositioner.onDragPositioningEnd( - originalX + SMALL_DELTA, originalY + SMALL_DELTA) + DISPLAY_ID, originalX + SMALL_DELTA, originalY + SMALL_DELTA) val capturedValues = getLatestOnEndArguments() assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA) @@ -249,9 +257,10 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) decoratedTaskPositioner.onDragPositioningEnd( + DISPLAY_ID, startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y) @@ -269,10 +278,12 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) decoratedTaskPositioner.onDragPositioningEnd( - startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y) + DISPLAY_ID, + startingPoint.x + testCase.dragDelta.x, + startingPoint.y + testCase.dragDelta.y) val adjustedDragDelta = calculateAdjustedDelta( testCase.ctrlType, testCase.dragDelta, orientation) @@ -295,9 +306,10 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds) decoratedTaskPositioner.onDragPositioningStart( - testCase.ctrlType, startingPoint.x, startingPoint.y) + testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) decoratedTaskPositioner.onDragPositioningEnd( + DISPLAY_ID, startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y) @@ -322,7 +334,7 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ val captorCtrlType = argumentCaptor<Int>() val captorCoordinates = argumentCaptor<Float>() verify(mockTaskPositioner).onDragPositioningStart( - captorCtrlType.capture(), captorCoordinates.capture(), captorCoordinates.capture()) + captorCtrlType.capture(), any(), captorCoordinates.capture(), captorCoordinates.capture()) return CtrlCoordinateCapture(captorCtrlType.firstValue, captorCoordinates.firstValue, captorCoordinates.secondValue) @@ -335,7 +347,7 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ private fun getLatestOnMoveArguments(): PointF { val captorCoordinates = argumentCaptor<Float>() verify(mockTaskPositioner).onDragPositioningMove( - captorCoordinates.capture(), captorCoordinates.capture()) + any(), captorCoordinates.capture(), captorCoordinates.capture()) return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue) } @@ -347,7 +359,7 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ private fun getLatestOnEndArguments(): PointF { val captorCoordinates = argumentCaptor<Float>() verify(mockTaskPositioner).onDragPositioningEnd( - captorCoordinates.capture(), captorCoordinates.capture()) + any(), captorCoordinates.capture(), captorCoordinates.capture()) return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue) } @@ -358,7 +370,7 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ private fun getAndMockBounds(orientation: Orientation): Rect { val mockBounds = if (orientation.isPortrait) PORTRAIT_BOUNDS else LANDSCAPE_BOUNDS doReturn(mockBounds).`when`(mockTaskPositioner).onDragPositioningStart( - any(), any(), any()) + any(), any(), any(), any()) doReturn(mockBounds).`when`(decoratedTaskPositioner).getBounds(any()) return mockBounds } @@ -458,6 +470,7 @@ class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ private val STARTING_ASPECT_RATIO = PORTRAIT_BOUNDS.height() / PORTRAIT_BOUNDS.width() private const val LARGE_DELTA = 50f private const val SMALL_DELTA = 30f + private const val DISPLAY_ID = 1 enum class Orientation( val isPortrait: Boolean diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt index 3b80cb4936b9..cec52518edd2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt @@ -150,11 +150,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_notMove_skipsTransitionOnEnd() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 10, STARTING_BOUNDS.top.toFloat() + 10 ) @@ -171,11 +173,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_noEffectiveMove_skipsTransitionOnMoveAndEnd() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -188,6 +192,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { }) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 10, STARTING_BOUNDS.top.toFloat() + 10 ) @@ -204,11 +209,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_hasEffectiveMove_issuesTransitionOnMoveAndEnd() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 10, STARTING_BOUNDS.top.toFloat() ) @@ -224,6 +231,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { verify(mockDragEventListener, times(1)).onDragMove(eq(TASK_ID)) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 10, STARTING_BOUNDS.top.toFloat() + 10 ) @@ -242,6 +250,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_move_skipsDragResizingFlag() { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, // Move + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -250,11 +259,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.left.toFloat() + 10 val newY = STARTING_BOUNDS.top.toFloat() taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -276,6 +286,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setsDragResizingFlag() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT, // Resize right + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -284,11 +295,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() + 10 val newY = STARTING_BOUNDS.top.toFloat() taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -310,6 +322,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -318,11 +331,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 5 val newY = STARTING_BOUNDS.top.toFloat() + 95 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -340,6 +354,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -348,11 +363,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 95 val newY = STARTING_BOUNDS.top.toFloat() + 5 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -370,6 +386,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -378,11 +395,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 5 val newY = STARTING_BOUNDS.top.toFloat() + 105 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -400,6 +418,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -408,11 +427,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 105 val newY = STARTING_BOUNDS.top.toFloat() + 5 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -430,6 +450,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -438,11 +459,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 80 val newY = STARTING_BOUNDS.top.toFloat() + 80 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -456,6 +478,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -464,11 +487,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 95 val newY = STARTING_BOUNDS.top.toFloat() + 95 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -484,6 +508,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -492,11 +517,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 97 val newY = STARTING_BOUNDS.top.toFloat() + 97 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -510,6 +536,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_useMinWidthWhenValid() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -518,11 +545,12 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.right.toFloat() - 93 val newY = STARTING_BOUNDS.top.toFloat() + 93 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -535,6 +563,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_toDisallowedBounds_freezesAtLimit() { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat() ) @@ -546,6 +575,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { STARTING_BOUNDS.right + 10, STARTING_BOUNDS.bottom + 10) taskPositioner.onDragPositioningMove( + DISPLAY_ID, newBounds.right.toFloat(), newBounds.bottom.toFloat() ) @@ -559,11 +589,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { DISALLOWED_RESIZE_AREA.top ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, newBounds2.right.toFloat(), newBounds2.bottom.toFloat() ) - taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat()) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newBounds2.right.toFloat(), + newBounds2.bottom.toFloat()) // The first resize falls in the allowed area, verify there's a change for it. verify(mockShellTaskOrganizer).applyTransaction(argThat { wct -> @@ -629,6 +661,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { mockWindowDecoration.mHasGlobalFocus = false taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT, // Resize right + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -645,6 +678,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { mockWindowDecoration.mHasGlobalFocus = true taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT, // Resize right + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -661,6 +695,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { mockWindowDecoration.mHasGlobalFocus = false taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, // drag + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -729,11 +764,13 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() - 20, STARTING_BOUNDS.top.toFloat() - 20 ) @@ -742,6 +779,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { assertTrue(taskPositioner.isResizingOrAnimating) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -785,15 +823,18 @@ class FluidResizeTaskPositionerTest : ShellTestCase() { ) { taskPositioner.onDragPositioningStart( ctrlType, + DISPLAY_ID, startX, startY ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, endX, endY ) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, endX, endY ) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt index e7df8643ba66..eb8c0dd365a3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt @@ -168,12 +168,14 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_noMove_doesNotShowResizeVeil() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) verify(mockDesktopWindowDecoration, never()).showResizeVeil(STARTING_BOUNDS) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -191,11 +193,13 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_movesTask_doesNotShowResizeVeil() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 60, STARTING_BOUNDS.top.toFloat() + 100 ) @@ -208,6 +212,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { eq(rectAfterMove.top.toFloat())) val endBounds = taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 70, STARTING_BOUNDS.top.toFloat() + 20 ) @@ -226,11 +231,13 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_resize_boundsUpdateOnEnd() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, + DISPLAY_ID, STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.right.toFloat() + 10, STARTING_BOUNDS.top.toFloat() + 10 ) @@ -248,6 +255,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { }) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.right.toFloat() + 20, STARTING_BOUNDS.top.toFloat() + 20 ) @@ -266,17 +274,20 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { @Test fun testDragResize_noEffectiveMove_skipsTransactionOnEnd() = runOnUiThread { taskPositioner.onDragPositioningStart( + DISPLAY_ID, CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() + 10, STARTING_BOUNDS.top.toFloat() + 10 ) @@ -300,6 +311,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, // drag + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -307,11 +319,12 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { val newX = STARTING_BOUNDS.left.toFloat() + 5 val newY = DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT.toFloat() - 1 taskPositioner.onDragPositioningMove( + DISPLAY_ID, newX, newY ) - taskPositioner.onDragPositioningEnd(newX, newY) + taskPositioner.onDragPositioningEnd(DISPLAY_ID, newX, newY) verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct -> return@argThat wct.changes.any { (token, change) -> @@ -326,6 +339,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { mockDesktopWindowDecoration.mHasGlobalFocus = false taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT, // Resize right + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -342,6 +356,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { mockDesktopWindowDecoration.mHasGlobalFocus = true taskPositioner.onDragPositioningStart( CTRL_TYPE_RIGHT, // Resize right + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -358,6 +373,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { mockDesktopWindowDecoration.mHasGlobalFocus = false taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, // drag + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -422,11 +438,13 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { taskPositioner.onDragPositioningStart( CTRL_TYPE_TOP or CTRL_TYPE_RIGHT, + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat() - 20, STARTING_BOUNDS.top.toFloat() - 20 ) @@ -436,6 +454,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { verify(mockDragEventListener, times(1)).onDragMove(eq(TASK_ID)) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, STARTING_BOUNDS.left.toFloat(), STARTING_BOUNDS.top.toFloat() ) @@ -501,15 +520,18 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { ) { taskPositioner.onDragPositioningStart( ctrlType, + DISPLAY_ID, startX, startY ) taskPositioner.onDragPositioningMove( + DISPLAY_ID, endX, endY ) taskPositioner.onDragPositioningEnd( + DISPLAY_ID, endX, endY ) diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 50387548b4ab..bcb70019b3ac 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -53,7 +53,7 @@ import java.util.stream.Collectors; * The format of the media data is specified as key/value pairs. Keys are strings. Values can * be integer, long, float, String or ByteBuffer. * <p> - * The feature metadata is specificed as string/boolean pairs. + * The feature metadata is specified as string/boolean pairs. * <p> * Keys common to all audio/video formats, <b>all keys not marked optional are mandatory</b>: * @@ -1244,12 +1244,12 @@ public final class MediaFormat { /** * An optional key describing the desired encoder latency in frames. This is an optional - * parameter that applies only to video encoders. If encoder supports it, it should ouput + * parameter that applies only to video encoders. If encoder supports it, it should output * at least one output frame after being queued the specified number of frames. This key * is ignored if the video encoder does not support the latency feature. Use the output * format to verify that this feature was enabled and the actual value used by the encoder. * <p> - * If the key is not specified, the default latency will be implenmentation specific. + * If the key is not specified, the default latency will be implementation specific. * The associated value is an integer. */ public static final String KEY_LATENCY = "latency"; @@ -1507,16 +1507,16 @@ public final class MediaFormat { */ public static final String KEY_COLOR_STANDARD = "color-standard"; - /** BT.709 color chromacity coordinates with KR = 0.2126, KB = 0.0722. */ + /** BT.709 color chromaticity coordinates with KR = 0.2126, KB = 0.0722. */ public static final int COLOR_STANDARD_BT709 = 1; - /** BT.601 625 color chromacity coordinates with KR = 0.299, KB = 0.114. */ + /** BT.601 625 color chromaticity coordinates with KR = 0.299, KB = 0.114. */ public static final int COLOR_STANDARD_BT601_PAL = 2; - /** BT.601 525 color chromacity coordinates with KR = 0.299, KB = 0.114. */ + /** BT.601 525 color chromaticity coordinates with KR = 0.299, KB = 0.114. */ public static final int COLOR_STANDARD_BT601_NTSC = 4; - /** BT.2020 color chromacity coordinates with KR = 0.2627, KB = 0.0593. */ + /** BT.2020 color chromaticity coordinates with KR = 0.2627, KB = 0.0593. */ public static final int COLOR_STANDARD_BT2020 = 6; /** @hide */ @@ -2150,7 +2150,7 @@ public final class MediaFormat { * Sets the value of a string key. * <p> * If value is {@code null}, it sets a null value that behaves similarly to a missing key. - * This could be used prior to API level {@link android os.Build.VERSION_CODES#Q} to effectively + * This could be used prior to API level {@link android.os.Build.VERSION_CODES#Q} to effectively * remove a key. */ public final void setString(@NonNull String name, @Nullable String value) { @@ -2161,7 +2161,7 @@ public final class MediaFormat { * Sets the value of a ByteBuffer key. * <p> * If value is {@code null}, it sets a null value that behaves similarly to a missing key. - * This could be used prior to API level {@link android os.Build.VERSION_CODES#Q} to effectively + * This could be used prior to API level {@link android.os.Build.VERSION_CODES#Q} to effectively * remove a key. */ public final void setByteBuffer(@NonNull String name, @Nullable ByteBuffer bytes) { diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index 0db99ffd208a..9257901bcd1f 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -22,6 +22,7 @@ #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionTag.h> +#include <aidl/android/hardware/power/SupportInfo.h> #include <aidl/android/hardware/power/WorkDuration.h> #include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/os/IHintManager.h> @@ -148,10 +149,36 @@ private: std::future<bool> mChannelCreationFinished; }; +class SupportInfoWrapper { +public: + SupportInfoWrapper(hal::SupportInfo& info); + bool isSessionModeSupported(hal::SessionMode mode); + bool isSessionHintSupported(hal::SessionHint hint); + +private: + template <class T> + bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) { + // extract the bit corresponding to the enum by shifting the bitfield + // over that much and cutting off any extra values + return (supportBitfield >> static_cast<int>(enumValue)) % 2; + } + hal::SupportInfo mSupportInfo; +}; + +class HintManagerClient : public IHintManager::BnHintManagerClient { +public: + // Currently a no-op that exists for FMQ init to call in the future + ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) { + return ndk::ScopedAStatus::ok(); + } +}; + struct APerformanceHintManager { public: static APerformanceHintManager* getInstance(); - APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos); + APerformanceHintManager(std::shared_ptr<IHintManager>& service, + IHintManager::HintManagerClientData&& clientData, + std::shared_ptr<HintManagerClient> callbackClient); APerformanceHintManager() = delete; ~APerformanceHintManager(); @@ -169,29 +196,21 @@ public: FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); void initJava(JNIEnv* _Nonnull env); - ndk::ScopedAIBinder_Weak x; template <class T> static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls, int numSurfaceControls, std::vector<T>& out); + ndk::SpAIBinder& getToken(); + SupportInfoWrapper& getSupportInfo(); private: - // Necessary to create an empty binder object - static void* tokenStubOnCreate(void*) { - return nullptr; - } - static void tokenStubOnDestroy(void*) {} - static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*, - AParcel*) { - return STATUS_OK; - } - static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); std::shared_ptr<IHintManager> mHintManager; + std::shared_ptr<HintManagerClient> mCallbackClient; + IHintManager::HintManagerClientData mClientData; + SupportInfoWrapper mSupportInfoWrapper; ndk::SpAIBinder mToken; - const int64_t mPreferredRateNanos; - std::optional<int32_t> mMaxGraphicsPipelineThreadsCount; FMQWrapper mFMQWrapper; double mHintBudget = kMaxLoadHintsPerInterval; int64_t mLastBudgetReplenish = 0; @@ -273,14 +292,27 @@ static FMQWrapper& getFMQ() { return APerformanceHintManager::getInstance()->getFMQWrapper(); } +// ===================================== SupportInfoWrapper implementation + +SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {} + +bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) { + return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints); +} + +bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) { + return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes); +} + // ===================================== APerformanceHintManager implementation APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, - int64_t preferredRateNanos) - : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) { - static AIBinder_Class* tokenBinderClass = - AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy, - tokenStubOnTransact); - mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr)); + IHintManager::HintManagerClientData&& clientData, + std::shared_ptr<HintManagerClient> callbackClient) + : mHintManager(std::move(manager)), + mCallbackClient(callbackClient), + mClientData(clientData), + mSupportInfoWrapper(clientData.supportInfo), + mToken(callbackClient->asBinder()) { if (mFMQWrapper.isSupported()) { mFMQWrapper.setToken(mToken); mFMQWrapper.startChannel(mHintManager.get()); @@ -315,16 +347,17 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); return nullptr; } - int64_t preferredRateNanos = -1L; - ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos); + std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>(); + IHintManager::HintManagerClientData clientData; + ndk::ScopedAStatus ret = manager->registerClient(client, &clientData); if (!ret.isOk()) { - ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage()); + ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage()); return nullptr; } - if (preferredRateNanos <= 0) { - preferredRateNanos = -1L; + if (clientData.preferredRateNanos <= 0) { + clientData.preferredRateNanos = -1L; } - return new APerformanceHintManager(manager, preferredRateNanos); + return new APerformanceHintManager(manager, std::move(clientData), client); } bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { @@ -389,7 +422,9 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig( ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); return nullptr; } - auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos, + + auto out = new APerformanceHintSession(mHintManager, std::move(session), + mClientData.preferredRateNanos, sessionCreationConfig->targetWorkDurationNanos, isJava, sessionConfig.id == -1 ? std::nullopt @@ -416,24 +451,11 @@ APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env } int64_t APerformanceHintManager::getPreferredRateNanos() const { - return mPreferredRateNanos; + return mClientData.preferredRateNanos; } int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() { - if (!mMaxGraphicsPipelineThreadsCount.has_value()) { - int32_t threadsCount = -1; - ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount); - if (!ret.isOk()) { - ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s", - __FUNCTION__, ret.getMessage()); - return -1; - } - if (threadsCount <= 0) { - threadsCount = -1; - } - mMaxGraphicsPipelineThreadsCount.emplace(threadsCount); - } - return mMaxGraphicsPipelineThreadsCount.value(); + return mClientData.maxGraphicsPipelineThreads; } FMQWrapper& APerformanceHintManager::getFMQWrapper() { @@ -450,6 +472,14 @@ void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) { mJavaInitialized = true; } +ndk::SpAIBinder& APerformanceHintManager::getToken() { + return mToken; +} + +SupportInfoWrapper& APerformanceHintManager::getSupportInfo() { + return mSupportInfoWrapper; +} + // ===================================== APerformanceHintSession implementation constexpr int kNumEnums = enum_size<hal::SessionHint>(); diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index c166e738ffb2..e3c10f63abb4 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -56,9 +56,6 @@ public: const SessionCreationConfig& creationConfig, hal::SessionConfig* config, std::shared_ptr<IHintSession>* _aidl_return), (override)); - MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); - MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return), - (override)); MOCK_METHOD(ScopedAStatus, setHintSessionThreads, (const std::shared_ptr<IHintSession>& hintSession, const ::std::vector<int32_t>& tids), @@ -84,6 +81,11 @@ public: MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); + MOCK_METHOD(ScopedAStatus, registerClient, + (const std::shared_ptr<::aidl::android::os::IHintManager::IHintManagerClient>& + clientDataIn, + ::aidl::android::os::IHintManager::HintManagerClientData* _aidl_return), + (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; @@ -125,10 +127,9 @@ public: APerformanceHintManager* createManager() { APerformanceHint_setUseFMQForTesting(mUsingFMQ); - ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) - .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); })); - ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_)) - .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); })); + ON_CALL(*mMockIHintManager, registerClient(_, _)) + .WillByDefault( + DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); })); return APerformanceHint_getManager(); } @@ -238,6 +239,20 @@ public: int kMockQueueSize = 20; bool mUsingFMQ = false; + IHintManager::HintManagerClientData mClientData{ + .powerHalVersion = 6, + .maxGraphicsPipelineThreads = 5, + .preferredRateNanos = 123L, + .supportInfo{ + .usesSessions = true, + .boosts = 0, + .modes = 0, + .sessionHints = -1, + .sessionModes = -1, + .sessionTags = -1, + }, + }; + int32_t mMaxLoadHintsPerInterval; int64_t mLoadHintInterval; @@ -256,12 +271,6 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) { lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; } -TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) { - APerformanceHintManager* manager = createManager(); - int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager); - EXPECT_EQ(123L, preferredUpdateRateNanos); -} - TEST_F(PerformanceHintTest, TestSession) { APerformanceHintManager* manager = createManager(); APerformanceHintSession* session = createSession(manager); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt index 21019875f51e..9d5bf4dbdc3f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt @@ -55,7 +55,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith @@ -887,7 +886,6 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { @Test @EnableSceneContainer - @Ignore("b/378766637") fun lockscreenVisibilityWithScenes() = testScope.runTest { val isDeviceUnlocked by @@ -896,6 +894,7 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { ) assertThat(isDeviceUnlocked).isFalse() + kosmos.setSceneTransition(Idle(Scenes.Lockscreen)) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt index 9edd62a8a784..6a2aae175d80 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt @@ -16,21 +16,23 @@ package com.android.systemui.media.controls.ui.viewmodel -import android.R import android.content.packageManager import android.content.pm.ApplicationInfo import android.media.MediaMetadata import android.media.session.MediaSession import android.media.session.PlaybackState +import androidx.constraintlayout.widget.ConstraintSet import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter +import com.android.systemui.media.controls.shared.model.MediaButton import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDeviceData import com.android.systemui.media.controls.util.mediaInstanceId +import com.android.systemui.res.R import com.android.systemui.statusbar.notificationLockscreenUserManager import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -132,6 +134,31 @@ class MediaControlViewModelTest : SysuiTestCase() { assertThat(underTest.setPlayer(playerModel!!)).isTrue() } + @Test + fun reservedButtons_showScrubbingTimes() = + testScope.runTest { + val playerModel by collectLastValue(underTest.player) + val mediaData = + initMediaData(ARTIST, TITLE) + .copy(semanticActions = MediaButton(reserveNext = true, reservePrev = true)) + + mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) + + assertThat(playerModel?.actionButtons).isNotNull() + assertThat(playerModel!!.useSemanticActions).isTrue() + assertThat(playerModel!!.canShowTime).isTrue() + + val buttons = playerModel!!.actionButtons + + val prevButton = buttons.find { it.buttonId == R.id.actionPrev }!! + assertThat(prevButton.notVisibleValue).isEqualTo(ConstraintSet.GONE) + assertThat(prevButton.isVisibleWhenScrubbing).isEqualTo(false) + + val nextButton = buttons.find { it.buttonId == R.id.actionNext }!! + assertThat(nextButton.notVisibleValue).isEqualTo(ConstraintSet.GONE) + assertThat(nextButton.isVisibleWhenScrubbing).isEqualTo(false) + } + private fun initMediaData(artist: String, title: String): MediaData { val device = MediaDeviceData(true, null, DEVICE_NAME, null, showBroadcastButton = true) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt index b19645fadbdf..8fb95e843ec1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository +import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository @@ -40,9 +41,14 @@ import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify @SmallTest @RunWith(AndroidJUnit4::class) @@ -51,6 +57,11 @@ class OngoingCallInteractorTest : SysuiTestCase() { private val repository = kosmos.activeNotificationListRepository private val underTest = kosmos.ongoingCallInteractor + @Before + fun setUp() { + underTest.start() + } + @Test fun noNotification_emitsNoCall() = runTest { val state by collectLastValue(underTest.ongoingCallState) @@ -210,8 +221,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { @Test fun ongoingCallNotification_setsRequiresStatusBarVisibleTrue() = kosmos.runTest { - val ongoingCallState by collectLastValue(underTest.ongoingCallState) - + val isStatusBarRequired by collectLastValue(underTest.isStatusBarRequiredForOngoingCall) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay @@ -222,21 +232,9 @@ class OngoingCallInteractorTest : SysuiTestCase() { kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) - repository.activeNotifications.value = - ActiveNotificationsStore.Builder() - .apply { - addIndividualNotif( - activeNotificationModel( - key = "notif1", - whenTime = 1000L, - callType = CallType.Ongoing, - uid = UID, - ) - ) - } - .build() + postOngoingCallNotification() - assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) + assertThat(isStatusBarRequired).isTrue() assertThat(requiresStatusBarVisibleInRepository).isTrue() assertThat(requiresStatusBarVisibleInWindowController).isTrue() } @@ -244,8 +242,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { @Test fun notificationRemoved_setsRequiresStatusBarVisibleFalse() = kosmos.runTest { - val ongoingCallState by collectLastValue(underTest.ongoingCallState) - + val isStatusBarRequired by collectLastValue(underTest.isStatusBarRequiredForOngoingCall) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay @@ -257,23 +254,11 @@ class OngoingCallInteractorTest : SysuiTestCase() { .ongoingProcessRequiresStatusBarVisible ) - repository.activeNotifications.value = - ActiveNotificationsStore.Builder() - .apply { - addIndividualNotif( - activeNotificationModel( - key = "notif1", - whenTime = 1000L, - callType = CallType.Ongoing, - uid = UID, - ) - ) - } - .build() + postOngoingCallNotification() repository.activeNotifications.value = ActiveNotificationsStore() - assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.NoCall::class.java) + assertThat(isStatusBarRequired).isFalse() assertThat(requiresStatusBarVisibleInRepository).isFalse() assertThat(requiresStatusBarVisibleInWindowController).isFalse() } @@ -295,19 +280,8 @@ class OngoingCallInteractorTest : SysuiTestCase() { ) kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false - repository.activeNotifications.value = - ActiveNotificationsStore.Builder() - .apply { - addIndividualNotif( - activeNotificationModel( - key = "notif1", - whenTime = 1000L, - callType = CallType.Ongoing, - uid = UID, - ) - ) - } - .build() + + postOngoingCallNotification() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isTrue() @@ -321,6 +295,99 @@ class OngoingCallInteractorTest : SysuiTestCase() { assertThat(requiresStatusBarVisibleInWindowController).isFalse() } + @Test + fun gestureHandler_inCall_notFullscreen_doesNotListen() = + kosmos.runTest { + val ongoingCallState by collectLastValue(underTest.ongoingCallState) + + clearInvocations(kosmos.swipeStatusBarAwayGestureHandler) + // Set up notification but not in fullscreen + kosmos.fakeStatusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false + postOngoingCallNotification() + + assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) + verify(kosmos.swipeStatusBarAwayGestureHandler, never()) + .addOnGestureDetectedCallback(any(), any()) + } + + @Test + fun gestureHandler_inCall_fullscreen_addsListener() = + kosmos.runTest { + val isGestureListeningEnabled by collectLastValue(underTest.isGestureListeningEnabled) + + // Set up notification and fullscreen mode + kosmos.fakeStatusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true + postOngoingCallNotification() + + assertThat(isGestureListeningEnabled).isTrue() + verify(kosmos.swipeStatusBarAwayGestureHandler) + .addOnGestureDetectedCallback(any(), any()) + } + + @Test + fun gestureHandler_inCall_fullscreen_chipSwiped_removesListener() = + kosmos.runTest { + val swipeAwayState by collectLastValue(underTest.isChipSwipedAway) + + // Set up notification and fullscreen mode + kosmos.fakeStatusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true + postOngoingCallNotification() + + clearInvocations(kosmos.swipeStatusBarAwayGestureHandler) + + underTest.onStatusBarSwiped() + + assertThat(swipeAwayState).isTrue() + verify(kosmos.swipeStatusBarAwayGestureHandler).removeOnGestureDetectedCallback(any()) + } + + @Test + fun chipSwipedAway_setsRequiresStatusBarVisibleFalse() = + kosmos.runTest { + val isStatusBarRequiredForOngoingCall by + collectLastValue(underTest.isStatusBarRequiredForOngoingCall) + val requiresStatusBarVisibleInRepository by + collectLastValue( + kosmos.fakeStatusBarModeRepository.defaultDisplay + .ongoingProcessRequiresStatusBarVisible + ) + val requiresStatusBarVisibleInWindowController by + collectLastValue( + kosmos.fakeStatusBarWindowControllerStore.defaultDisplay + .ongoingProcessRequiresStatusBarVisible + ) + + // Start with an ongoing call (which should set status bar required) + postOngoingCallNotification() + + assertThat(isStatusBarRequiredForOngoingCall).isTrue() + assertThat(requiresStatusBarVisibleInRepository).isTrue() + assertThat(requiresStatusBarVisibleInWindowController).isTrue() + + // Swipe away the chip + underTest.onStatusBarSwiped() + + // Verify status bar is no longer required + assertThat(requiresStatusBarVisibleInRepository).isFalse() + assertThat(requiresStatusBarVisibleInWindowController).isFalse() + } + + private fun postOngoingCallNotification() { + repository.activeNotifications.value = + ActiveNotificationsStore.Builder() + .apply { + addIndividualNotif( + activeNotificationModel( + key = "notif1", + whenTime = 1000L, + callType = CallType.Ongoing, + uid = UID, + ) + ) + } + .build() + } + companion object { private const val UID = 885 } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java index 70ca82492775..dccf61d4e6c7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java @@ -1369,8 +1369,9 @@ public class MediaControlPanel { boolean visible = mediaAction != null && !shouldBeHiddenDueToScrubbing; int notVisibleValue; - if ((buttonId == R.id.actionPrev && semanticActions.getReservePrev()) - || (buttonId == R.id.actionNext && semanticActions.getReserveNext())) { + if (!shouldBeHiddenDueToScrubbing + && ((buttonId == R.id.actionPrev && semanticActions.getReservePrev()) + || (buttonId == R.id.actionNext && semanticActions.getReserveNext()))) { notVisibleValue = ConstraintSet.INVISIBLE; mMediaViewHolder.getAction(buttonId).setFocusable(visible); mMediaViewHolder.getAction(buttonId).setClickable(visible); @@ -1408,7 +1409,9 @@ public class MediaControlPanel { // The scrubbing time views replace the SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING action views, // so we should only allow scrubbing times to be shown if those action views are present. return semanticActions != null && SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.stream().allMatch( - id -> semanticActions.getActionById(id) != null + id -> (semanticActions.getActionById(id) != null + || ((id == R.id.actionPrev && semanticActions.getReservePrev()) + || (id == R.id.actionNext && semanticActions.getReserveNext()))) ); } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt index 4e97f2015c12..61e4d95a88e6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt @@ -316,8 +316,11 @@ class MediaControlViewModel( isVisibleWhenScrubbing = !shouldHideWhenScrubbing, notVisibleValue = if ( - (buttonId == R.id.actionPrev && model.semanticActionButtons!!.reservePrev) || - (buttonId == R.id.actionNext && model.semanticActionButtons!!.reserveNext) + !shouldHideWhenScrubbing && + ((buttonId == R.id.actionPrev && + model.semanticActionButtons!!.reservePrev) || + (buttonId == R.id.actionNext && + model.semanticActionButtons!!.reserveNext)) ) { ConstraintSet.INVISIBLE } else { @@ -382,7 +385,9 @@ class MediaControlViewModel( // so we should only allow scrubbing times to be shown if those action views are present. return semanticActions?.let { SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.stream().allMatch { id: Int -> - semanticActions.getActionById(id) != null + semanticActions.getActionById(id) != null || + (id == R.id.actionPrev && semanticActions.reservePrev || + id == R.id.actionNext && semanticActions.reserveNext) } } ?: false } 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 b1719107fae1..037a1b2a97f1 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -26,6 +26,7 @@ import static com.android.systemui.classifier.Classifier.BACK_GESTURE; import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll; import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED; +import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.isEdgeResizePermitted; import static java.util.stream.Collectors.joining; @@ -965,11 +966,14 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack return mDesktopModeExcludeRegion.contains(x, y); } - private boolean isWithinTouchRegion(int x, int y) { + private boolean isWithinTouchRegion(MotionEvent ev) { // If the point is inside the PiP or Nav bar overlay excluded bounds, then ignore the back // gesture + int x = (int) ev.getX(); + int y = (int) ev.getY(); final boolean isInsidePip = mIsInPip && mPipExcludedBounds.contains(x, y); - final boolean isInDesktopExcludeRegion = desktopExcludeRegionContains(x, y); + final boolean isInDesktopExcludeRegion = desktopExcludeRegionContains(x, y) + && isEdgeResizePermitted(ev); if (isInsidePip || isInDesktopExcludeRegion || mNavBarOverlayExcludedBounds.contains(x, y)) { return false; @@ -1098,8 +1102,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack && isValidTrackpadBackGesture(true /* isTrackpadEvent */); } else { mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets - && isWithinTouchRegion((int) ev.getX(), (int) ev.getY()) - && !isButtonPressFromTrackpad(ev); + && isWithinTouchRegion(ev) && !isButtonPressFromTrackpad(ev); } if (mAllowGesture) { mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index 879e01f0ae9a..d401b6ecbfd8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -779,11 +779,15 @@ constructor( lastIconTint = icon.getColor(state) // Long-press effects - longPressEffect?.qsTile?.state?.handlesLongClick = state.handlesLongClick - if ( - state.handlesLongClick && - longPressEffect?.initializeEffect(longPressEffectDuration) == true - ) { + updateLongPressEffect(state.handlesLongClick) + } + + private fun updateLongPressEffect(handlesLongClick: Boolean) { + // The long press effect in the tile can't be updated if it is still running + if (longPressEffect?.state != QSLongPressEffect.State.IDLE) return + + longPressEffect.qsTile?.state?.handlesLongClick = handlesLongClick + if (handlesLongClick && longPressEffect.initializeEffect(longPressEffectDuration)) { showRippleEffect = false longPressEffect.qsTile?.state?.state = lastState // Store the tile's state longPressEffect.resetState() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt index 2588c7ae2363..46c84fbc19aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.phone.StatusBarSignalPolicy import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.domain.interactor.OngoingCallInteractor import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl import com.android.systemui.statusbar.window.MultiDisplayStatusBarWindowControllerStore @@ -101,6 +102,19 @@ interface StatusBarModule { @Provides @SysUISingleton + @IntoMap + @ClassKey(OngoingCallInteractor::class) + fun ongoingCallInteractor( + interactor: OngoingCallInteractor + ): CoreStartable = + if (StatusBarChipsModernization.isEnabled) { + interactor + } else { + CoreStartable.NOP + } + + @Provides + @SysUISingleton fun lightBarController(store: LightBarControllerStore): LightBarController { return store.defaultDisplay } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt index b7ccfa01c92c..2f7b24393ae0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt @@ -16,12 +16,15 @@ package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor +import androidx.annotation.VisibleForTesting +import com.android.systemui.CoreStartable import com.android.systemui.activity.data.repository.ActivityManagerRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore +import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog @@ -31,11 +34,15 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn @@ -55,12 +62,19 @@ class OngoingCallInteractor @Inject constructor( private val activityManagerRepository: ActivityManagerRepository, private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, + private val swipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler, activeNotificationsInteractor: ActiveNotificationsInteractor, @OngoingCallLog private val logBuffer: LogBuffer, -) { +) : CoreStartable { private val logger = Logger(logBuffer, TAG) /** + * Tracks whether the call chip has been swiped away. + */ + private val _isChipSwipedAway = MutableStateFlow(false) + val isChipSwipedAway: StateFlow<Boolean> = _isChipSwipedAway.asStateFlow() + + /** * The current state of ongoing calls. */ val ongoingCallState: StateFlow<OngoingCallModel> = @@ -70,15 +84,29 @@ class OngoingCallInteractor @Inject constructor( notification = notification ) } - .onEach { state -> - setStatusBarRequiredForOngoingCall(state) - } .stateIn( scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = OngoingCallModel.NoCall ) + @VisibleForTesting + val isStatusBarRequiredForOngoingCall = combine( + ongoingCallState, + isChipSwipedAway + ) { callState, chipSwipedAway -> + callState is OngoingCallModel.InCall && !chipSwipedAway + } + + @VisibleForTesting + val isGestureListeningEnabled = combine( + ongoingCallState, + statusBarModeRepositoryStore.defaultDisplay.isInFullscreenMode, + isChipSwipedAway + ) { callState, isFullscreen, chipSwipedAway -> + callState is OngoingCallModel.InCall && !chipSwipedAway && isFullscreen + } + private fun createOngoingCallStateFlow( notification: ActiveNotificationModel? ): Flow<OngoingCallModel> { @@ -99,6 +127,31 @@ class OngoingCallInteractor @Inject constructor( } } + override fun start() { + ongoingCallState + .filterIsInstance<OngoingCallModel.NoCall>() + .onEach { + _isChipSwipedAway.value = false + }.launchIn(scope) + + isStatusBarRequiredForOngoingCall.onEach { statusBarRequired -> + setStatusBarRequiredForOngoingCall(statusBarRequired) + }.launchIn(scope) + + isGestureListeningEnabled.onEach { isEnabled -> + updateGestureListening(isEnabled) + }.launchIn(scope) + } + + /** + * Callback that must run when the status bar is swiped while gesture listening is active. + */ + @VisibleForTesting + fun onStatusBarSwiped() { + logger.d("Status bar chip swiped away") + _isChipSwipedAway.value = true + } + private fun deriveOngoingCallState( model: ActiveNotificationModel, isVisible: Boolean @@ -126,8 +179,7 @@ class OngoingCallInteractor @Inject constructor( } } - private fun setStatusBarRequiredForOngoingCall(state: OngoingCallModel) { - val statusBarRequired = state is OngoingCallModel.InCall + private fun setStatusBarRequiredForOngoingCall(statusBarRequired: Boolean) { // TODO(b/382808183): Create a single repository that can be utilized in // `statusBarModeRepositoryStore` and `statusBarWindowControllerStore` so we do not need // two separate calls to force the status bar to stay visible. @@ -138,6 +190,16 @@ class OngoingCallInteractor @Inject constructor( .setOngoingProcessRequiresStatusBarVisible(statusBarRequired) } + private fun updateGestureListening(isEnabled: Boolean) { + if (isEnabled) { + swipeStatusBarAwayGestureHandler.addOnGestureDetectedCallback(TAG) { _ -> + onStatusBarSwiped() + } + } else { + swipeStatusBarAwayGestureHandler.removeOnGestureDetectedCallback(TAG) + } + } + companion object { private val TAG = "OngoingCall" } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt index 68a5d9361046..9543032ef5ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt @@ -247,7 +247,7 @@ public class MediaControlPanelTest : SysuiTestCase() { mContext, 0, intent.setPackage(mContext.packageName), - PendingIntent.FLAG_MUTABLE + PendingIntent.FLAG_MUTABLE, ) @JvmField @Rule val mockito = MockitoJUnit.rule() @@ -294,7 +294,7 @@ public class MediaControlPanelTest : SysuiTestCase() { override fun loadAnimator( animId: Int, otionInterpolator: Interpolator, - vararg targets: View + vararg targets: View, ): AnimatorSet { return mockAnimator } @@ -323,7 +323,7 @@ public class MediaControlPanelTest : SysuiTestCase() { packageName = PACKAGE, instanceId = instanceId, recommendations = listOf(smartspaceAction, smartspaceAction, smartspaceAction), - cardAction = smartspaceAction + cardAction = smartspaceAction, ) } @@ -370,7 +370,7 @@ public class MediaControlPanelTest : SysuiTestCase() { packageName = PACKAGE, token = session.sessionToken, device = device, - instanceId = instanceId + instanceId = instanceId, ) } @@ -416,7 +416,7 @@ public class MediaControlPanelTest : SysuiTestCase() { action1.id, action2.id, action3.id, - action4.id + action4.id, ) } @@ -536,7 +536,7 @@ public class MediaControlPanelTest : SysuiTestCase() { playOrPause = MediaAction(icon, Runnable {}, "play", bg), nextOrCustom = MediaAction(icon, Runnable {}, "next", bg), custom0 = MediaAction(icon, null, "custom 0", bg), - custom1 = MediaAction(icon, null, "custom 1", bg) + custom1 = MediaAction(icon, null, "custom 1", bg), ) val state = mediaData.copy(semanticActions = semanticActions) player.attachPlayer(viewHolder) @@ -590,7 +590,7 @@ public class MediaControlPanelTest : SysuiTestCase() { custom0 = MediaAction(icon, null, "custom 0", bg), custom1 = MediaAction(icon, null, "custom 1", bg), false, - true + true, ) val state = mediaData.copy(semanticActions = semanticActions) @@ -622,7 +622,7 @@ public class MediaControlPanelTest : SysuiTestCase() { custom0 = MediaAction(icon, null, "custom 0", bg), custom1 = MediaAction(icon, null, "custom 1", bg), true, - false + false, ) val state = mediaData.copy(semanticActions = semanticActions) @@ -760,7 +760,7 @@ public class MediaControlPanelTest : SysuiTestCase() { val semanticActions = MediaButton( playOrPause = MediaAction(icon, Runnable {}, "play", null), - nextOrCustom = MediaAction(icon, Runnable {}, "next", null) + nextOrCustom = MediaAction(icon, Runnable {}, "next", null), ) val state = mediaData.copy(semanticActions = semanticActions) @@ -850,7 +850,7 @@ public class MediaControlPanelTest : SysuiTestCase() { val semanticActions = MediaButton( prevOrCustom = MediaAction(icon, {}, "prev", null), - nextOrCustom = MediaAction(icon, {}, "next", null) + nextOrCustom = MediaAction(icon, {}, "next", null), ) val state = mediaData.copy(semanticActions = semanticActions) @@ -921,7 +921,7 @@ public class MediaControlPanelTest : SysuiTestCase() { val semanticActions = MediaButton( prevOrCustom = MediaAction(icon, {}, "prev", null), - nextOrCustom = MediaAction(icon, {}, "next", null) + nextOrCustom = MediaAction(icon, {}, "next", null), ) val state = mediaData.copy(semanticActions = semanticActions) player.attachPlayer(viewHolder) @@ -944,7 +944,7 @@ public class MediaControlPanelTest : SysuiTestCase() { val semanticActions = MediaButton( prevOrCustom = MediaAction(icon, {}, "prev", null), - nextOrCustom = MediaAction(icon, {}, "next", null) + nextOrCustom = MediaAction(icon, {}, "next", null), ) val state = mediaData.copy(semanticActions = semanticActions) @@ -966,6 +966,29 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun setIsScrubbing_reservedButtonSpaces_scrubbingTimesShown() { + val semanticActions = + MediaButton( + prevOrCustom = null, + nextOrCustom = null, + reserveNext = true, + reservePrev = true, + ) + val state = mediaData.copy(semanticActions = semanticActions) + player.attachPlayer(viewHolder) + player.bindPlayer(state, PACKAGE) + reset(expandedSet) + + getScrubbingChangeListener().onScrubbingChanged(true) + mainExecutor.runAllReady() + + verify(expandedSet).setVisibility(R.id.actionPrev, View.GONE) + verify(expandedSet).setVisibility(R.id.actionNext, View.GONE) + verify(expandedSet).setVisibility(R.id.media_scrubbing_elapsed_time, View.VISIBLE) + verify(expandedSet).setVisibility(R.id.media_scrubbing_total_time, View.VISIBLE) + } + + @Test fun bind_resumeState_withProgress() { val progress = 0.5 val state = mediaData.copy(resumption = true, resumeProgress = progress) @@ -1009,13 +1032,13 @@ public class MediaControlPanelTest : SysuiTestCase() { MediaNotificationAction(true, actionIntent = pendingIntent, icon, "play"), MediaNotificationAction(true, actionIntent = null, icon, "next"), MediaNotificationAction(true, actionIntent = null, icon, "custom 0"), - MediaNotificationAction(true, actionIntent = pendingIntent, icon, "custom 1") + MediaNotificationAction(true, actionIntent = pendingIntent, icon, "custom 1"), ) val state = mediaData.copy( actions = actions, actionsToShowInCompact = listOf(1, 2), - semanticActions = null + semanticActions = null, ) player.attachPlayer(viewHolder) @@ -1701,7 +1724,7 @@ public class MediaControlPanelTest : SysuiTestCase() { MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 1"), MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 2"), MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 3"), - MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4") + MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4"), ) val data = mediaData.copy(actions = actions) @@ -1720,7 +1743,7 @@ public class MediaControlPanelTest : SysuiTestCase() { MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 1"), MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 2"), MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 3"), - MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4") + MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4"), ) val data = mediaData.copy(actions = actions) @@ -1739,7 +1762,7 @@ public class MediaControlPanelTest : SysuiTestCase() { MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 1"), MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 2"), MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 3"), - MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4") + MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4"), ) val data = mediaData.copy(actions = actions) @@ -2021,7 +2044,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle(subtitle3) .setIcon(icon) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) player.bindRecommendation(data) @@ -2047,7 +2070,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setIcon( Icon.createWithResource( context, - com.android.settingslib.R.drawable.ic_1x_mobiledata + com.android.settingslib.R.drawable.ic_1x_mobiledata, ) ) .setExtras(Bundle.EMPTY) @@ -2084,7 +2107,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle("fake subtitle") .setIcon(icon) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) player.bindRecommendation(data) @@ -2119,7 +2142,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle("") .setIcon(icon) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) player.bindRecommendation(data) @@ -2142,7 +2165,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setIcon( Icon.createWithResource( context, - com.android.settingslib.R.drawable.ic_1x_mobiledata + com.android.settingslib.R.drawable.ic_1x_mobiledata, ) ) .setExtras(Bundle.EMPTY) @@ -2157,11 +2180,11 @@ public class MediaControlPanelTest : SysuiTestCase() { .setIcon( Icon.createWithResource( context, - com.android.settingslib.R.drawable.ic_3g_mobiledata + com.android.settingslib.R.drawable.ic_3g_mobiledata, ) ) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) @@ -2185,7 +2208,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setIcon( Icon.createWithResource( context, - com.android.settingslib.R.drawable.ic_1x_mobiledata + com.android.settingslib.R.drawable.ic_1x_mobiledata, ) ) .setExtras(Bundle.EMPTY) @@ -2200,11 +2223,11 @@ public class MediaControlPanelTest : SysuiTestCase() { .setIcon( Icon.createWithResource( context, - com.android.settingslib.R.drawable.ic_3g_mobiledata + com.android.settingslib.R.drawable.ic_3g_mobiledata, ) ) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) @@ -2245,7 +2268,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle("subtitle1") .setIcon(albumArt) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) @@ -2268,7 +2291,7 @@ public class MediaControlPanelTest : SysuiTestCase() { Bundle().apply { putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS, - MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED + MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED, ) putDouble(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.5) } @@ -2290,7 +2313,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle("subtitle1") .setIcon(albumArt) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) @@ -2328,7 +2351,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle("subtitle1") .setIcon(albumArt) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) @@ -2381,7 +2404,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .setSubtitle("subtitle1") .setIcon(albumArt) .setExtras(Bundle.EMPTY) - .build() + .build(), ) ) @@ -2444,7 +2467,7 @@ public class MediaControlPanelTest : SysuiTestCase() { icon = null, action = {}, contentDescription = "play", - background = null + background = null, ) ) val data = mediaData.copy(semanticActions = semanticActions) @@ -2465,7 +2488,7 @@ public class MediaControlPanelTest : SysuiTestCase() { icon = null, action = {}, contentDescription = "play", - background = null + background = null, ) ) val data = mediaData.copy(semanticActions = semanticActions) @@ -2498,7 +2521,7 @@ public class MediaControlPanelTest : SysuiTestCase() { icon = null, action = {}, contentDescription = "play", - background = null + background = null, ) ) val data = mediaData.copy(semanticActions = semanticActions) @@ -2530,8 +2553,8 @@ public class MediaControlPanelTest : SysuiTestCase() { icon = null, action = {}, contentDescription = "custom0", - background = null - ), + background = null, + ) ) val data = mediaData.copy(semanticActions = semanticActions) player.attachPlayer(viewHolder) @@ -2553,8 +2576,8 @@ public class MediaControlPanelTest : SysuiTestCase() { icon = null, action = {}, contentDescription = "custom0", - background = null - ), + background = null, + ) ) val data = mediaData.copy(semanticActions = semanticActions) player.attachPlayer(viewHolder) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt index 90ffaf19be96..67c5986fe5d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt @@ -236,7 +236,7 @@ class QSTileViewImplTest : SysuiTestCase() { context.orCreateTestableResources.addOverride( R.array.tile_states_internet, - arrayOf(unavailableString, offString, onString) + arrayOf(unavailableString, offString, onString), ) // State UNAVAILABLE @@ -341,7 +341,7 @@ class QSTileViewImplTest : SysuiTestCase() { val testA11yLabel = "TEST_LABEL" context.orCreateTestableResources.addOverride( R.string.accessibility_tile_disabled_by_policy_action_description, - testA11yLabel + testA11yLabel, ) val stateDisabledByPolicy = QSTile.State() @@ -374,7 +374,7 @@ class QSTileViewImplTest : SysuiTestCase() { context.orCreateTestableResources.addOverride( R.array.tile_states_internet, - arrayOf(unavailableString, offString, onString) + arrayOf(unavailableString, offString, onString), ) tileView.changeState(state) @@ -477,6 +477,24 @@ class QSTileViewImplTest : SysuiTestCase() { } @Test + fun onStateChange_fromLongPress_toNoLongPress_whileLongPressRuns_doesNotClearResources() { + // GIVEN that the long-press effect has been initialized + val state = QSTile.State() + state.handlesLongClick = true + tileView.changeState(state) + + // WHEN the long-press effect is running + kosmos.qsLongPressEffect.setState(QSLongPressEffect.State.RUNNING_FORWARD) + + // WHEN a state changed happens so that the tile no longer handles long-press + state.handlesLongClick = false + tileView.changeState(state) + + // THEN the long-press effect resources are not cleared + assertThat(tileView.areLongPressEffectPropertiesSet).isTrue() + } + + @Test fun onStateChange_withoutLongPressEffect_fromLongPress_to_noLongPress_neverSetsProperties() { // GIVEN a tile where the long-press effect is null tileView = FakeTileView(context, false, null) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandlerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandlerKosmos.kt new file mode 100644 index 000000000000..72165c95fc55 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandlerKosmos.kt @@ -0,0 +1,25 @@ +/* + * 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.systemui.statusbar.gesture + +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +val Kosmos.swipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler by +Kosmos.Fixture { + mock<SwipeStatusBarAwayGestureHandler>() +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt index 9090e02b22b6..40d91017eeef 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository +import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore @@ -32,6 +33,7 @@ val Kosmos.ongoingCallInteractor: OngoingCallInteractor by activityManagerRepository = activityManagerRepository, statusBarModeRepositoryStore = fakeStatusBarModeRepository, statusBarWindowControllerStore = fakeStatusBarWindowControllerStore, + swipeStatusBarAwayGestureHandler = swipeStatusBarAwayGestureHandler, logBuffer = logcatLogBuffer("OngoingCallInteractorKosmos"), ) } diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java index 354f281551b2..aa06b7ecf76c 100644 --- a/services/core/java/com/android/server/am/BroadcastController.java +++ b/services/core/java/com/android/server/am/BroadcastController.java @@ -316,8 +316,7 @@ class BroadcastController { return null; } if (callerApp.info.uid != SYSTEM_UID - && !callerApp.getPkgList().containsKey(callerPackage) - && !"android".equals(callerPackage)) { + && !callerApp.getPkgList().containsKey(callerPackage)) { throw new SecurityException("Given caller package " + callerPackage + " is not running in process " + callerApp); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 7505c710f483..424102cbdd89 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -212,11 +212,11 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { HdmiConfig.TIMEOUT_MS); } - launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC && - reason != HdmiControlService.INITIATED_BY_BOOT_UP); resetSelectRequestBuffer(); launchDeviceDiscovery(); startQueuedActions(); + final boolean routingForBootup = reason != HdmiControlService.INITIATED_BY_ENABLE_CEC + && reason != HdmiControlService.INITIATED_BY_BOOT_UP; List<HdmiCecMessage> bufferedActiveSource = mDelayedMessageBuffer .getBufferedMessagesWithOpcode(Constants.MESSAGE_ACTIVE_SOURCE); if (bufferedActiveSource.isEmpty()) { @@ -227,14 +227,8 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { addAndStartAction(new RequestActiveSourceAction(this, new IHdmiControlCallback.Stub() { @Override public void onComplete(int result) { - if (!mService.getLocalActiveSource().isValid() - && result != HdmiControlManager.RESULT_SUCCESS) { - mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource( - getDeviceInfo().getLogicalAddress(), - getDeviceInfo().getPhysicalAddress())); - updateActiveSource(getDeviceInfo().getLogicalAddress(), - getDeviceInfo().getPhysicalAddress(), - "RequestActiveSourceAction#finishWithCallback()"); + if (result != HdmiControlManager.RESULT_SUCCESS) { + launchRoutingControl(routingForBootup); } } })); @@ -1384,8 +1378,7 @@ public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } else { int activePath = mService.getPhysicalAddress(); setActivePath(activePath); - if (!routingForBootup - && !mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) { + if (!mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) { mService.sendCecCommand( HdmiCecMessageBuilder.buildActiveSource( getDeviceInfo().getLogicalAddress(), activePath)); diff --git a/services/core/java/com/android/server/pm/RestrictionsSet.java b/services/core/java/com/android/server/pm/RestrictionsSet.java index 08047695a42a..38075c135d2a 100644 --- a/services/core/java/com/android/server/pm/RestrictionsSet.java +++ b/services/core/java/com/android/server/pm/RestrictionsSet.java @@ -65,6 +65,7 @@ public class RestrictionsSet { throw new IllegalArgumentException("empty restriction bundle cannot be added."); } mUserRestrictions.put(userId, restrictions); + UserManager.invalidateUserRestriction(); } /** @@ -84,6 +85,7 @@ public class RestrictionsSet { } else { mUserRestrictions.delete(userId); } + UserManager.invalidateUserRestriction(); return true; } @@ -102,6 +104,9 @@ public class RestrictionsSet { removed = true; } } + if (removed) { + UserManager.invalidateUserRestriction(); + } return removed; } @@ -129,6 +134,7 @@ public class RestrictionsSet { i--; } } + UserManager.invalidateUserRestriction(); } } @@ -192,6 +198,7 @@ public class RestrictionsSet { public boolean remove(@UserIdInt int userId) { boolean hasUserRestriction = mUserRestrictions.contains(userId); mUserRestrictions.remove(userId); + UserManager.invalidateUserRestriction(); return hasUserRestriction; } @@ -200,6 +207,7 @@ public class RestrictionsSet { */ public void removeAllRestrictions() { mUserRestrictions.clear(); + UserManager.invalidateUserRestriction(); } /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 066fce068d61..8249d65868cd 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1113,6 +1113,7 @@ public class UserManagerService extends IUserManager.Stub { UserManager.invalidateUserPropertiesCache(); } UserManager.invalidateCacheOnUserListChange(); + UserManager.invalidateUserRestriction(); } } diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index 7c7504dccf94..aae7417970eb 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -297,7 +297,11 @@ public final class HintManagerService extends SystemService { mPowerHalVersion = 0; mUsesFmq = false; if (mPowerHal != null) { - mSupportInfo = getSupportInfo(); + try { + mSupportInfo = getSupportInfo(); + } catch (RemoteException e) { + throw new IllegalStateException("Could not contact PowerHAL!", e); + } } mDefaultCpuHeadroomCalculationWindowMillis = new CpuHeadroomParamsInternal().calculationWindowMillis; @@ -315,7 +319,7 @@ public final class HintManagerService extends SystemService { } } - SupportInfo getSupportInfo() { + SupportInfo getSupportInfo() throws RemoteException { try { mPowerHalVersion = mPowerHal.getInterfaceVersion(); if (mPowerHalVersion >= 6) { @@ -326,9 +330,42 @@ public final class HintManagerService extends SystemService { } SupportInfo supportInfo = new SupportInfo(); + supportInfo.usesSessions = isHintSessionSupported(); + // Global boosts & modes aren't currently relevant for HMS clients + supportInfo.boosts = 0; + supportInfo.modes = 0; + supportInfo.sessionHints = 0; + supportInfo.sessionModes = 0; + supportInfo.sessionTags = 0; + supportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); supportInfo.headroom.isCpuSupported = false; supportInfo.headroom.isGpuSupported = false; + + supportInfo.compositionData = new SupportInfo.CompositionDataSupportInfo(); + if (isHintSessionSupported()) { + if (mPowerHalVersion == 4) { + // Assume we support the V4 hints & modes unless specified + // otherwise; this is to avoid breaking backwards compat + // since we historically just assumed they were. + supportInfo.sessionHints = 31; // first 5 bits are ones + } + if (mPowerHalVersion == 5) { + // Assume we support the V5 hints & modes unless specified + // otherwise; this is to avoid breaking backwards compat + // since we historically just assumed they were. + + // Hal V5 has 8 modes, all of which it assumes are supported, + // so we represent that by having the first 8 bits set + supportInfo.sessionHints = 255; // first 8 bits are ones + // Hal V5 has 1 mode which it assumes is supported, so we + // represent that by having the first bit set + supportInfo.sessionModes = 1; + // Hal V5 has 5 tags, all of which it assumes are supported, + // so we represent that by having the first 5 bits set + supportInfo.sessionTags = 31; + } + } return supportInfo; } @@ -1229,7 +1266,7 @@ public final class HintManagerService extends SystemService { @SessionTag int tag, SessionCreationConfig creationConfig, SessionConfig config) { if (!isHintSessionSupported()) { - throw new UnsupportedOperationException("PowerHAL is not supported!"); + throw new UnsupportedOperationException("PowerHintSessions are not supported!"); } java.util.Objects.requireNonNull(token); @@ -1425,12 +1462,6 @@ public final class HintManagerService extends SystemService { removeChannelItem(callingTgid, callingUid); }; - @Override - public long getHintSessionPreferredRate() { - return mHintSessionPreferredRate; - } - - @Override public int getMaxGraphicsPipelineThreadsCount() { return MAX_GRAPHICS_PIPELINE_THREADS_COUNT; } @@ -1621,13 +1652,24 @@ public final class HintManagerService extends SystemService { } @Override + public IHintManager.HintManagerClientData + registerClient(@NonNull IHintManager.IHintManagerClient clientBinder) { + IHintManager.HintManagerClientData out = new IHintManager.HintManagerClientData(); + out.preferredRateNanos = mHintSessionPreferredRate; + out.maxGraphicsPipelineThreads = getMaxGraphicsPipelineThreadsCount(); + out.powerHalVersion = mPowerHalVersion; + out.supportInfo = mSupportInfo; + return out; + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { return; } pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate); pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT); - pw.println("HAL Support: " + isHintSessionSupported()); + pw.println("Hint Session Support: " + isHintSessionSupported()); pw.println("Active Sessions:"); synchronized (mLock) { for (int i = 0; i < mActiveSessions.size(); i++) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 27d32bedfecb..0aff1de72cb1 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -1269,7 +1269,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Checks if the caller can be shown in the given public display. int userId = UserHandle.getUserId(callingUid); int displayId = display.getDisplayId(); - boolean allowed = mWindowManager.mUmInternal.isUserVisible(userId, displayId); + boolean allowed = userId == UserHandle.USER_SYSTEM + || mWindowManager.mUmInternal.isUserVisible(userId, displayId); ProtoLog.d(WM_DEBUG_TASKS, "Launch on display check: %s launch for userId=%d on displayId=%d", (allowed ? "allow" : "disallow"), userId, displayId); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 82699ea3badb..01639cc3b516 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -61,6 +61,7 @@ cc_library_static { "com_android_server_SystemServer.cpp", "com_android_server_tv_TvUinputBridge.cpp", "com_android_server_tv_TvInputHal.cpp", + "com_android_server_UsbAlsaDevice.cpp", "com_android_server_UsbAlsaJackDetector.cpp", "com_android_server_UsbAlsaMidiDevice.cpp", "com_android_server_UsbDeviceManager.cpp", diff --git a/services/core/jni/com_android_server_UsbAlsaDevice.cpp b/services/core/jni/com_android_server_UsbAlsaDevice.cpp new file mode 100644 index 000000000000..166932f167ed --- /dev/null +++ b/services/core/jni/com_android_server_UsbAlsaDevice.cpp @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#define LOG_TAG "UsbAlsaDeviceJNI" + +#include <nativehelper/JNIPlatformHelp.h> +#include <tinyalsa/asoundlib.h> + +#include <string> +#include <vector> + +#include "jni.h" +#include "utils/Log.h" + +static const std::vector<std::string> POSSIBLE_HARDWARE_VOLUME_MIXER_NAMES = + {"Headphone Playback Volume", "Headset Playback Volume", "PCM Playback Volume"}; + +namespace android { + +static void android_server_UsbAlsaDevice_setVolume(JNIEnv* /*env*/, jobject /*thiz*/, jint card, + float volume) { + ALOGD("%s(%d, %f)", __func__, card, volume); + struct mixer* alsaMixer = mixer_open(card); + if (alsaMixer == nullptr) { + ALOGW("%s(%d, %f) returned as no mixer is opened", __func__, card, volume); + return; + } + struct mixer_ctl* ctl = nullptr; + for (const auto& mixerName : POSSIBLE_HARDWARE_VOLUME_MIXER_NAMES) { + ctl = mixer_get_ctl_by_name(alsaMixer, mixerName.c_str()); + if (ctl != nullptr) { + break; + } + } + if (ctl == nullptr) { + ALOGW("%s(%d, %f) returned as no volume mixer is found", __func__, card, volume); + return; + } + const unsigned int n = mixer_ctl_get_num_values(ctl); + for (unsigned int id = 0; id < n; id++) { + if (int error = mixer_ctl_set_percent(ctl, id, 100 * volume); error != 0) { + ALOGE("%s(%d, %f) failed, error=%d", __func__, card, volume, error); + return; + } + } + ALOGD("%s(%d, %f) succeed", __func__, card, volume); +} + +static JNINativeMethod method_table[] = { + {"nativeSetVolume", "(IF)V", (void*)android_server_UsbAlsaDevice_setVolume}, +}; + +int register_android_server_UsbAlsaDevice(JNIEnv* env) { + return jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaDevice", method_table, + NELEM(method_table)); +} +} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 09fd8d4ac02e..e3bd69c30de7 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -33,6 +33,7 @@ int register_android_server_power_stats_CpuPowerStatsCollector(JNIEnv* env); int register_android_server_HintManagerService(JNIEnv* env); int register_android_server_storage_AppFuse(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); +int register_android_server_UsbAlsaDevice(JNIEnv* env); int register_android_server_UsbAlsaJackDetector(JNIEnv* env); int register_android_server_UsbAlsaMidiDevice(JNIEnv* env); int register_android_server_UsbDeviceManager(JavaVM* vm, JNIEnv* env); @@ -98,6 +99,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_InputManager(env); register_android_server_LightsService(env); register_android_server_UsbDeviceManager(vm, env); + register_android_server_UsbAlsaDevice(env); register_android_server_UsbAlsaJackDetector(env); register_android_server_UsbAlsaMidiDevice(env); register_android_server_UsbHostManager(env); diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java index 5c73fd33f46f..4b2e850d08e7 100644 --- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -64,6 +64,7 @@ import android.os.Binder; import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IBinder; +import android.os.IHintManager; import android.os.IHintSession; import android.os.PerformanceHintManager; import android.os.Process; @@ -154,6 +155,8 @@ public class HintManagerServiceTest { private ActivityManagerInternal mAmInternalMock; @Mock private PackageManager mMockPackageManager; + @Mock + private IHintManager.IHintManagerClient mClientCallback; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @@ -171,6 +174,24 @@ public class HintManagerServiceTest { }; } + private SupportInfo makeDefaultSupportInfo() { + mSupportInfo = new SupportInfo(); + mSupportInfo.usesSessions = true; + // By default, mark everything as fully supported + mSupportInfo.sessionHints = -1; + mSupportInfo.sessionModes = -1; + mSupportInfo.modes = -1; + mSupportInfo.boosts = -1; + mSupportInfo.sessionTags = -1; + mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); + mSupportInfo.headroom.isCpuSupported = true; + mSupportInfo.headroom.cpuMinIntervalMillis = 2000; + mSupportInfo.headroom.isGpuSupported = true; + mSupportInfo.headroom.gpuMinIntervalMillis = 2000; + mSupportInfo.compositionData = new SupportInfo.CompositionDataSupportInfo(); + return mSupportInfo; + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -181,12 +202,7 @@ public class HintManagerServiceTest { mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.category = ApplicationInfo.CATEGORY_GAME; - mSupportInfo = new SupportInfo(); - mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); - mSupportInfo.headroom.isCpuSupported = true; - mSupportInfo.headroom.cpuMinIntervalMillis = 2000; - mSupportInfo.headroom.isGpuSupported = true; - mSupportInfo.headroom.gpuMinIntervalMillis = 2000; + mSupportInfo = makeDefaultSupportInfo(); when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME); when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt())) @@ -215,6 +231,7 @@ public class HintManagerServiceTest { when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); + when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); } @@ -409,8 +426,11 @@ public class HintManagerServiceTest { HintManagerService service = createService(); IBinder token = new Binder(); - final int threadCount = - service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + + final int threadCount = data.maxGraphicsPipelineThreads; + long sessionPtr1 = 1111L; long sessionId1 = 11111L; CountDownLatch stopLatch1 = new CountDownLatch(1); @@ -1447,4 +1467,67 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); } + + @Test + public void testRegisteringClient() throws Exception { + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo, mSupportInfo); + } + + @Test + public void testRegisteringClientOnV4() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(4); + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo.usesSessions, true); + assertEquals(data.supportInfo.boosts, 0); + assertEquals(data.supportInfo.modes, 0); + assertEquals(data.supportInfo.sessionHints, 31); + assertEquals(data.supportInfo.sessionModes, 0); + assertEquals(data.supportInfo.sessionTags, 0); + assertEquals(data.powerHalVersion, 4); + assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); + } + + @Test + public void testRegisteringClientOnV5() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(5); + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo.usesSessions, true); + assertEquals(data.supportInfo.boosts, 0); + assertEquals(data.supportInfo.modes, 0); + assertEquals(data.supportInfo.sessionHints, 255); + assertEquals(data.supportInfo.sessionModes, 1); + assertEquals(data.supportInfo.sessionTags, 31); + assertEquals(data.powerHalVersion, 5); + assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); + } + + @Test + public void testSettingUpOldClientWhenUnsupported() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(5); + // Mock unsupported to modify the default support behavior + when(mNativeWrapperMock.halGetHintSessionPreferredRate()) + .thenReturn(-1L); + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo.usesSessions, false); + assertEquals(data.supportInfo.boosts, 0); + assertEquals(data.supportInfo.modes, 0); + assertEquals(data.supportInfo.sessionHints, 0); + assertEquals(data.supportInfo.sessionModes, 0); + assertEquals(data.supportInfo.sessionTags, 0); + assertEquals(data.powerHalVersion, 5); + assertEquals(data.preferredRateNanos, -1); + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java index d69e47684f8b..9b878b349618 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerCacheTest.java @@ -19,6 +19,7 @@ package com.android.server.pm; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assume.assumeTrue; +import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.LocaleManager; @@ -26,6 +27,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.multiuser.Flags; +import android.os.Bundle; import android.os.LocaleList; import android.os.SystemClock; import android.os.UserHandle; @@ -261,6 +263,162 @@ public final class UserManagerCacheTest { assertThat(um.getUserName()).isEqualTo(newName); } + + @MediumTest + @Test + public void testDefaultRestrictionsApplied() throws Exception { + final UserInfo userInfo = mUserManager.createUser("Useroid", + UserManager.USER_TYPE_FULL_SECONDARY, 0); + mUsersToRemove.add(userInfo.id); + final UserTypeDetails userTypeDetails = + UserTypeFactory.getUserTypes().get(UserManager.USER_TYPE_FULL_SECONDARY); + final Bundle expectedRestrictions = userTypeDetails.getDefaultRestrictions(); + // Note this can fail if DO unset those restrictions. + for (String restriction : expectedRestrictions.keySet()) { + if (expectedRestrictions.getBoolean(restriction)) { + assertThat(mUserManager.hasUserRestriction(restriction, UserHandle.of(userInfo.id))) + .isTrue(); + // Test cached value + assertThat(mUserManager.hasUserRestriction(restriction, UserHandle.of(userInfo.id))) + .isTrue(); + } + } + } + + @MediumTest + @Test + public void testSetDefaultGuestRestrictions() { + final Bundle origRestrictions = mUserManager.getDefaultGuestRestrictions(); + try { + final boolean isFunDisallowed = origRestrictions.getBoolean(UserManager.DISALLOW_FUN, + false); + final UserInfo guest1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST); + assertThat(guest1).isNotNull(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest1.getUserHandle())).isEqualTo(isFunDisallowed); + removeUser(guest1.id, true); + // Cache return false after user was removed + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest1.getUserHandle())).isFalse(); + + Bundle restrictions = new Bundle(); + restrictions.putBoolean(UserManager.DISALLOW_FUN, !isFunDisallowed); + mUserManager.setDefaultGuestRestrictions(restrictions); + UserInfo guest2 = mUserManager.createUser("Guest 2", UserInfo.FLAG_GUEST); + assertThat(guest2).isNotNull(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest2.getUserHandle())).isNotEqualTo(isFunDisallowed); + removeUser(guest2.id, true); + assertThat(mUserManager.getUserInfo(guest2.id)).isNull(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest2.getUserHandle())).isFalse(); + } finally { + mUserManager.setDefaultGuestRestrictions(origRestrictions); + } + } + + @MediumTest + @Test + public void testCacheInvalidatedAfterUserAddedOrRemoved() { + final Bundle origRestrictions = mUserManager.getDefaultGuestRestrictions(); + try { + final boolean isFunDisallowed = origRestrictions.getBoolean(UserManager.DISALLOW_FUN, + false); + final UserInfo guest1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST); + assertThat(guest1).isNotNull(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest1.getUserHandle())).isEqualTo(isFunDisallowed); + removeUser(guest1.id, true); + + Bundle restrictions = new Bundle(); + restrictions.putBoolean(UserManager.DISALLOW_FUN, !isFunDisallowed); + mUserManager.setDefaultGuestRestrictions(restrictions); + int latest_id = guest1.id; + // Cache removed id and few next ids. + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + UserHandle.of(latest_id))).isFalse(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + UserHandle.of(latest_id + 1))).isFalse(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + UserHandle.of(latest_id + 2))).isFalse(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + UserHandle.of(latest_id + 3))).isFalse(); + + UserInfo guest2 = mUserManager.createUser("Guest 2", UserInfo.FLAG_GUEST); + assertThat(guest2).isNotNull(); + // Cache was invalidated after user was added + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest2.getUserHandle())).isTrue(); + removeUser(guest2.id, true); + assertThat(mUserManager.getUserInfo(guest2.id)).isNull(); + // Cache was invalidated after user was removed + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + guest2.getUserHandle())).isFalse(); + } finally { + mUserManager.setDefaultGuestRestrictions(origRestrictions); + } + } + + + @MediumTest + @Test + public void testAddRemoveUsersAndRestrictions() { + try { + final UserInfo userInfo = mUserManager.createUser("Useroid", + UserManager.USER_TYPE_FULL_SECONDARY, 0); + mUsersToRemove.add(userInfo.id); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + userInfo.getUserHandle())).isFalse(); + mUserManager.setUserRestriction(UserManager.DISALLOW_FUN, true, + userInfo.getUserHandle()); + + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + userInfo.getUserHandle())).isTrue(); + removeUser(userInfo.id, true); + assertThat(mUserManager.getUserSerialNumber(userInfo.id)).isEqualTo(-1); + assertThat(mUserManager.getUserInfo(userInfo.id)).isNull(); + assertThat(mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN, + userInfo.getUserHandle())).isFalse(); + } catch (java.lang.Exception e) { + } + } + + + private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + + @MediumTest + @Test + public void testDefaultUserRestrictionsForPrivateProfile() { + assumeTrue(mUserManager.canAddPrivateProfile()); + final int currentUserId = ActivityManager.getCurrentUser(); + UserInfo privateProfileInfo = null; + try { + privateProfileInfo = mUserManager.createProfileForUser( + "Private", UserManager.USER_TYPE_PROFILE_PRIVATE, 0, currentUserId, null); + assertThat(privateProfileInfo).isNotNull(); + } catch (Exception e) { + fail("Creation of private profile failed due to " + e.getMessage()); + } + assertDefaultPrivateProfileRestrictions(privateProfileInfo.getUserHandle()); + // Assert cached values + assertDefaultPrivateProfileRestrictions(privateProfileInfo.getUserHandle()); + } + + private void assertDefaultPrivateProfileRestrictions(UserHandle userHandle) { + Bundle defaultPrivateProfileRestrictions = + UserTypeFactory.getDefaultPrivateProfileRestrictions(); + for (String restriction : defaultPrivateProfileRestrictions.keySet()) { + assertThat(mUserManager.hasUserRestrictionForUser(restriction, userHandle)).isTrue(); + } + } + private void assumeManagedUsersSupported() { // In Automotive, if headless system user is enabled, a managed user cannot be created // under a primary user. @@ -270,9 +428,23 @@ public final class UserManagerCacheTest { } private void removeUser(int userId) { + removeUser(userId, false); + } + + private void removeUser(int userId, boolean waitForCompleteRemoval) { mUserManager.removeUser(userId); mUserRemovalWaiter.waitFor(userId); mUsersToRemove.remove(userId); + if (waitForCompleteRemoval) { + int serialNumber = mUserManager.getUserSerialNumber(userId); + int timeout = REMOVE_USER_TIMEOUT_SECONDS * 5; // called every 200ms + // Wait for the user to be removed from memory + while (serialNumber > 0 && timeout > 0) { + sleep(200); + timeout--; + serialNumber = mUserManager.getUserSerialNumber(userId); + } + } } private boolean isAutomotive() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 661d07e09f99..5cb741fe81d4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2472,11 +2472,14 @@ public class ActivityRecordTests extends WindowTestsBase { final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); assertEquals(0, activity.getChildCount()); - final WindowState win1 = createWindow(null, TYPE_APPLICATION, activity, "win1"); - final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, - "startingWin"); - final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "baseWin"); - final WindowState win4 = createWindow(null, TYPE_APPLICATION, activity, "win4"); + final WindowState win1 = newWindowBuilder("app1", TYPE_APPLICATION).setWindowToken( + activity).build(); + final WindowState startingWin = newWindowBuilder("startingWin", + TYPE_APPLICATION_STARTING).setWindowToken(activity).build(); + final WindowState baseWin = newWindowBuilder("baseWin", + TYPE_BASE_APPLICATION).setWindowToken(activity).build(); + final WindowState win4 = newWindowBuilder("win4", TYPE_APPLICATION).setWindowToken( + activity).build(); // Should not contain the windows that were added above. assertEquals(4, activity.getChildCount()); @@ -2499,14 +2502,17 @@ public class ActivityRecordTests extends WindowTestsBase { final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); assertNull(activity.findMainWindow()); - final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1"); - final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window11"); - final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window12"); + final WindowState window1 = newWindowBuilder("window1", + TYPE_BASE_APPLICATION).setWindowToken(activity).build(); + final WindowState window11 = newWindowBuilder("window11", FIRST_SUB_WINDOW).setParent( + window1).setWindowToken(activity).build(); + final WindowState window12 = newWindowBuilder("window12", FIRST_SUB_WINDOW).setParent( + window1).setWindowToken(activity).build(); assertEquals(window1, activity.findMainWindow()); window1.mAnimatingExit = true; assertEquals(window1, activity.findMainWindow()); - final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, activity, - "window2"); + final WindowState window2 = newWindowBuilder("window2", + TYPE_APPLICATION_STARTING).setWindowToken(activity).build(); assertEquals(window2, activity.findMainWindow()); activity.removeImmediately(); } @@ -2651,8 +2657,8 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testStuckExitingWindow() { - final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, - "closingWindow"); + final WindowState closingWindow = newWindowBuilder("closingWindow", + FIRST_APPLICATION_WINDOW).build(); closingWindow.mAnimatingExit = true; closingWindow.mRemoveOnExit = true; closingWindow.mActivityRecord.commitVisibility( @@ -3313,7 +3319,7 @@ public class ActivityRecordTests extends WindowTestsBase { @SetupWindows(addWindows = W_INPUT_METHOD) @Test public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() { - final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build(); makeWindowVisibleAndDrawn(app, mImeWindow); mDisplayContent.setImeLayeringTarget(app); mDisplayContent.setImeInputTarget(app); @@ -3341,7 +3347,7 @@ public class ActivityRecordTests extends WindowTestsBase { @SetupWindows(addWindows = W_INPUT_METHOD) @Test public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() { - final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build(); mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer( mImeWindow, null, null); @@ -3385,8 +3391,8 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest() throws RemoteException { - final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1"); - final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); + final WindowState app1 = newWindowBuilder("app1", TYPE_APPLICATION).build(); + final WindowState app2 = newWindowBuilder("app2", TYPE_APPLICATION).build(); mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer( mImeWindow, null, null); @@ -3430,7 +3436,8 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testImeInsetsFrozenFlag_multiWindowActivities() { final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent); - final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, imeToken, "ime"); + final WindowState ime = newWindowBuilder("ime", TYPE_INPUT_METHOD).setWindowToken( + imeToken).build(); makeWindowVisibleAndDrawn(ime); // Create a split-screen root task with activity1 and activity 2. @@ -3451,8 +3458,10 @@ public class ActivityRecordTests extends WindowTestsBase { activity1.mImeInsetsFrozenUntilStartInput = true; activity2.mImeInsetsFrozenUntilStartInput = true; - final WindowState app1 = createWindow(null, TYPE_APPLICATION, activity1, "app1"); - final WindowState app2 = createWindow(null, TYPE_APPLICATION, activity2, "app2"); + final WindowState app1 = newWindowBuilder("app1", TYPE_APPLICATION).setWindowToken( + activity1).build(); + final WindowState app2 = newWindowBuilder("app2", TYPE_APPLICATION).setWindowToken( + activity2).build(); makeWindowVisibleAndDrawn(app1, app2); final InsetsStateController controller = mDisplayContent.getInsetsStateController(); @@ -3481,7 +3490,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testInClosingAnimation_visibilityNotCommitted_doNotHideSurface() { - final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build(); makeWindowVisibleAndDrawn(app); // Put the activity in close transition. @@ -3508,7 +3517,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testInClosingAnimation_visibilityCommitted_hideSurface() { - final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build(); makeWindowVisibleAndDrawn(app); app.mActivityRecord.prepareSurfaces(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index f339d292ed82..429a396ad997 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -92,7 +92,7 @@ import java.util.concurrent.TimeUnit; * Tests for the {@link DragDropController} class. * * Build/Install/Run: - * atest WmTests:DragDropControllerTests + * atest WmTests:DragDropControllerTests */ @SmallTest @Presubmit @@ -146,12 +146,12 @@ public class DragDropControllerTests extends WindowTestsBase { */ private WindowState createDropTargetWindow(String name, int ownerId) { final Task task = new TaskBuilder(mSupervisor).setUserId(ownerId).build(); - final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task) - .setUseProcess(mProcess).build(); + final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).setUseProcess( + mProcess).build(); // Use a new TestIWindow so we don't collect events for other windows - final WindowState window = createWindow( - null, TYPE_BASE_APPLICATION, activity, name, ownerId, false, new TestIWindow()); + final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, activity, name, + ownerId, false, new TestIWindow()); InputChannel channel = new InputChannel(); window.openInputChannel(channel); window.mHasSurface = true; @@ -173,12 +173,11 @@ public class DragDropControllerTests extends WindowTestsBase { @Before public void setUp() throws Exception { mTarget = new TestDragDropController(mWm, mWm.mH.getLooper()); - mProcess = mSystemServicesTestRule.addProcess(TEST_PACKAGE, "testProc", - TEST_PID, TEST_UID); + mProcess = mSystemServicesTestRule.addProcess(TEST_PACKAGE, "testProc", TEST_PID, TEST_UID); mWindow = createDropTargetWindow("Drag test window", 0); doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0); - when(mWm.mInputManager.startDragAndDrop(any(IBinder.class), - any(IBinder.class))).thenReturn(true); + when(mWm.mInputManager.startDragAndDrop(any(IBinder.class), any(IBinder.class))).thenReturn( + true); mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); } @@ -286,16 +285,15 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify the start-drag event is sent for the local and global intercept window // but not the other window assertTrue(nonLocalWindowDragEvents.isEmpty()); - assertTrue(localWindowDragEvents.get(0).getAction() - == ACTION_DRAG_STARTED); + assertTrue(localWindowDragEvents.get(0).getAction() == ACTION_DRAG_STARTED); assertTrue(globalInterceptWindowDragEvents.get(0).getAction() == ACTION_DRAG_STARTED); // Verify that only the global intercept window receives the clip data with the // resolved activity info for the drag assertNull(localWindowDragEvents.get(0).getClipData()); - assertTrue(globalInterceptWindowDragEvents.get(0).getClipData() - .willParcelWithActivityInfo()); + assertTrue(globalInterceptWindowDragEvents.get( + 0).getClipData().willParcelWithActivityInfo()); mTarget.reportDropWindow(globalInterceptWindow.mInputChannelToken, 0, 0); mTarget.handleMotionEvent(false, 0, 0); @@ -330,9 +328,8 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify the start-drag event has the drag flags final DragEvent dragEvent = dragEvents.get(0); assertTrue(dragEvent.getAction() == ACTION_DRAG_STARTED); - assertTrue(dragEvent.getDragFlags() == - (View.DRAG_FLAG_GLOBAL - | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG)); + assertTrue(dragEvent.getDragFlags() == (View.DRAG_FLAG_GLOBAL + | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG)); try { mTarget.mDeferDragStateClosed = true; @@ -340,9 +337,8 @@ public class DragDropControllerTests extends WindowTestsBase { // // Verify the drop event does not have the drag flags mTarget.handleMotionEvent(false, 0, 0); final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1); - assertTrue(dropEvent.getDragFlags() == - (View.DRAG_FLAG_GLOBAL - | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG)); + assertTrue(dropEvent.getDragFlags() == (View.DRAG_FLAG_GLOBAL + | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG)); mTarget.reportDropResult(iwindow, true); } finally { @@ -385,16 +381,15 @@ public class DragDropControllerTests extends WindowTestsBase { data.putExtra(Intent.EXTRA_USER, user); } final ClipData clipData = new ClipData( - new ClipDescription("drag", new String[] { - MIMETYPE_APPLICATION_ACTIVITY}), + new ClipDescription("drag", new String[]{MIMETYPE_APPLICATION_ACTIVITY}), new ClipData.Item(data)); return clipData; } @Test public void testValidateAppShortcutArguments() { - doReturn(PERMISSION_GRANTED).when(mWm.mContext) - .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS)); + doReturn(PERMISSION_GRANTED).when(mWm.mContext).checkCallingOrSelfPermission( + eq(START_TASKS_FROM_RECENTS)); final Session session = createTestSession(mAtm); try { session.validateAndResolveDragMimeTypeExtras( @@ -414,8 +409,8 @@ public class DragDropControllerTests extends WindowTestsBase { } try { session.validateAndResolveDragMimeTypeExtras( - createClipDataForShortcut("test_package", "test_shortcut_id", null), - TEST_UID, TEST_PID, TEST_PACKAGE); + createClipDataForShortcut("test_package", "test_shortcut_id", null), TEST_UID, + TEST_PID, TEST_PACKAGE); fail("Expected failure without package name"); } catch (IllegalArgumentException e) { // Expected failure @@ -424,8 +419,8 @@ public class DragDropControllerTests extends WindowTestsBase { @Test public void testValidateProfileAppShortcutArguments_notCallingUid() { - doReturn(PERMISSION_GRANTED).when(mWm.mContext) - .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS)); + doReturn(PERMISSION_GRANTED).when(mWm.mContext).checkCallingOrSelfPermission( + eq(START_TASKS_FROM_RECENTS)); final Session session = createTestSession(mAtm); final ShortcutServiceInternal shortcutService = mock(ShortcutServiceInternal.class); final Intent[] shortcutIntents = new Intent[1]; @@ -438,10 +433,9 @@ public class DragDropControllerTests extends WindowTestsBase { ArgumentCaptor<Integer> callingUser = ArgumentCaptor.forClass(Integer.class); session.validateAndResolveDragMimeTypeExtras( createClipDataForShortcut("test_package", "test_shortcut_id", - mock(UserHandle.class)), - TEST_PROFILE_UID, TEST_PID, TEST_PACKAGE); - verify(shortcutService).createShortcutIntents(callingUser.capture(), any(), - any(), any(), anyInt(), anyInt(), anyInt()); + mock(UserHandle.class)), TEST_PROFILE_UID, TEST_PID, TEST_PACKAGE); + verify(shortcutService).createShortcutIntents(callingUser.capture(), any(), any(), any(), + anyInt(), anyInt(), anyInt()); assertTrue(callingUser.getValue() == UserHandle.getUserId(TEST_PROFILE_UID)); } @@ -458,20 +452,19 @@ public class DragDropControllerTests extends WindowTestsBase { data.putExtra(Intent.EXTRA_USER, user); } final ClipData clipData = new ClipData( - new ClipDescription("drag", new String[] { - MIMETYPE_APPLICATION_SHORTCUT}), + new ClipDescription("drag", new String[]{MIMETYPE_APPLICATION_SHORTCUT}), new ClipData.Item(data)); return clipData; } @Test public void testValidateAppTaskArguments() { - doReturn(PERMISSION_GRANTED).when(mWm.mContext) - .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS)); + doReturn(PERMISSION_GRANTED).when(mWm.mContext).checkCallingOrSelfPermission( + eq(START_TASKS_FROM_RECENTS)); final Session session = createTestSession(mAtm); try { final ClipData clipData = new ClipData( - new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_TASK }), + new ClipDescription("drag", new String[]{MIMETYPE_APPLICATION_TASK}), new ClipData.Item(new Intent())); session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID, TEST_PID, @@ -496,8 +489,8 @@ public class DragDropControllerTests extends WindowTestsBase { @Test public void testValidateFlagsWithPermission() { - doReturn(PERMISSION_GRANTED).when(mWm.mContext) - .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS)); + doReturn(PERMISSION_GRANTED).when(mWm.mContext).checkCallingOrSelfPermission( + eq(START_TASKS_FROM_RECENTS)); final Session session = createTestSession(mAtm); try { session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION, @@ -533,8 +526,8 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify the DRAG_ENDED event does NOT include the drag surface final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1); - assertTrue(dragEvents.get(dragEvents.size() - 1).getAction() - == ACTION_DRAG_ENDED); + assertTrue( + dragEvents.get(dragEvents.size() - 1).getAction() == ACTION_DRAG_ENDED); assertTrue(dropEvent.getDragSurface() == null); }); } @@ -564,8 +557,8 @@ public class DragDropControllerTests extends WindowTestsBase { // Verify the DRAG_ENDED event includes the drag surface final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1); - assertTrue(dragEvents.get(dragEvents.size() - 1).getAction() - == ACTION_DRAG_ENDED); + assertTrue( + dragEvents.get(dragEvents.size() - 1).getAction() == ACTION_DRAG_ENDED); assertTrue(dropEvent.getDragSurface() != null); }); } @@ -591,18 +584,18 @@ public class DragDropControllerTests extends WindowTestsBase { final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { - // Trigger an unhandled drop and verify the global drag listener was called - mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); - mTarget.reportDropResult(mWindow.mClient, false); - mTarget.onUnhandledDropCallback(true); - mToken = null; - try { - verify(listener, times(1)).onUnhandledDrop(any(), any()); - } catch (RemoteException e) { - fail("Failed to verify unhandled drop: " + e); - } - }); + // Trigger an unhandled drop and verify the global drag listener was called + mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mTarget.reportDropResult(mWindow.mClient, false); + mTarget.onUnhandledDropCallback(true); + mToken = null; + try { + verify(listener, times(1)).onUnhandledDrop(any(), any()); + } catch (RemoteException e) { + fail("Failed to verify unhandled drop: " + e); + } + }); } @Test @@ -615,17 +608,17 @@ public class DragDropControllerTests extends WindowTestsBase { final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { - // Trigger an unhandled drop and verify the global drag listener was called - mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); - mTarget.onUnhandledDropCallback(true); - mToken = null; - try { - verify(listener, times(1)).onUnhandledDrop(any(), any()); - } catch (RemoteException e) { - fail("Failed to verify unhandled drop: " + e); - } - }); + // Trigger an unhandled drop and verify the global drag listener was called + mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mTarget.onUnhandledDropCallback(true); + mToken = null; + try { + verify(listener, times(1)).onUnhandledDrop(any(), any()); + } catch (RemoteException e) { + fail("Failed to verify unhandled drop: " + e); + } + }); } @Test @@ -636,18 +629,17 @@ public class DragDropControllerTests extends WindowTestsBase { doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; - startDrag(View.DRAG_FLAG_GLOBAL, - ClipData.newPlainText("label", "Test"), () -> { - // Trigger an unhandled drop and verify the global drag listener was not called - mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); - mToken = null; - try { - verify(listener, never()).onUnhandledDrop(any(), any()); - } catch (RemoteException e) { - fail("Failed to verify unhandled drop: " + e); - } - }); + startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { + // Trigger an unhandled drop and verify the global drag listener was not called + mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mToken = null; + try { + verify(listener, never()).onUnhandledDrop(any(), any()); + } catch (RemoteException e) { + fail("Failed to verify unhandled drop: " + e); + } + }); } @Test @@ -660,20 +652,22 @@ public class DragDropControllerTests extends WindowTestsBase { final int invalidXY = 100_000; startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ClipData.newPlainText("label", "Test"), () -> { - // Trigger an unhandled drop and verify the global drag listener was called - mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); - mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + // Trigger an unhandled drop and verify the global drag listener was called + mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); - // Verify that the unhandled drop listener callback timeout has been scheduled - final Handler handler = mTarget.getHandler(); - assertTrue(handler.hasMessages(MSG_UNHANDLED_DROP_LISTENER_TIMEOUT)); + // Verify that the unhandled drop listener callback timeout has been scheduled + final Handler handler = mTarget.getHandler(); + assertTrue(handler.hasMessages(MSG_UNHANDLED_DROP_LISTENER_TIMEOUT)); - // Force trigger the timeout and verify that it actually cleans up the drag & timeout - handler.handleMessage(Message.obtain(handler, MSG_UNHANDLED_DROP_LISTENER_TIMEOUT)); - assertFalse(handler.hasMessages(MSG_UNHANDLED_DROP_LISTENER_TIMEOUT)); - assertFalse(mTarget.dragDropActiveLocked()); - mToken = null; - }); + // Force trigger the timeout and verify that it actually cleans up the drag & + // timeout + handler.handleMessage( + Message.obtain(handler, MSG_UNHANDLED_DROP_LISTENER_TIMEOUT)); + assertFalse(handler.hasMessages(MSG_UNHANDLED_DROP_LISTENER_TIMEOUT)); + assertFalse(mTarget.dragDropActiveLocked()); + mToken = null; + }); } private void doDragAndDrop(int flags, ClipData data, float dropX, float dropY) { @@ -690,15 +684,13 @@ public class DragDropControllerTests extends WindowTestsBase { private void startDrag(int flag, ClipData data, Runnable r) { final SurfaceSession appSession = new SurfaceSession(); try { - final SurfaceControl surface = new SurfaceControl.Builder(appSession) - .setName("drag surface") - .setBufferSize(100, 100) - .setFormat(PixelFormat.TRANSLUCENT) - .build(); + final SurfaceControl surface = new SurfaceControl.Builder(appSession).setName( + "drag surface").setBufferSize(100, 100).setFormat( + PixelFormat.TRANSLUCENT).build(); assertTrue(mWm.mInputManager.startDragAndDrop(new Binder(), new Binder())); - mToken = mTarget.performDrag(TEST_PID, 0, mWindow.mClient, - flag, surface, 0, 0, 0, 0, 0, 0, 0, data); + mToken = mTarget.performDrag(TEST_PID, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, + 0, 0, data); assertNotNull(mToken); r.run(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index b27025c34d6b..b61dada809d8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -89,6 +89,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; +import android.tools.function.Supplier; import android.util.MergedConfiguration; import android.util.SparseArray; import android.view.Display; @@ -1804,6 +1805,124 @@ public class WindowTestsBase extends SystemServiceTestsBase { } } + protected WindowStateBuilder newWindowBuilder(String name, int type) { + return new WindowStateBuilder(name, type, mWm, mDisplayContent, mIWindow, + this::getTestSession, this::createWindowToken); + } + + /** + * Builder for creating new window. + */ + protected static class WindowStateBuilder { + private final String mName; + private final int mType; + private final WindowManagerService mWm; + private final DisplayContent mDefaultTargetDisplay; + private final Supplier<WindowToken, Session> mSessionSupplier; + private final WindowTokenCreator mWindowTokenCreator; + + private int mActivityType = ACTIVITY_TYPE_STANDARD; + private IWindow mClientWindow; + private boolean mOwnerCanAddInternalSystemWindow = false; + private int mOwnerId = 0; + private WindowState mParent; + private DisplayContent mTargetDisplay; + private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; + private WindowToken mWindowToken; + + WindowStateBuilder(String name, int type, WindowManagerService windowManagerService, + DisplayContent dc, IWindow iWindow, Supplier<WindowToken, Session> sessionSupplier, + WindowTokenCreator windowTokenCreator) { + mName = name; + mType = type; + mClientWindow = iWindow; + mDefaultTargetDisplay = dc; + mSessionSupplier = sessionSupplier; + mWindowTokenCreator = windowTokenCreator; + mWm = windowManagerService; + } + + WindowStateBuilder setActivityType(int activityType) { + mActivityType = activityType; + return this; + } + + WindowStateBuilder setClientWindow(IWindow clientWindow) { + mClientWindow = clientWindow; + return this; + } + + WindowStateBuilder setDisplay(DisplayContent displayContent) { + mTargetDisplay = displayContent; + return this; + } + + WindowStateBuilder setOwnerCanAddInternalSystemWindow( + boolean ownerCanAddInternalSystemWindow) { + mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow; + return this; + } + + WindowStateBuilder setOwnerId(int ownerId) { + mOwnerId = ownerId; + return this; + } + + WindowStateBuilder setParent(WindowState parent) { + mParent = parent; + return this; + } + + WindowStateBuilder setWindowToken(WindowToken token) { + mWindowToken = token; + return this; + } + + WindowStateBuilder setWindowingMode(int windowingMode) { + mWindowingMode = windowingMode; + return this; + } + + WindowState build() { + SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock); + + final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(mType); + attrs.setTitle(mName); + attrs.packageName = "test"; + + assertFalse( + "targetDisplay shouldn't be specified together with windowToken, since" + + " windowToken will be derived from targetDisplay.", + mWindowToken != null && mTargetDisplay != null); + + if (mWindowToken == null) { + if (mTargetDisplay != null) { + mWindowToken = mWindowTokenCreator.createWindowToken(mTargetDisplay, + mWindowingMode, mActivityType, mType); + } else if (mParent != null) { + mWindowToken = mParent.mToken; + } else { + // Use default mDisplayContent as window token. + mWindowToken = mWindowTokenCreator.createWindowToken(mDefaultTargetDisplay, + mWindowingMode, mActivityType, mType); + } + } + + final WindowState w = new WindowState(mWm, mSessionSupplier.get(mWindowToken), + mClientWindow, mWindowToken, mParent, OP_NONE, attrs, VISIBLE, mOwnerId, + UserHandle.getUserId(mOwnerId), mOwnerCanAddInternalSystemWindow); + // TODO: Probably better to make this call in the WindowState ctor to avoid errors with + // adding it to the token... + mWindowToken.addWindow(w); + return w; + } + + interface WindowTokenCreator { + WindowToken createWindowToken(DisplayContent dc, int windowingMode, int activityType, + int type); + } + } + static class TestStartingWindowOrganizer extends WindowOrganizerTests.StubOrganizer { private final ActivityTaskManagerService mAtm; private final WindowManagerService mWMService; diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java index c508fa968b14..ce3cd29a3ce2 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java @@ -26,6 +26,7 @@ import android.util.Slog; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.audio.AudioService; +import com.android.server.usb.flags.Flags; import java.util.Arrays; @@ -211,6 +212,9 @@ public final class UsbAlsaDevice { mIsSelected[direction] = true; mState[direction] = 0; startJackDetect(); + if (direction == OUTPUT && Flags.maximizeUsbAudioVolumeWhenConnecting()) { + nativeSetVolume(mCardNum, 1.0f /*volume*/); + } updateWiredDeviceConnectionState(direction, true /*enable*/); } @@ -412,5 +416,7 @@ public final class UsbAlsaDevice { return result; } + + private native void nativeSetVolume(int card, float volume); } diff --git a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig index a2d0efd1d063..dfbd74c1f3e1 100644 --- a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig +++ b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig @@ -21,3 +21,10 @@ flag { description: "This flag checks if phone is unlocked after boot" bug: "73654179" } + +flag { + name: "maximize_usb_audio_volume_when_connecting" + namespace: "usb" + description: "This flag maximizes the usb audio volume when it is connected" + bug: "245041322" +} |