10a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown/*
20a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * Copyright (C) 2011 The Android Open Source Project
30a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown *
40a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
50a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * you may not use this file except in compliance with the License.
60a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * You may obtain a copy of the License at
70a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown *
80a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
90a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown *
100a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * Unless required by applicable law or agreed to in writing, software
110a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
120a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * See the License for the specific language governing permissions and
140a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown * limitations under the License.
150a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown */
160a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
170a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#define LOG_TAG "DisplayEventReceiver"
180a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
190a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown//#define LOG_NDEBUG 0
200a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
210a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
220a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include "JNIHelp.h"
230a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
240a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <android_runtime/AndroidRuntime.h>
250a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <utils/Log.h>
260a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <utils/Looper.h>
270a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <utils/threads.h>
280a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <gui/DisplayEventReceiver.h>
290a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include "android_os_MessageQueue.h"
300a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
310a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownnamespace android {
320a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
330a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown// Number of events to read at a time from the DisplayEventReceiver pipe.
340a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown// The value should be large enough that we can quickly drain the pipe
350a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown// using just a few large reads.
360a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownstatic const size_t EVENT_BUFFER_SIZE = 100;
370a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
380a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownstatic struct {
390a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    jclass clazz;
400a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
410a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    jmethodID dispatchVsync;
42e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    jmethodID dispatchHotplug;
430a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown} gDisplayEventReceiverClassInfo;
440a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
450a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
4680a1de1007ddc62e1af2a4746008f499145aeaabJeff Brownclass NativeDisplayEventReceiver : public LooperCallback {
470a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownpublic:
480a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    NativeDisplayEventReceiver(JNIEnv* env,
49603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            jobject receiverObj, const sp<MessageQueue>& messageQueue);
500a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
510a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    status_t initialize();
5280a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown    void dispose();
530a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    status_t scheduleVsync();
540a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
550a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownprotected:
560a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    virtual ~NativeDisplayEventReceiver();
570a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
580a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownprivate:
590a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    jobject mReceiverObjGlobal;
60603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    sp<MessageQueue> mMessageQueue;
610a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    DisplayEventReceiver mReceiver;
620a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    bool mWaitingForVsync;
63bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown
6480a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown    virtual int handleEvent(int receiveFd, int events, void* data);
6516823bd611689e9b5c0e1b675fee43579f85612aJesse Hall    bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
66e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
67e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
680a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown};
690a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
700a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
710a0a1248cfc03940174cbd9af677bafd7280a3bcJeff BrownNativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
72603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        jobject receiverObj, const sp<MessageQueue>& messageQueue) :
730a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
74603b44589682db3ff33ade172facb0c5e309f1beJeff Brown        mMessageQueue(messageQueue), mWaitingForVsync(false) {
750a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    ALOGV("receiver %p ~ Initializing input event receiver.", this);
760a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
770a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
780a0a1248cfc03940174cbd9af677bafd7280a3bcJeff BrownNativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
790a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    JNIEnv* env = AndroidRuntime::getJNIEnv();
800a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    env->DeleteGlobalRef(mReceiverObjGlobal);
810a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
820a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
830a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownstatus_t NativeDisplayEventReceiver::initialize() {
840a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    status_t result = mReceiver.initCheck();
850a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    if (result) {
868564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("Failed to initialize display event receiver, status=%d", result);
870a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        return result;
880a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
890a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
9082b007d7572dceb0981b269338bd1ac6c40496c5Brian Carlstrom    int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
9180a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown            this, NULL);
9258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    if (rc < 0) {
9358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        return UNKNOWN_ERROR;
9458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
950a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    return OK;
960a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
970a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
9880a1de1007ddc62e1af2a4746008f499145aeaabJeff Brownvoid NativeDisplayEventReceiver::dispose() {
9980a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown    ALOGV("receiver %p ~ Disposing display event receiver.", this);
10080a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown
10180a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown    if (!mReceiver.initCheck()) {
10280a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown        mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
10380a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown    }
10480a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown}
10580a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown
1060a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownstatus_t NativeDisplayEventReceiver::scheduleVsync() {
1070a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    if (!mWaitingForVsync) {
1080a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        ALOGV("receiver %p ~ Scheduling vsync.", this);
1090a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
1100a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        // Drain all pending events.
111bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown        nsecs_t vsyncTimestamp;
112e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        int32_t vsyncDisplayId;
113bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown        uint32_t vsyncCount;
11416823bd611689e9b5c0e1b675fee43579f85612aJesse Hall        processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
1150a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
1166779df2c28a68616134b1988f009221652d9f2adMathias Agopian        status_t status = mReceiver.requestNextVsync();
1176779df2c28a68616134b1988f009221652d9f2adMathias Agopian        if (status) {
1188564c8da817a845353d213acd8636b76f567b234Steve Block            ALOGW("Failed to request next vsync, status=%d", status);
1196779df2c28a68616134b1988f009221652d9f2adMathias Agopian            return status;
1206779df2c28a68616134b1988f009221652d9f2adMathias Agopian        }
1216779df2c28a68616134b1988f009221652d9f2adMathias Agopian
1220a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        mWaitingForVsync = true;
1230a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
1240a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    return OK;
1250a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
1260a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
12780a1de1007ddc62e1af2a4746008f499145aeaabJeff Brownint NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
12882b007d7572dceb0981b269338bd1ac6c40496c5Brian Carlstrom    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
1293762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Display event receiver pipe was closed or an error occurred.  "
1300a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown                "events=0x%x", events);
1310a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        return 0; // remove the callback
1320a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
1330a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
13482b007d7572dceb0981b269338bd1ac6c40496c5Brian Carlstrom    if (!(events & Looper::EVENT_INPUT)) {
1358564c8da817a845353d213acd8636b76f567b234Steve Block        ALOGW("Received spurious callback for unhandled poll event.  "
1360a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown                "events=0x%x", events);
1370a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        return 1; // keep the callback
1380a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
1390a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
1400a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    // Drain all pending events, keep the last vsync.
141bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    nsecs_t vsyncTimestamp;
142e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    int32_t vsyncDisplayId;
143bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    uint32_t vsyncCount;
14416823bd611689e9b5c0e1b675fee43579f85612aJesse Hall    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
14516823bd611689e9b5c0e1b675fee43579f85612aJesse Hall        ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d",
14616823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
14716823bd611689e9b5c0e1b675fee43579f85612aJesse Hall        mWaitingForVsync = false;
14816823bd611689e9b5c0e1b675fee43579f85612aJesse Hall        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
1490a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
1500a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
15158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    return 1; // keep the callback
1520a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
1530a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
15416823bd611689e9b5c0e1b675fee43579f85612aJesse Hallbool NativeDisplayEventReceiver::processPendingEvents(
155e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
15616823bd611689e9b5c0e1b675fee43579f85612aJesse Hall    bool gotVsync = false;
157bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
158bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    ssize_t n;
159bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
160bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown        ALOGV("receiver %p ~ Read %d events.", this, int(n));
16116823bd611689e9b5c0e1b675fee43579f85612aJesse Hall        for (ssize_t i = 0; i < n; i++) {
16216823bd611689e9b5c0e1b675fee43579f85612aJesse Hall            const DisplayEventReceiver::Event& ev = buf[i];
16316823bd611689e9b5c0e1b675fee43579f85612aJesse Hall            switch (ev.header.type) {
16416823bd611689e9b5c0e1b675fee43579f85612aJesse Hall            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
16516823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                // Later vsync events will just overwrite the info from earlier
16616823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                // ones. That's fine, we only care about the most recent.
16716823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                gotVsync = true;
168e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                *outTimestamp = ev.header.timestamp;
169e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                *outId = ev.header.id;
170e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                *outCount = ev.vsync.count;
17116823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                break;
17216823bd611689e9b5c0e1b675fee43579f85612aJesse Hall            case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
173e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
17416823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                break;
17516823bd611689e9b5c0e1b675fee43579f85612aJesse Hall            default:
17616823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                ALOGW("receiver %p ~ ignoring unknown event type %#x", this, ev.header.type);
17716823bd611689e9b5c0e1b675fee43579f85612aJesse Hall                break;
178e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            }
179bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown        }
180bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    }
181bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    if (n < 0) {
182bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown        ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
183bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown    }
18416823bd611689e9b5c0e1b675fee43579f85612aJesse Hall    return gotVsync;
185bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown}
186bec0a8682c75a40df6d0dca17e23db2103a950f3Jeff Brown
187e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brownvoid NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
188e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    JNIEnv* env = AndroidRuntime::getJNIEnv();
189e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
190e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    ALOGV("receiver %p ~ Invoking vsync handler.", this);
191e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    env->CallVoidMethod(mReceiverObjGlobal,
192e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
193e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    ALOGV("receiver %p ~ Returned from vsync handler.", this);
194e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
195e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    mMessageQueue->raiseAndClearException(env, "dispatchVsync");
196e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown}
197e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
198e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brownvoid NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
199e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    JNIEnv* env = AndroidRuntime::getJNIEnv();
200e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
201e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    ALOGV("receiver %p ~ Invoking hotplug handler.", this);
202e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    env->CallVoidMethod(mReceiverObjGlobal,
203e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
204e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    ALOGV("receiver %p ~ Returned from hotplug handler.", this);
205e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
206e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
207e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown}
208e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
2090a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
21027285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhatstatic jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
2110a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        jobject messageQueueObj) {
212603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
213603b44589682db3ff33ade172facb0c5e309f1beJeff Brown    if (messageQueue == NULL) {
2140a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
2150a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        return 0;
2160a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
2170a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2180a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
219603b44589682db3ff33ade172facb0c5e309f1beJeff Brown            receiverObj, messageQueue);
2200a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    status_t status = receiver->initialize();
2210a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    if (status) {
2220a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        String8 message;
2230a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
2240a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        jniThrowRuntimeException(env, message.string());
2250a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        return 0;
2260a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
2270a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2280a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
22927285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhat    return reinterpret_cast<jlong>(receiver.get());
2300a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
2310a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
23227285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhatstatic void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) {
2330a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    sp<NativeDisplayEventReceiver> receiver =
2340a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
23580a1de1007ddc62e1af2a4746008f499145aeaabJeff Brown    receiver->dispose();
2360a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
2370a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
2380a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
23927285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhatstatic void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
2400a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    sp<NativeDisplayEventReceiver> receiver =
2410a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
2420a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    status_t status = receiver->scheduleVsync();
2430a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    if (status) {
2440a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        String8 message;
2450a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
2460a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        jniThrowRuntimeException(env, message.string());
2470a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    }
2480a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
2490a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2500a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2510a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownstatic JNINativeMethod gMethods[] = {
2520a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    /* name, signature, funcPtr */
2530a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    { "nativeInit",
25427285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhat            "(Landroid/view/DisplayEventReceiver;Landroid/os/MessageQueue;)J",
2550a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            (void*)nativeInit },
2560a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    { "nativeDispose",
25727285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhat            "(J)V",
2580a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            (void*)nativeDispose },
25927285821b74ca9bc381d33f40028f06ff0f85e0cAshok Bhat    { "nativeScheduleVsync", "(J)V",
2600a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            (void*)nativeScheduleVsync }
2610a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown};
2620a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2630a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#define FIND_CLASS(var, className) \
2640a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        var = env->FindClass(className); \
2650a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        LOG_FATAL_IF(! var, "Unable to find class " className); \
2660a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        var = jclass(env->NewGlobalRef(var));
2670a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2680a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
2690a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
2700a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown        LOG_FATAL_IF(! var, "Unable to find method " methodName);
2710a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2720a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brownint register_android_view_DisplayEventReceiver(JNIEnv* env) {
2730a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    int res = jniRegisterNativeMethods(env, "android/view/DisplayEventReceiver",
2740a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            gMethods, NELEM(gMethods));
2750a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
2760a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2770a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, "android/view/DisplayEventReceiver");
2780a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2790a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
2800a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown            gDisplayEventReceiverClassInfo.clazz,
281e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            "dispatchVsync", "(JII)V");
282e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
283e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            gDisplayEventReceiverClassInfo.clazz,
284e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            "dispatchHotplug", "(JIZ)V");
2850a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown    return 0;
2860a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown}
2870a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown
2880a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown} // namespace android
289