blob: c43e7e776fdf5d7f224c73b2ec82f8db32380549 [file] [log] [blame]
Dianne Hackborn69969e42010-05-04 11:40:40 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "NativeActivity"
18#include <utils/Log.h>
19
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070020#include <poll.h>
21#include <dlfcn.h>
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070022#include <fcntl.h>
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070023
Dianne Hackborn69969e42010-05-04 11:40:40 -070024#include <android_runtime/AndroidRuntime.h>
Dianne Hackborn289b9b62010-07-09 11:44:11 -070025#include <android_runtime/android_view_Surface.h>
26#include <android_runtime/android_app_NativeActivity.h>
Christopher Tate6cce32b2010-07-12 18:21:36 -070027#include <android_runtime/android_util_AssetManager.h>
Dianne Hackborn54a181b2010-06-30 18:35:14 -070028#include <surfaceflinger/Surface.h>
29#include <ui/egl/android_natives.h>
Dianne Hackborna95e4cb2010-06-18 18:09:33 -070030#include <ui/InputTransport.h>
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070031#include <utils/Looper.h>
Dianne Hackborn69969e42010-05-04 11:40:40 -070032
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070033#include "JNIHelp.h"
34#include "android_os_MessageQueue.h"
35#include "android_view_InputChannel.h"
36#include "android_view_KeyEvent.h"
Dianne Hackborn69969e42010-05-04 11:40:40 -070037
Dianne Hackborndb28a942010-10-21 17:22:30 -070038#define LOG_TRACE(...)
Steve Block28d9f022011-10-12 17:27:03 +010039//#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070040
Dianne Hackborn69969e42010-05-04 11:40:40 -070041namespace android
42{
43
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070044static struct {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070045 jmethodID dispatchUnhandledKeyEvent;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -070046 jmethodID preDispatchKeyEvent;
Dianne Hackborndb28a942010-10-21 17:22:30 -070047 jmethodID finish;
Dianne Hackborn54a181b2010-06-30 18:35:14 -070048 jmethodID setWindowFlags;
49 jmethodID setWindowFormat;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070050 jmethodID showIme;
51 jmethodID hideIme;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070052} gNativeActivityClassInfo;
53
Dianne Hackborn54a181b2010-06-30 18:35:14 -070054// ------------------------------------------------------------------------
55
Dianne Hackborn289b9b62010-07-09 11:44:11 -070056struct ActivityWork {
57 int32_t cmd;
58 int32_t arg1;
59 int32_t arg2;
60};
61
62enum {
63 CMD_DEF_KEY = 1,
Dianne Hackborndb28a942010-10-21 17:22:30 -070064 CMD_FINISH,
Dianne Hackborn289b9b62010-07-09 11:44:11 -070065 CMD_SET_WINDOW_FORMAT,
66 CMD_SET_WINDOW_FLAGS,
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070067 CMD_SHOW_SOFT_INPUT,
68 CMD_HIDE_SOFT_INPUT,
Dianne Hackborn289b9b62010-07-09 11:44:11 -070069};
70
71static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
72 ActivityWork work;
73 work.cmd = cmd;
74 work.arg1 = arg1;
75 work.arg2 = arg2;
76
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070077 LOG_TRACE("write_work: cmd=%d", cmd);
78
Dianne Hackborn289b9b62010-07-09 11:44:11 -070079restart:
80 int res = write(fd, &work, sizeof(work));
81 if (res < 0 && errno == EINTR) {
82 goto restart;
83 }
84
85 if (res == sizeof(work)) return;
86
87 if (res < 0) LOGW("Failed writing to work fd: %s", strerror(errno));
88 else LOGW("Truncated writing to work fd: %d", res);
89}
90
91static bool read_work(int fd, ActivityWork* outWork) {
92 int res = read(fd, outWork, sizeof(ActivityWork));
93 // no need to worry about EINTR, poll loop will just come back again.
94 if (res == sizeof(ActivityWork)) return true;
95
96 if (res < 0) LOGW("Failed reading work fd: %s", strerror(errno));
97 else LOGW("Truncated reading work fd: %d", res);
98 return false;
99}
100
101// ------------------------------------------------------------------------
102
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700103} // namespace android
104
105using namespace android;
106
107AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) :
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700108 mWorkWrite(workWrite), mConsumer(channel), mSeq(0) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700109 int msgpipe[2];
110 if (pipe(msgpipe)) {
111 LOGW("could not create pipe: %s", strerror(errno));
112 mDispatchKeyRead = mDispatchKeyWrite = -1;
113 } else {
114 mDispatchKeyRead = msgpipe[0];
115 mDispatchKeyWrite = msgpipe[1];
116 int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK);
117 SLOGW_IF(result != 0, "Could not make AInputQueue read pipe "
118 "non-blocking: %s", strerror(errno));
119 result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK);
120 SLOGW_IF(result != 0, "Could not make AInputQueue write pipe "
121 "non-blocking: %s", strerror(errno));
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700122 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700123}
124
125AInputQueue::~AInputQueue() {
126 close(mDispatchKeyRead);
127 close(mDispatchKeyWrite);
128}
129
Dianne Hackborn42c03e52010-09-07 15:28:30 -0700130void AInputQueue::attachLooper(ALooper* looper, int ident,
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700131 ALooper_callbackFunc callback, void* data) {
132 mLooper = static_cast<android::Looper*>(looper);
133 mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
134 ident, ALOOPER_EVENT_INPUT, callback, data);
135 mLooper->addFd(mDispatchKeyRead,
136 ident, ALOOPER_EVENT_INPUT, callback, data);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700137}
138
139void AInputQueue::detachLooper() {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700140 mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
141 mLooper->removeFd(mDispatchKeyRead);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700142}
143
144int32_t AInputQueue::hasEvents() {
145 struct pollfd pfd[2];
146
147 pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
148 pfd[0].events = POLLIN;
149 pfd[0].revents = 0;
150 pfd[1].fd = mDispatchKeyRead;
Kenny Root2bb10f42011-02-22 15:00:35 -0800151 pfd[1].events = POLLIN;
152 pfd[1].revents = 0;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700153
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700154 int nfd = poll(pfd, 2, 0);
155 if (nfd <= 0) return 0;
Kenny Root2bb10f42011-02-22 15:00:35 -0800156 return ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN)) ? 1 : -1;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700157}
158
159int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
160 *outEvent = NULL;
161
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700162 bool finishNow = false;
163
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700164 char byteread;
165 ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);
166 if (nRead == 1) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700167 mLock.lock();
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700168 if (mDispatchingKeys.size() > 0) {
169 KeyEvent* kevent = mDispatchingKeys[0];
170 *outEvent = kevent;
171 mDispatchingKeys.removeAt(0);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700172 in_flight_event inflight;
173 inflight.event = kevent;
174 inflight.seq = -1;
175 inflight.doFinish = false;
176 mInFlightEvents.push(inflight);
177 }
178 if (mFinishPreDispatches.size() > 0) {
179 finish_pre_dispatch finish(mFinishPreDispatches[0]);
180 mFinishPreDispatches.removeAt(0);
181 const size_t N = mInFlightEvents.size();
182 for (size_t i=0; i<N; i++) {
183 const in_flight_event& inflight(mInFlightEvents[i]);
184 if (inflight.seq == finish.seq) {
185 *outEvent = inflight.event;
186 finishNow = finish.handled;
187 }
188 }
189 if (*outEvent == NULL) {
190 LOGW("getEvent couldn't find inflight for seq %d", finish.seq);
191 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700192 }
193 mLock.unlock();
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700194
195 if (finishNow) {
Jeff Brown3915bb82010-11-05 15:02:16 -0700196 finishEvent(*outEvent, true, false);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700197 *outEvent = NULL;
198 return -1;
199 } else if (*outEvent != NULL) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700200 return 0;
201 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700202 }
203
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700204 int32_t res = mConsumer.receiveDispatchSignal();
205 if (res != android::OK) {
206 LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
207 mConsumer.getChannel()->getName().string(), res);
208 return -1;
209 }
210
211 InputEvent* myEvent = NULL;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700212 res = mConsumer.consume(this, &myEvent);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700213 if (res != android::OK) {
214 LOGW("channel '%s' ~ Failed to consume input event. status=%d",
215 mConsumer.getChannel()->getName().string(), res);
Jeff Brown3915bb82010-11-05 15:02:16 -0700216 mConsumer.sendFinishedSignal(false);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700217 return -1;
218 }
219
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700220 in_flight_event inflight;
221 inflight.event = myEvent;
222 inflight.seq = -1;
223 inflight.doFinish = true;
224 mInFlightEvents.push(inflight);
225
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700226 *outEvent = myEvent;
227 return 0;
228}
229
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700230bool AInputQueue::preDispatchEvent(AInputEvent* event) {
231 if (((InputEvent*)event)->getType() != AINPUT_EVENT_TYPE_KEY) {
232 // The IME only cares about key events.
233 return false;
234 }
235
236 // For now we only send system keys to the IME... this avoids having
237 // critical keys like DPAD go through this path. We really need to have
238 // the IME report which keys it wants.
239 if (!((KeyEvent*)event)->isSystemKey()) {
240 return false;
241 }
242
243 return preDispatchKey((KeyEvent*)event);
244}
245
Jeff Brown3915bb82010-11-05 15:02:16 -0700246void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultHandling) {
247 LOG_TRACE("finishEvent: %p handled=%d, didDefaultHandling=%d", event,
248 handled ? 1 : 0, didDefaultHandling ? 1 : 0);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700249
Jeff Brown3915bb82010-11-05 15:02:16 -0700250 if (!handled && !didDefaultHandling
251 && ((InputEvent*)event)->getType() == AINPUT_EVENT_TYPE_KEY
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700252 && ((KeyEvent*)event)->hasDefaultAction()) {
253 // The app didn't handle this, but it may have a default action
254 // associated with it. We need to hand this back to Java to be
255 // executed.
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700256 doUnhandledKey((KeyEvent*)event);
257 return;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700258 }
259
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700260 mLock.lock();
261 const size_t N = mInFlightEvents.size();
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700262 for (size_t i=0; i<N; i++) {
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700263 const in_flight_event& inflight(mInFlightEvents[i]);
264 if (inflight.event == event) {
265 if (inflight.doFinish) {
Jeff Brown3915bb82010-11-05 15:02:16 -0700266 int32_t res = mConsumer.sendFinishedSignal(handled);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700267 if (res != android::OK) {
268 LOGW("Failed to send finished signal on channel '%s'. status=%d",
269 mConsumer.getChannel()->getName().string(), res);
270 }
271 }
272 if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) {
273 mAvailKeyEvents.push(static_cast<KeyEvent*>(event));
274 } else {
275 mAvailMotionEvents.push(static_cast<MotionEvent*>(event));
276 }
277 mInFlightEvents.removeAt(i);
278 mLock.unlock();
279 return;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700280 }
281 }
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700282 mLock.unlock();
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700283
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700284 LOGW("finishEvent called for unknown event: %p", event);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700285}
286
287void AInputQueue::dispatchEvent(android::KeyEvent* event) {
288 mLock.lock();
289 LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
290 mDispatchKeyWrite);
291 mDispatchingKeys.add(event);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700292 wakeupDispatch();
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700293 mLock.unlock();
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700294}
295
296void AInputQueue::finishPreDispatch(int seq, bool handled) {
297 mLock.lock();
298 LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0);
299 finish_pre_dispatch finish;
300 finish.seq = seq;
301 finish.handled = handled;
302 mFinishPreDispatches.add(finish);
303 wakeupDispatch();
304 mLock.unlock();
305}
306
307KeyEvent* AInputQueue::consumeUnhandledEvent() {
308 KeyEvent* event = NULL;
309
310 mLock.lock();
311 if (mUnhandledKeys.size() > 0) {
312 event = mUnhandledKeys[0];
313 mUnhandledKeys.removeAt(0);
314 }
315 mLock.unlock();
316
317 LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
318
319 return event;
320}
321
322KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) {
323 KeyEvent* event = NULL;
324
325 mLock.lock();
326 if (mPreDispatchingKeys.size() > 0) {
327 const in_flight_event& inflight(mPreDispatchingKeys[0]);
328 event = static_cast<KeyEvent*>(inflight.event);
329 *outSeq = inflight.seq;
330 mPreDispatchingKeys.removeAt(0);
331 }
332 mLock.unlock();
333
334 LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event);
335
336 return event;
337}
338
339KeyEvent* AInputQueue::createKeyEvent() {
340 mLock.lock();
341 KeyEvent* event;
342 if (mAvailKeyEvents.size() <= 0) {
343 event = new KeyEvent();
344 } else {
345 event = mAvailKeyEvents.top();
346 mAvailKeyEvents.pop();
347 }
348 mLock.unlock();
349 return event;
350}
351
352MotionEvent* AInputQueue::createMotionEvent() {
353 mLock.lock();
354 MotionEvent* event;
355 if (mAvailMotionEvents.size() <= 0) {
356 event = new MotionEvent();
357 } else {
358 event = mAvailMotionEvents.top();
359 mAvailMotionEvents.pop();
360 }
361 mLock.unlock();
362 return event;
363}
364
365void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) {
366 mLock.lock();
367 LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite);
368 if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) {
369 write_work(mWorkWrite, CMD_DEF_KEY);
370 }
371 mUnhandledKeys.add(keyEvent);
372 mLock.unlock();
373}
374
375bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
376 mLock.lock();
377 LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite);
378 const size_t N = mInFlightEvents.size();
379 for (size_t i=0; i<N; i++) {
380 in_flight_event& inflight(mInFlightEvents.editItemAt(i));
381 if (inflight.event == keyEvent) {
382 if (inflight.seq >= 0) {
383 // This event has already been pre-dispatched!
384 LOG_TRACE("Event already pre-dispatched!");
385 mLock.unlock();
386 return false;
387 }
388 mSeq++;
389 if (mSeq < 0) mSeq = 1;
390 inflight.seq = mSeq;
391
392 if (mPreDispatchingKeys.size() <= 0 && mWorkWrite >= 0) {
393 write_work(mWorkWrite, CMD_DEF_KEY);
394 }
395 mPreDispatchingKeys.add(inflight);
396 mLock.unlock();
397 return true;
398 }
399 }
400
401 LOGW("preDispatchKey called for unknown event: %p", keyEvent);
402 return false;
403}
404
405void AInputQueue::wakeupDispatch() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700406restart:
407 char dummy = 0;
408 int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
409 if (res < 0 && errno == EINTR) {
410 goto restart;
411 }
412
413 if (res == sizeof(dummy)) return;
414
415 if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno));
416 else LOGW("Truncated writing to dispatch fd: %d", res);
417}
418
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700419namespace android {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700420
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700421// ------------------------------------------------------------------------
422
423/*
424 * Native state for interacting with the NativeActivity class.
425 */
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700426struct NativeCode : public ANativeActivity {
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700427 NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700428 memset((ANativeActivity*)this, 0, sizeof(ANativeActivity));
429 memset(&callbacks, 0, sizeof(callbacks));
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700430 dlhandle = _dlhandle;
431 createActivityFunc = _createFunc;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700432 nativeWindow = NULL;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700433 inputChannel = NULL;
434 nativeInputQueue = NULL;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700435 mainWorkRead = mainWorkWrite = -1;
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700436 }
437
438 ~NativeCode() {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700439 if (callbacks.onDestroy != NULL) {
440 callbacks.onDestroy(this);
441 }
442 if (env != NULL && clazz != NULL) {
443 env->DeleteGlobalRef(clazz);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700444 }
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700445 if (looper != NULL && mainWorkRead >= 0) {
446 looper->removeFd(mainWorkRead);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700447 }
448 if (nativeInputQueue != NULL) {
449 nativeInputQueue->mWorkWrite = -1;
450 }
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700451 setSurface(NULL);
452 setInputChannel(NULL);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700453 if (mainWorkRead >= 0) close(mainWorkRead);
454 if (mainWorkWrite >= 0) close(mainWorkWrite);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700455 if (dlhandle != NULL) {
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700456 // for now don't unload... we probably should clean this
457 // up and only keep one open dlhandle per proc, since there
458 // is really no benefit to unloading the code.
459 //dlclose(dlhandle);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700460 }
461 }
462
463 void setSurface(jobject _surface) {
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700464 if (_surface != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700465 nativeWindow = android_Surface_getNativeWindow(env, _surface);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700466 } else {
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700467 nativeWindow = NULL;
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700468 }
469 }
470
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700471 status_t setInputChannel(jobject _channel) {
472 if (inputChannel != NULL) {
473 delete nativeInputQueue;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700474 env->DeleteGlobalRef(inputChannel);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700475 }
476 inputChannel = NULL;
477 nativeInputQueue = NULL;
478 if (_channel != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700479 inputChannel = env->NewGlobalRef(_channel);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700480 sp<InputChannel> ic =
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700481 android_view_InputChannel_getInputChannel(env, _channel);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700482 if (ic != NULL) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700483 nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700484 if (nativeInputQueue->getConsumer().initialize() != android::OK) {
485 delete nativeInputQueue;
486 nativeInputQueue = NULL;
487 return UNKNOWN_ERROR;
488 }
489 } else {
490 return UNKNOWN_ERROR;
491 }
492 }
493 return OK;
494 }
495
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700496 ANativeActivityCallbacks callbacks;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700497
498 void* dlhandle;
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700499 ANativeActivity_createFunc* createActivityFunc;
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700500
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800501 String8 internalDataPathObj;
502 String8 externalDataPathObj;
503 String8 obbPathObj;
Dianne Hackborn68267412010-07-02 18:52:01 -0700504
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700505 sp<ANativeWindow> nativeWindow;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700506 int32_t lastWindowWidth;
507 int32_t lastWindowHeight;
508
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700509 jobject inputChannel;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700510 struct AInputQueue* nativeInputQueue;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700511
512 // These are used to wake up the main thread to process work.
513 int mainWorkRead;
514 int mainWorkWrite;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700515 sp<Looper> looper;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700516};
517
Dianne Hackborndb28a942010-10-21 17:22:30 -0700518void android_NativeActivity_finish(ANativeActivity* activity) {
519 NativeCode* code = static_cast<NativeCode*>(activity);
520 write_work(code->mainWorkWrite, CMD_FINISH, 0);
521}
522
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700523void android_NativeActivity_setWindowFormat(
524 ANativeActivity* activity, int32_t format) {
525 NativeCode* code = static_cast<NativeCode*>(activity);
526 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format);
527}
528
529void android_NativeActivity_setWindowFlags(
530 ANativeActivity* activity, int32_t values, int32_t mask) {
531 NativeCode* code = static_cast<NativeCode*>(activity);
532 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
533}
534
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700535void android_NativeActivity_showSoftInput(
536 ANativeActivity* activity, int32_t flags) {
537 NativeCode* code = static_cast<NativeCode*>(activity);
538 write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags);
539}
540
541void android_NativeActivity_hideSoftInput(
542 ANativeActivity* activity, int32_t flags) {
543 NativeCode* code = static_cast<NativeCode*>(activity);
544 write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags);
545}
546
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700547// ------------------------------------------------------------------------
548
Dianne Hackborndb28a942010-10-21 17:22:30 -0700549static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
550 if (env->ExceptionCheck()) {
551 LOGE("An exception was thrown by callback '%s'.", methodName);
552 LOGE_EX(env);
553 env->ExceptionClear();
554 return true;
555 }
556 return false;
557}
558
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700559/*
560 * Callback for handling native events on the application's main thread.
561 */
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700562static int mainWorkCallback(int fd, int events, void* data) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700563 NativeCode* code = (NativeCode*)data;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700564 if ((events & POLLIN) == 0) {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700565 return 1;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700566 }
567
568 ActivityWork work;
569 if (!read_work(code->mainWorkRead, &work)) {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700570 return 1;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700571 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700572
573 LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
574
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700575 switch (work.cmd) {
576 case CMD_DEF_KEY: {
577 KeyEvent* keyEvent;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700578 while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700579 jobject inputEventObj = android_view_KeyEvent_fromNative(
580 code->env, keyEvent);
Jeff Brown1f245102010-11-18 20:53:46 -0800581 jboolean handled;
582 if (inputEventObj) {
583 handled = code->env->CallBooleanMethod(code->clazz,
584 gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
585 checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
586 code->env->DeleteLocalRef(inputEventObj);
587 } else {
588 LOGE("Failed to obtain key event for dispatchUnhandledKeyEvent.");
589 handled = false;
590 }
Jeff Brown3915bb82010-11-05 15:02:16 -0700591 code->nativeInputQueue->finishEvent(keyEvent, handled, true);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700592 }
593 int seq;
594 while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) {
595 jobject inputEventObj = android_view_KeyEvent_fromNative(
596 code->env, keyEvent);
Jeff Brown1f245102010-11-18 20:53:46 -0800597 if (inputEventObj) {
598 code->env->CallVoidMethod(code->clazz,
599 gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
600 checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
601 code->env->DeleteLocalRef(inputEventObj);
602 } else {
603 LOGE("Failed to obtain key event for preDispatchKeyEvent.");
604 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700605 }
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700606 } break;
Dianne Hackborndb28a942010-10-21 17:22:30 -0700607 case CMD_FINISH: {
608 code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish);
609 checkAndClearExceptionFromCallback(code->env, "finish");
610 } break;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700611 case CMD_SET_WINDOW_FORMAT: {
612 code->env->CallVoidMethod(code->clazz,
613 gNativeActivityClassInfo.setWindowFormat, work.arg1);
Dianne Hackborndb28a942010-10-21 17:22:30 -0700614 checkAndClearExceptionFromCallback(code->env, "setWindowFormat");
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700615 } break;
616 case CMD_SET_WINDOW_FLAGS: {
617 code->env->CallVoidMethod(code->clazz,
618 gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
Dianne Hackborndb28a942010-10-21 17:22:30 -0700619 checkAndClearExceptionFromCallback(code->env, "setWindowFlags");
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700620 } break;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700621 case CMD_SHOW_SOFT_INPUT: {
622 code->env->CallVoidMethod(code->clazz,
623 gNativeActivityClassInfo.showIme, work.arg1);
Dianne Hackborndb28a942010-10-21 17:22:30 -0700624 checkAndClearExceptionFromCallback(code->env, "showIme");
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700625 } break;
626 case CMD_HIDE_SOFT_INPUT: {
627 code->env->CallVoidMethod(code->clazz,
628 gNativeActivityClassInfo.hideIme, work.arg1);
Dianne Hackborndb28a942010-10-21 17:22:30 -0700629 checkAndClearExceptionFromCallback(code->env, "hideIme");
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700630 } break;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700631 default:
632 LOGW("Unknown work command: %d", work.cmd);
633 break;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700634 }
635
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700636 return 1;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700637}
638
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700639// ------------------------------------------------------------------------
640
Dianne Hackborn69969e42010-05-04 11:40:40 -0700641static jint
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700642loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800643 jobject messageQueue, jstring internalDataDir, jstring obbDir,
644 jstring externalDataDir, int sdkVersion,
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700645 jobject jAssetMgr, jbyteArray savedState)
Dianne Hackborn69969e42010-05-04 11:40:40 -0700646{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700647 LOG_TRACE("loadNativeCode_native");
648
Dianne Hackborn69969e42010-05-04 11:40:40 -0700649 const char* pathStr = env->GetStringUTFChars(path, NULL);
650 NativeCode* code = NULL;
651
652 void* handle = dlopen(pathStr, RTLD_LAZY);
653
654 env->ReleaseStringUTFChars(path, pathStr);
655
656 if (handle != NULL) {
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700657 const char* funcStr = env->GetStringUTFChars(funcName, NULL);
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700658 code = new NativeCode(handle, (ANativeActivity_createFunc*)
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700659 dlsym(handle, funcStr));
660 env->ReleaseStringUTFChars(funcName, funcStr);
661
Dianne Hackborn69969e42010-05-04 11:40:40 -0700662 if (code->createActivityFunc == NULL) {
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700663 LOGW("ANativeActivity_onCreate not found");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700664 delete code;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700665 return 0;
666 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700667
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700668 code->looper = android_os_MessageQueue_getLooper(env, messageQueue);
669 if (code->looper == NULL) {
670 LOGW("Unable to retrieve MessageQueue's Looper");
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700671 delete code;
672 return 0;
673 }
674
675 int msgpipe[2];
676 if (pipe(msgpipe)) {
677 LOGW("could not create pipe: %s", strerror(errno));
678 delete code;
679 return 0;
680 }
681 code->mainWorkRead = msgpipe[0];
682 code->mainWorkWrite = msgpipe[1];
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700683 int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
684 SLOGW_IF(result != 0, "Could not make main work read pipe "
685 "non-blocking: %s", strerror(errno));
686 result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
687 SLOGW_IF(result != 0, "Could not make main work write pipe "
688 "non-blocking: %s", strerror(errno));
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700689 code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700690
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700691 code->ANativeActivity::callbacks = &code->callbacks;
692 if (env->GetJavaVM(&code->vm) < 0) {
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700693 LOGW("NativeActivity GetJavaVM failed");
694 delete code;
695 return 0;
696 }
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700697 code->env = env;
698 code->clazz = env->NewGlobalRef(clazz);
Christopher Tate6cce32b2010-07-12 18:21:36 -0700699
Dianne Hackborn68267412010-07-02 18:52:01 -0700700 const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800701 code->internalDataPathObj = dirStr;
702 code->internalDataPath = code->internalDataPathObj.string();
703 env->ReleaseStringUTFChars(internalDataDir, dirStr);
Dianne Hackborn68267412010-07-02 18:52:01 -0700704
705 dirStr = env->GetStringUTFChars(externalDataDir, NULL);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800706 code->externalDataPathObj = dirStr;
707 code->externalDataPath = code->externalDataPathObj.string();
708 env->ReleaseStringUTFChars(externalDataDir, dirStr);
Christopher Tate6cce32b2010-07-12 18:21:36 -0700709
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700710 code->sdkVersion = sdkVersion;
Dianne Hackborn68267412010-07-02 18:52:01 -0700711
Christopher Tate6cce32b2010-07-12 18:21:36 -0700712 code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
713
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800714 dirStr = env->GetStringUTFChars(obbDir, NULL);
715 code->obbPathObj = dirStr;
716 code->obbPath = code->obbPathObj.string();
717 env->ReleaseStringUTFChars(obbDir, dirStr);
718
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700719 jbyte* rawSavedState = NULL;
720 jsize rawSavedSize = 0;
721 if (savedState != NULL) {
722 rawSavedState = env->GetByteArrayElements(savedState, NULL);
723 rawSavedSize = env->GetArrayLength(savedState);
724 }
725
726 code->createActivityFunc(code, rawSavedState, rawSavedSize);
727
728 if (rawSavedState != NULL) {
729 env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
730 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700731 }
732
733 return (jint)code;
734}
735
736static void
737unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
738{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700739 LOG_TRACE("unloadNativeCode_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700740 if (handle != 0) {
741 NativeCode* code = (NativeCode*)handle;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700742 delete code;
743 }
744}
745
746static void
747onStart_native(JNIEnv* env, jobject clazz, jint handle)
748{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700749 LOG_TRACE("onStart_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700750 if (handle != 0) {
751 NativeCode* code = (NativeCode*)handle;
752 if (code->callbacks.onStart != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700753 code->callbacks.onStart(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700754 }
755 }
756}
757
758static void
759onResume_native(JNIEnv* env, jobject clazz, jint handle)
760{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700761 LOG_TRACE("onResume_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700762 if (handle != 0) {
763 NativeCode* code = (NativeCode*)handle;
764 if (code->callbacks.onResume != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700765 code->callbacks.onResume(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700766 }
767 }
768}
769
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700770static jbyteArray
Dianne Hackborn69969e42010-05-04 11:40:40 -0700771onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
772{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700773 LOG_TRACE("onSaveInstanceState_native");
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700774
775 jbyteArray array = NULL;
776
Dianne Hackborn69969e42010-05-04 11:40:40 -0700777 if (handle != 0) {
778 NativeCode* code = (NativeCode*)handle;
779 if (code->callbacks.onSaveInstanceState != NULL) {
780 size_t len = 0;
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700781 jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len);
782 if (len > 0) {
783 array = env->NewByteArray(len);
784 if (array != NULL) {
785 env->SetByteArrayRegion(array, 0, len, state);
786 }
787 }
788 if (state != NULL) {
789 free(state);
790 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700791 }
792 }
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700793
794 return array;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700795}
796
797static void
798onPause_native(JNIEnv* env, jobject clazz, jint handle)
799{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700800 LOG_TRACE("onPause_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700801 if (handle != 0) {
802 NativeCode* code = (NativeCode*)handle;
803 if (code->callbacks.onPause != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700804 code->callbacks.onPause(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700805 }
806 }
807}
808
809static void
810onStop_native(JNIEnv* env, jobject clazz, jint handle)
811{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700812 LOG_TRACE("onStop_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700813 if (handle != 0) {
814 NativeCode* code = (NativeCode*)handle;
815 if (code->callbacks.onStop != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700816 code->callbacks.onStop(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700817 }
818 }
819}
820
821static void
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700822onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle)
823{
824 LOG_TRACE("onConfigurationChanged_native");
825 if (handle != 0) {
826 NativeCode* code = (NativeCode*)handle;
827 if (code->callbacks.onConfigurationChanged != NULL) {
828 code->callbacks.onConfigurationChanged(code);
829 }
830 }
831}
832
833static void
Dianne Hackborn69969e42010-05-04 11:40:40 -0700834onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
835{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700836 LOG_TRACE("onLowMemory_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700837 if (handle != 0) {
838 NativeCode* code = (NativeCode*)handle;
839 if (code->callbacks.onLowMemory != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700840 code->callbacks.onLowMemory(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700841 }
842 }
843}
844
845static void
846onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
847{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700848 LOG_TRACE("onWindowFocusChanged_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700849 if (handle != 0) {
850 NativeCode* code = (NativeCode*)handle;
851 if (code->callbacks.onWindowFocusChanged != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700852 code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700853 }
854 }
855}
856
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700857static void
858onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
859{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700860 LOG_TRACE("onSurfaceCreated_native");
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700861 if (handle != 0) {
862 NativeCode* code = (NativeCode*)handle;
863 code->setSurface(surface);
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700864 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700865 code->callbacks.onNativeWindowCreated(code,
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700866 code->nativeWindow.get());
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700867 }
868 }
869}
870
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700871static int32_t getWindowProp(ANativeWindow* window, int what) {
872 int value;
873 int res = window->query(window, what, &value);
874 return res < 0 ? res : value;
875}
876
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700877static void
878onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
879 jint format, jint width, jint height)
880{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700881 LOG_TRACE("onSurfaceChanged_native");
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700882 if (handle != 0) {
883 NativeCode* code = (NativeCode*)handle;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700884 sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
885 code->setSurface(surface);
886 if (oldNativeWindow != code->nativeWindow) {
Dianne Hackborn8ae5a8e2010-07-01 18:44:46 -0700887 if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700888 code->callbacks.onNativeWindowDestroyed(code,
Dianne Hackborn8ae5a8e2010-07-01 18:44:46 -0700889 oldNativeWindow.get());
890 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700891 if (code->nativeWindow != NULL) {
892 if (code->callbacks.onNativeWindowCreated != NULL) {
893 code->callbacks.onNativeWindowCreated(code,
894 code->nativeWindow.get());
895 }
896 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
897 NATIVE_WINDOW_WIDTH);
898 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
899 NATIVE_WINDOW_HEIGHT);
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700900 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700901 } else {
902 // Maybe it resized?
903 int32_t newWidth = getWindowProp(code->nativeWindow.get(),
904 NATIVE_WINDOW_WIDTH);
905 int32_t newHeight = getWindowProp(code->nativeWindow.get(),
906 NATIVE_WINDOW_HEIGHT);
907 if (newWidth != code->lastWindowWidth
908 || newHeight != code->lastWindowHeight) {
909 if (code->callbacks.onNativeWindowResized != NULL) {
910 code->callbacks.onNativeWindowResized(code,
911 code->nativeWindow.get());
912 }
913 }
914 }
915 }
916}
917
918static void
919onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle)
920{
921 LOG_TRACE("onSurfaceRedrawNeeded_native");
922 if (handle != 0) {
923 NativeCode* code = (NativeCode*)handle;
924 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
925 code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700926 }
927 }
928}
929
930static void
931onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
932{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700933 LOG_TRACE("onSurfaceDestroyed_native");
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700934 if (handle != 0) {
935 NativeCode* code = (NativeCode*)handle;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700936 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700937 code->callbacks.onNativeWindowDestroyed(code,
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700938 code->nativeWindow.get());
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700939 }
940 code->setSurface(NULL);
941 }
942}
943
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700944static void
945onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
946{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700947 LOG_TRACE("onInputChannelCreated_native");
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700948 if (handle != 0) {
949 NativeCode* code = (NativeCode*)handle;
950 status_t err = code->setInputChannel(channel);
951 if (err != OK) {
952 jniThrowException(env, "java/lang/IllegalStateException",
953 "Error setting input channel");
954 return;
955 }
956 if (code->callbacks.onInputQueueCreated != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700957 code->callbacks.onInputQueueCreated(code,
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700958 code->nativeInputQueue);
959 }
960 }
961}
962
963static void
964onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
965{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700966 LOG_TRACE("onInputChannelDestroyed_native");
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700967 if (handle != 0) {
968 NativeCode* code = (NativeCode*)handle;
969 if (code->nativeInputQueue != NULL
970 && code->callbacks.onInputQueueDestroyed != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700971 code->callbacks.onInputQueueDestroyed(code,
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700972 code->nativeInputQueue);
973 }
974 code->setInputChannel(NULL);
975 }
976}
977
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700978static void
979onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle,
980 jint x, jint y, jint w, jint h)
981{
982 LOG_TRACE("onContentRectChanged_native");
983 if (handle != 0) {
984 NativeCode* code = (NativeCode*)handle;
985 if (code->callbacks.onContentRectChanged != NULL) {
986 ARect rect;
987 rect.left = x;
988 rect.top = y;
989 rect.right = x+w;
990 rect.bottom = y+h;
991 code->callbacks.onContentRectChanged(code, &rect);
992 }
993 }
994}
995
996static void
997dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj)
998{
999 LOG_TRACE("dispatchKeyEvent_native");
1000 if (handle != 0) {
1001 NativeCode* code = (NativeCode*)handle;
1002 if (code->nativeInputQueue != NULL) {
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001003 KeyEvent* event = code->nativeInputQueue->createKeyEvent();
Jeff Brown1f245102010-11-18 20:53:46 -08001004 status_t status = android_view_KeyEvent_toNative(env, eventObj, event);
1005 if (status) {
1006 delete event;
1007 jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
1008 return;
1009 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001010 code->nativeInputQueue->dispatchEvent(event);
1011 }
1012 }
1013}
1014
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001015static void
1016finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle,
1017 jint seq, jboolean handled)
1018{
1019 LOG_TRACE("finishPreDispatchKeyEvent_native");
1020 if (handle != 0) {
1021 NativeCode* code = (NativeCode*)handle;
1022 if (code->nativeInputQueue != NULL) {
1023 code->nativeInputQueue->finishPreDispatch(seq, handled ? true : false);
1024 }
1025 }
1026}
1027
Dianne Hackborn69969e42010-05-04 11:40:40 -07001028static const JNINativeMethod g_methods[] = {
Dianne Hackborn805fd7e2011-01-16 18:30:29 -08001029 { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I",
Dianne Hackborn68267412010-07-02 18:52:01 -07001030 (void*)loadNativeCode_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -07001031 { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
1032 { "onStartNative", "(I)V", (void*)onStart_native },
1033 { "onResumeNative", "(I)V", (void*)onResume_native },
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -07001034 { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -07001035 { "onPauseNative", "(I)V", (void*)onPause_native },
1036 { "onStopNative", "(I)V", (void*)onStop_native },
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -07001037 { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -07001038 { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
1039 { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001040 { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
1041 { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001042 { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001043 { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
Dianne Hackborna95e4cb2010-06-18 18:09:33 -07001044 { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
1045 { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001046 { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native },
1047 { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native },
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001048 { "finishPreDispatchKeyEventNative", "(IIZ)V", (void*)finishPreDispatchKeyEvent_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -07001049};
1050
1051static const char* const kNativeActivityPathName = "android/app/NativeActivity";
1052
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -07001053#define FIND_CLASS(var, className) \
1054 var = env->FindClass(className); \
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001055 LOG_FATAL_IF(! var, "Unable to find class %s", className);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -07001056
1057#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
1058 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
1059 LOG_FATAL_IF(! var, "Unable to find method" methodName);
1060
Dianne Hackborn69969e42010-05-04 11:40:40 -07001061int register_android_app_NativeActivity(JNIEnv* env)
1062{
1063 //LOGD("register_android_app_NativeActivity");
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001064 jclass clazz;
1065 FIND_CLASS(clazz, kNativeActivityPathName);
Dianne Hackborn69969e42010-05-04 11:40:40 -07001066
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -07001067 GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001068 clazz,
Jeff Brown3915bb82010-11-05 15:02:16 -07001069 "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)Z");
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001070 GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001071 clazz,
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001072 "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V");
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001073
Dianne Hackborndb28a942010-10-21 17:22:30 -07001074 GET_METHOD_ID(gNativeActivityClassInfo.finish,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001075 clazz,
Dianne Hackborndb28a942010-10-21 17:22:30 -07001076 "finish", "()V");
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001077 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001078 clazz,
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001079 "setWindowFlags", "(II)V");
1080 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001081 clazz,
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001082 "setWindowFormat", "(I)V");
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001083 GET_METHOD_ID(gNativeActivityClassInfo.showIme,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001084 clazz,
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001085 "showIme", "(I)V");
1086 GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001087 clazz,
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001088 "hideIme", "(I)V");
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001089
Dianne Hackborn69969e42010-05-04 11:40:40 -07001090 return AndroidRuntime::registerNativeMethods(
1091 env, kNativeActivityPathName,
1092 g_methods, NELEM(g_methods));
1093}
1094
Dianne Hackborna95e4cb2010-06-18 18:09:33 -07001095} // namespace android