From 989de3d470dca6df8319be87c8f60c0fdc092b25 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 27 Jul 2021 21:09:34 -0700 Subject: Use ui::LayerStack Bug: 182939859 Test: Build Change-Id: I4658471996939713a6330a9c4a7d05cf4c91833a --- libs/input/SpriteController.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libs/input/SpriteController.cpp') diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index acd8bced0612..12c6a32bd0ad 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -169,7 +169,8 @@ void SpriteController::doUpdateSprites() { // If surface is a new one, we have to set right layer stack. if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) { - t.setLayerStack(update.state.surfaceControl, update.state.displayId); + t.setLayerStack(update.state.surfaceControl, + ui::LayerStack::fromValue(update.state.displayId)); needApplyTransaction = true; } } -- cgit v1.2.3-59-g8ed1b From fef0c61c9ccc1c0ca08ef4e8538d86d5e892e682 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 4 Nov 2021 14:08:50 -0700 Subject: SpriteController: Reparent pointer surfaces under DisplayContent When using MediaProjection to mirror a display, only surfaces that are inside the mirrored DisplayContent's hierarcy show up in the mirror surface. Previously, since pointer icons created by SpriteController were not part of SF's hierarcy under the DisplayContent's SurfaceControl, they did not show up in the mirror surface. In this CL, we reparent pointer sprite surfaces to the the DisplayContent's SurfaceControl whenever there are surface changes, ensuring that they show up in screen recordings. Bug: 202258016 Test: manual: Start screen recording from quick settings tile Change-Id: Ib404ed36bd13b0fc8cc4a6fb593dc54b3e35dd1a --- libs/input/SpriteController.cpp | 11 +++++---- libs/input/SpriteController.h | 4 +++- libs/input/tests/mocks/MockSpriteController.h | 3 ++- .../android/server/input/InputManagerService.java | 16 +++++++++++++ .../android/server/wm/InputManagerCallback.java | 14 +++++++++++ ...om_android_server_input_InputManagerService.cpp | 27 ++++++++++++++++++---- 6 files changed, 63 insertions(+), 12 deletions(-) (limited to 'libs/input/SpriteController.cpp') diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index 0c6dac02453a..da21438bafd1 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -27,10 +27,12 @@ namespace android { // --- SpriteController --- -SpriteController::SpriteController(const sp& looper, int32_t overlayLayer) : - mLooper(looper), mOverlayLayer(overlayLayer) { +SpriteController::SpriteController(const sp& looper, int32_t overlayLayer, + ParentSurfaceProvider parentSurfaceProvider) + : mLooper(looper), + mOverlayLayer(overlayLayer), + mParentSurfaceProvider(std::move(parentSurfaceProvider)) { mHandler = new WeakMessageHandler(this); - mLocked.transactionNestingCount = 0; mLocked.deferredSpriteUpdate = false; } @@ -168,8 +170,7 @@ void SpriteController::doUpdateSprites() { // If surface is a new one, we have to set right layer stack. if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) { - t.setLayerStack(update.state.surfaceControl, - ui::LayerStack::fromValue(update.state.displayId)); + t.reparent(update.state.surfaceControl, mParentSurfaceProvider(update.state.displayId)); needApplyTransaction = true; } } diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h index 137b5646feae..2a80d9579711 100644 --- a/libs/input/SpriteController.h +++ b/libs/input/SpriteController.h @@ -114,7 +114,8 @@ protected: virtual ~SpriteController(); public: - SpriteController(const sp& looper, int32_t overlayLayer); + using ParentSurfaceProvider = std::function(int /*displayId*/)>; + SpriteController(const sp& looper, int32_t overlayLayer, ParentSurfaceProvider parent); /* Creates a new sprite, initially invisible. */ virtual sp createSprite(); @@ -245,6 +246,7 @@ private: sp mLooper; const int32_t mOverlayLayer; sp mHandler; + ParentSurfaceProvider mParentSurfaceProvider; sp mSurfaceComposerClient; diff --git a/libs/input/tests/mocks/MockSpriteController.h b/libs/input/tests/mocks/MockSpriteController.h index a034f66c9abf..62f1d65e77a5 100644 --- a/libs/input/tests/mocks/MockSpriteController.h +++ b/libs/input/tests/mocks/MockSpriteController.h @@ -26,7 +26,8 @@ namespace android { class MockSpriteController : public SpriteController { public: - MockSpriteController(sp looper) : SpriteController(looper, 0) {} + MockSpriteController(sp looper) + : SpriteController(looper, 0, [](int) { return nullptr; }) {} ~MockSpriteController() {} MOCK_METHOD(sp, createSprite, (), (override)); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 15d2a056ffbb..3d04037185f3 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -98,6 +98,7 @@ import android.view.InputMonitor; import android.view.KeyEvent; import android.view.PointerIcon; import android.view.Surface; +import android.view.SurfaceControl; import android.view.VerifiedInputEvent; import android.view.ViewConfiguration; import android.widget.Toast; @@ -2906,6 +2907,15 @@ public class InputManagerService extends IInputManager.Stub return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId)); } + // Native callback. + private long getParentSurfaceForPointers(int displayId) { + final SurfaceControl sc = mWindowManagerCallbacks.getParentSurfaceForPointers(displayId); + if (sc == null) { + return 0; + } + return sc.mNativeObject; + } + @NonNull private Context getContextForPointerIcon(int displayId) { if (mPointerIconDisplayContext != null @@ -3105,6 +3115,12 @@ public class InputManagerService extends IInputManager.Stub * Called when the drag over window has changed. */ void notifyDropWindow(IBinder token, float x, float y); + + /** + * Get the {@link SurfaceControl} that should be the parent for the surfaces created for + * pointers such as the mouse cursor and touch spots for the given display. + */ + SurfaceControl getParentSurfaceForPointers(int displayId); } /** diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 18a2c601f6d3..e02e7c5ab15d 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -29,6 +29,7 @@ import android.os.IBinder; import android.util.Slog; import android.view.InputApplicationHandle; import android.view.KeyEvent; +import android.view.SurfaceControl; import android.view.WindowManager; import android.view.WindowManagerPolicyConstants; @@ -234,6 +235,19 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal mService.mDragDropController::reportDropWindow, token, x, y)); } + @Override + public SurfaceControl getParentSurfaceForPointers(int displayId) { + synchronized (mService.mGlobalLock) { + final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); + if (dc == null) { + Slog.e(TAG, "Failed to get parent surface for pointers on display " + displayId + + " - DisplayContent not found."); + return null; + } + return dc.getOverlayLayer(); + } + } + /** Waits until the built-in input devices have been configured. */ public boolean waitForInputDevicesReady(long timeoutMillis) { synchronized (mInputDevicesReadyMonitor) { diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 790acbf2cd23..85e7f7b5226b 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -129,6 +129,7 @@ static struct { jmethodID getTouchCalibrationForInputDevice; jmethodID getContextForDisplay; jmethodID notifyDropWindow; + jmethodID getParentSurfaceForPointers; } gServiceClassInfo; static struct { @@ -390,7 +391,7 @@ private: void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags); void ensureSpriteControllerLocked(); int32_t getPointerDisplayId(); - void updatePointerDisplayLocked(); + sp getParentSurfaceForPointers(int displayId); static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); static inline JNIEnv* jniEnv() { @@ -669,6 +670,18 @@ int32_t NativeInputManager::getPointerDisplayId() { return pointerDisplayId; } +sp NativeInputManager::getParentSurfaceForPointers(int displayId) { + JNIEnv* env = jniEnv(); + jlong nativeSurfaceControlPtr = + env->CallLongMethod(mServiceObj, gServiceClassInfo.getParentSurfaceForPointers, + displayId); + if (checkAndClearExceptionFromCallback(env, "getParentSurfaceForPointers")) { + return nullptr; + } + + return reinterpret_cast(nativeSurfaceControlPtr); +} + void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) { if (mLocked.spriteController == nullptr) { JNIEnv* env = jniEnv(); @@ -676,7 +689,9 @@ void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) { if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) { layer = -1; } - mLocked.spriteController = new SpriteController(mLooper, layer); + mLocked.spriteController = new SpriteController(mLooper, layer, [this](int displayId) { + return getParentSurfaceForPointers(displayId); + }); } } @@ -2504,9 +2519,11 @@ int register_android_server_InputManager(JNIEnv* env) { "getTouchCalibrationForInputDevice", "(Ljava/lang/String;I)Landroid/hardware/input/TouchCalibration;"); - GET_METHOD_ID(gServiceClassInfo.getContextForDisplay, clazz, - "getContextForDisplay", - "(I)Landroid/content/Context;") + GET_METHOD_ID(gServiceClassInfo.getContextForDisplay, clazz, "getContextForDisplay", + "(I)Landroid/content/Context;"); + + GET_METHOD_ID(gServiceClassInfo.getParentSurfaceForPointers, clazz, + "getParentSurfaceForPointers", "(I)J"); // InputDevice -- cgit v1.2.3-59-g8ed1b From 3f8b28918dac53c2418bf72b139a97a854a6626d Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 18 Nov 2021 08:55:02 -0800 Subject: SpriteController: Reparent SurfaceControls to null before disposing Bug: 206650086 Test: manual: see repro insructions in the bug Change-Id: Ib8e39780002ecb74ade64791bdb98b8b9c969bce --- libs/input/SpriteController.cpp | 19 +++++++++++++------ libs/input/SpriteController.h | 4 ++-- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'libs/input/SpriteController.cpp') diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index da21438bafd1..2b809eab4ae4 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -70,8 +70,8 @@ void SpriteController::closeTransaction() { } void SpriteController::invalidateSpriteLocked(const sp& sprite) { - bool wasEmpty = mLocked.invalidatedSprites.isEmpty(); - mLocked.invalidatedSprites.push(sprite); + bool wasEmpty = mLocked.invalidatedSprites.empty(); + mLocked.invalidatedSprites.push_back(sprite); if (wasEmpty) { if (mLocked.transactionNestingCount != 0) { mLocked.deferredSpriteUpdate = true; @@ -82,8 +82,8 @@ void SpriteController::invalidateSpriteLocked(const sp& sprite) { } void SpriteController::disposeSurfaceLocked(const sp& surfaceControl) { - bool wasEmpty = mLocked.disposedSurfaces.isEmpty(); - mLocked.disposedSurfaces.push(surfaceControl); + bool wasEmpty = mLocked.disposedSurfaces.empty(); + mLocked.disposedSurfaces.push_back(surfaceControl); if (wasEmpty) { mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); } @@ -113,7 +113,7 @@ void SpriteController::doUpdateSprites() { numSprites = mLocked.invalidatedSprites.size(); for (size_t i = 0; i < numSprites; i++) { - const sp& sprite = mLocked.invalidatedSprites.itemAt(i); + const sp& sprite = mLocked.invalidatedSprites[i]; updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); sprite->resetDirtyLocked(); @@ -305,7 +305,7 @@ void SpriteController::doUpdateSprites() { void SpriteController::doDisposeSurfaces() { // Collect disposed surfaces. - Vector > disposedSurfaces; + std::vector> disposedSurfaces; { // acquire lock AutoMutex _l(mLock); @@ -313,6 +313,13 @@ void SpriteController::doDisposeSurfaces() { mLocked.disposedSurfaces.clear(); } // release lock + // Remove the parent from all surfaces. + SurfaceComposerClient::Transaction t; + for (const sp& sc : disposedSurfaces) { + t.reparent(sc, nullptr); + } + t.apply(); + // Release the last reference to each surface outside of the lock. // We don't want the surfaces to be deleted while we are holding our lock. disposedSurfaces.clear(); diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h index 2a80d9579711..2e9cb9685c46 100644 --- a/libs/input/SpriteController.h +++ b/libs/input/SpriteController.h @@ -251,8 +251,8 @@ private: sp mSurfaceComposerClient; struct Locked { - Vector > invalidatedSprites; - Vector > disposedSurfaces; + std::vector> invalidatedSprites; + std::vector> disposedSurfaces; uint32_t transactionNestingCount; bool deferredSpriteUpdate; } mLocked; // guarded by mLock -- cgit v1.2.3-59-g8ed1b