diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 3e8002f4634dc..60daddd663d5d 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -155,6 +155,17 @@ public abstract class DisplayEventReceiver { public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { } + /** + * Called when a display config changed event is received. + * + * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} + * timebase. + * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. + * @param configId The new config Id + */ + public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { + } + /** * Schedules a single vertical sync pulse to be delivered when the next * display frame begins. @@ -182,4 +193,11 @@ public abstract class DisplayEventReceiver { private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { onHotplug(timestampNanos, physicalDisplayId, connected); } + + // Called from native code. + @SuppressWarnings("unused") + private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { + onConfigChanged(timestampNanos, physicalDisplayId, configId); + } + } diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 191472d086f6a..8d702d11d8fea 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -41,6 +41,7 @@ static struct { jmethodID dispatchVsync; jmethodID dispatchHotplug; + jmethodID dispatchConfigChanged; } gDisplayEventReceiverClassInfo; @@ -61,6 +62,8 @@ private: void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override; void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; + void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, + int32_t configId) override; }; @@ -114,6 +117,23 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp mMessageQueue->raiseAndClearException(env, "dispatchHotplug"); } +void NativeDisplayEventReceiver::dispatchConfigChanged(nsecs_t timestamp, + PhysicalDisplayId displayId, + int32_t configId) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + ScopedLocalRef receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); + if (receiverObj.get()) { + ALOGV("receiver %p ~ Invoking config changed handler.", this); + env->CallVoidMethod(receiverObj.get(), + gDisplayEventReceiverClassInfo.dispatchConfigChanged, + timestamp, displayId, configId); + ALOGV("receiver %p ~ Returned from config changed handler.", this); + } + + mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged"); +} + static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj, jint vsyncSource) { @@ -180,6 +200,8 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V"); gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V"); + gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env, + gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V"); return res; } diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp index 3b9a348047baa..6606148956031 100644 --- a/libs/androidfw/DisplayEventDispatcher.cpp +++ b/libs/androidfw/DisplayEventDispatcher.cpp @@ -135,6 +135,9 @@ bool DisplayEventDispatcher::processPendingEvents( case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); break; + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, ev.config.configId); + break; default: ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type); break; diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h index d2addba61679b..5381c0174cb0b 100644 --- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h +++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h @@ -40,6 +40,8 @@ private: virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0; virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) = 0; + virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, + int32_t configId) = 0; virtual int handleEvent(int receiveFd, int events, void* data); bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp index 2db575bf5a134..3fecd53b43e21 100644 --- a/native/android/choreographer.cpp +++ b/native/android/choreographer.cpp @@ -70,6 +70,8 @@ private: void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override; void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; + void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, + int32_t configId) override; void scheduleCallbacks(); @@ -164,6 +166,13 @@ void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool c this, displayId, toString(connected)); } +void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, + int32_t configId) { + ALOGV("choreographer %p ~ received config changed event (displayId=%" + ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.", + this, displayId, toString(configId)); +} + void Choreographer::handleMessage(const Message& message) { switch (message.what) { case MSG_SCHEDULE_CALLBACKS: diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 489194726c5a0..77df10bf536aa 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -65,7 +65,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { new LongSparseArray(); @SuppressWarnings("unused") // Becomes active at instantiation time. - private HotplugDisplayEventReceiver mHotplugReceiver; + private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver; + // Called with SyncRoot lock held. public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, @@ -77,7 +78,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { public void registerLocked() { super.registerLocked(); - mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper()); + mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper()); for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) { tryConnectDisplayLocked(physicalDisplayId); @@ -727,8 +728,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } - private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { - public HotplugDisplayEventReceiver(Looper looper) { + private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver { + PhysicalDisplayEventReceiver(Looper looper) { super(looper, VSYNC_SOURCE_APP); } @@ -742,5 +743,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } } + + @Override + public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { + if (DEBUG) { + Slog.d(TAG, "onConfigChanged(" + + "timestampNanos=" + timestampNanos + + ", builtInDisplayId=" + physicalDisplayId + + ", configId=" + configId + ")"); + } + } } }