Merge "Support HDMI hotplug." into jb-mr1-dev
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -685,7 +684,24 @@ public final class Choreographer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVsync(long timestampNanos, int frame) {
|
||||
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
|
||||
// Ignore vsync from secondary display.
|
||||
// This can be problematic because the call to scheduleVsync() is a one-shot.
|
||||
// We need to ensure that we will still receive the vsync from the primary
|
||||
// display which is the one we really care about. Ideally we should schedule
|
||||
// vsync for a particular display.
|
||||
// At this time Surface Flinger won't send us vsyncs for secondary displays
|
||||
// but that could change in the future so let's log a message to help us remember
|
||||
// that we need to fix this.
|
||||
if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) {
|
||||
Log.d(TAG, "Received vsync from secondary display, but we don't support "
|
||||
+ "this case yet. Choreographer needs a way to explicitly request "
|
||||
+ "vsync for a specific display to ensure it doesn't lose track "
|
||||
+ "of its scheduled vsync.");
|
||||
scheduleVsync();
|
||||
return;
|
||||
}
|
||||
|
||||
// Post the vsync event to the Handler.
|
||||
// The idea is to prevent incoming vsync events from completely starving
|
||||
// the message queue. If there are no messages in the queue with timestamps
|
||||
|
||||
@@ -101,9 +101,23 @@ public abstract class DisplayEventReceiver {
|
||||
*
|
||||
* @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
|
||||
* timebase.
|
||||
* @param builtInDisplayId The surface flinger built-in display id such as
|
||||
* {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}.
|
||||
* @param frame The frame number. Increases by one for each vertical sync interval.
|
||||
*/
|
||||
public void onVsync(long timestampNanos, int frame) {
|
||||
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a display hotplug event is received.
|
||||
*
|
||||
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
|
||||
* timebase.
|
||||
* @param builtInDisplayId The surface flinger built-in display id such as
|
||||
* {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}.
|
||||
* @param connected True if the display is connected, false if it disconnected.
|
||||
*/
|
||||
public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +135,13 @@ public abstract class DisplayEventReceiver {
|
||||
|
||||
// Called from native code.
|
||||
@SuppressWarnings("unused")
|
||||
private void dispatchVsync(long timestampNanos, int frame) {
|
||||
onVsync(timestampNanos, frame);
|
||||
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
|
||||
onVsync(timestampNanos, builtInDisplayId, frame);
|
||||
}
|
||||
|
||||
// Called from native code.
|
||||
@SuppressWarnings("unused")
|
||||
private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
|
||||
onHotplug(timestampNanos, builtInDisplayId, connected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ static struct {
|
||||
jclass clazz;
|
||||
|
||||
jmethodID dispatchVsync;
|
||||
jmethodID dispatchHotplug;
|
||||
} gDisplayEventReceiverClassInfo;
|
||||
|
||||
|
||||
@@ -61,7 +62,9 @@ private:
|
||||
bool mWaitingForVsync;
|
||||
|
||||
virtual int handleEvent(int receiveFd, int events, void* data);
|
||||
bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount);
|
||||
bool readLastVsyncMessage(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
|
||||
void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
|
||||
void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
|
||||
};
|
||||
|
||||
|
||||
@@ -106,8 +109,9 @@ status_t NativeDisplayEventReceiver::scheduleVsync() {
|
||||
|
||||
// Drain all pending events.
|
||||
nsecs_t vsyncTimestamp;
|
||||
int32_t vsyncDisplayId;
|
||||
uint32_t vsyncCount;
|
||||
readLastVsyncMessage(&vsyncTimestamp, &vsyncCount);
|
||||
readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
|
||||
|
||||
status_t status = mReceiver.requestNextVsync();
|
||||
if (status) {
|
||||
@@ -135,39 +139,39 @@ int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* dat
|
||||
|
||||
// Drain all pending events, keep the last vsync.
|
||||
nsecs_t vsyncTimestamp;
|
||||
int32_t vsyncDisplayId;
|
||||
uint32_t vsyncCount;
|
||||
if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) {
|
||||
if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
|
||||
ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
|
||||
return 1; // keep the callback, did not obtain a vsync pulse
|
||||
}
|
||||
|
||||
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
|
||||
this, vsyncTimestamp, vsyncCount);
|
||||
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d",
|
||||
this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
|
||||
mWaitingForVsync = false;
|
||||
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
ALOGV("receiver %p ~ Invoking vsync handler.", this);
|
||||
env->CallVoidMethod(mReceiverObjGlobal,
|
||||
gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
|
||||
ALOGV("receiver %p ~ Returned from vsync handler.", this);
|
||||
|
||||
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
|
||||
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
|
||||
return 1; // keep the callback
|
||||
}
|
||||
|
||||
bool NativeDisplayEventReceiver::readLastVsyncMessage(
|
||||
nsecs_t* outTimestamp, uint32_t* outCount) {
|
||||
nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
|
||||
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
|
||||
ssize_t n;
|
||||
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
|
||||
ALOGV("receiver %p ~ Read %d events.", this, int(n));
|
||||
while (n-- > 0) {
|
||||
if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
|
||||
*outTimestamp = buf[n].header.timestamp;
|
||||
*outCount = buf[n].vsync.count;
|
||||
const DisplayEventReceiver::Event& ev = buf[n];
|
||||
if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
|
||||
*outTimestamp = ev.header.timestamp;
|
||||
*outId = ev.header.id;
|
||||
*outCount = ev.vsync.count;
|
||||
return true; // stop at last vsync in the buffer
|
||||
}
|
||||
|
||||
if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
|
||||
dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n < 0) {
|
||||
@@ -176,6 +180,28 @@ bool NativeDisplayEventReceiver::readLastVsyncMessage(
|
||||
return false;
|
||||
}
|
||||
|
||||
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
ALOGV("receiver %p ~ Invoking vsync handler.", this);
|
||||
env->CallVoidMethod(mReceiverObjGlobal,
|
||||
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
|
||||
ALOGV("receiver %p ~ Returned from vsync handler.", this);
|
||||
|
||||
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
|
||||
}
|
||||
|
||||
void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
ALOGV("receiver %p ~ Invoking hotplug handler.", this);
|
||||
env->CallVoidMethod(mReceiverObjGlobal,
|
||||
gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
|
||||
ALOGV("receiver %p ~ Returned from hotplug handler.", this);
|
||||
|
||||
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
|
||||
}
|
||||
|
||||
|
||||
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
|
||||
jobject messageQueueObj) {
|
||||
@@ -248,7 +274,10 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
|
||||
|
||||
GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
|
||||
gDisplayEventReceiverClassInfo.clazz,
|
||||
"dispatchVsync", "(JI)V");
|
||||
"dispatchVsync", "(JII)V");
|
||||
GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
|
||||
gDisplayEventReceiverClassInfo.clazz,
|
||||
"dispatchHotplug", "(JIZ)V");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -536,6 +536,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
|
||||
|
||||
mDisplayDevices.add(device);
|
||||
addLogicalDisplayLocked(device);
|
||||
scheduleTraversalLocked();
|
||||
@@ -550,6 +552,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
|
||||
|
||||
device.applyPendingDisplayDeviceInfoChangesLocked();
|
||||
if (updateLogicalDisplaysLocked()) {
|
||||
scheduleTraversalLocked();
|
||||
@@ -565,6 +569,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
|
||||
|
||||
mRemovedDisplayDevices.add(device);
|
||||
updateLogicalDisplaysLocked();
|
||||
scheduleTraversalLocked();
|
||||
|
||||
@@ -19,7 +19,9 @@ package com.android.server.display;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.util.SparseArray;
|
||||
import android.view.DisplayEventReceiver;
|
||||
import android.view.Surface;
|
||||
import android.view.Surface.PhysicalDisplayInfo;
|
||||
|
||||
@@ -41,12 +43,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|
||||
|
||||
private final SparseArray<LocalDisplayDevice> mDevices =
|
||||
new SparseArray<LocalDisplayDevice>();
|
||||
private final HotplugDisplayEventReceiver mHotplugReceiver;
|
||||
|
||||
private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
|
||||
|
||||
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
|
||||
Context context, Handler handler, Listener listener) {
|
||||
super(syncRoot, context, handler, listener, TAG);
|
||||
mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,4 +152,17 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|
||||
pw.println("mPhys=" + mPhys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
|
||||
public HotplugDisplayEventReceiver(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
|
||||
synchronized (getSyncRoot()) {
|
||||
scanDisplaysLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user