blob: 21162f43a9fef5c4cfc01d805d56b1c031f31a2a [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 Hackborn289b9b62010-07-09 11:44:11 -070024#include <android_runtime/android_app_NativeActivity.h>
Christopher Tate6cce32b2010-07-12 18:21:36 -070025#include <android_runtime/android_util_AssetManager.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080026#include <android_runtime/android_view_Surface.h>
27#include <android_runtime/AndroidRuntime.h>
Mathias Agopianb93a03f82012-02-17 15:34:57 -080028#include <androidfw/InputTransport.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080029
30#include <gui/Surface.h>
31
32#include <system/window.h>
33
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070034#include <utils/Looper.h>
Dianne Hackborn69969e42010-05-04 11:40:40 -070035
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070036#include "JNIHelp.h"
37#include "android_os_MessageQueue.h"
38#include "android_view_InputChannel.h"
39#include "android_view_KeyEvent.h"
Dianne Hackborn69969e42010-05-04 11:40:40 -070040
Dianne Hackborndb28a942010-10-21 17:22:30 -070041#define LOG_TRACE(...)
Steve Block28d9f022011-10-12 17:27:03 +010042//#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070043
Dianne Hackborn69969e42010-05-04 11:40:40 -070044namespace android
45{
46
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070047static struct {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070048 jmethodID dispatchUnhandledKeyEvent;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -070049 jmethodID preDispatchKeyEvent;
Dianne Hackborndb28a942010-10-21 17:22:30 -070050 jmethodID finish;
Dianne Hackborn54a181b2010-06-30 18:35:14 -070051 jmethodID setWindowFlags;
52 jmethodID setWindowFormat;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070053 jmethodID showIme;
54 jmethodID hideIme;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -070055} gNativeActivityClassInfo;
56
Dianne Hackborn54a181b2010-06-30 18:35:14 -070057// ------------------------------------------------------------------------
58
Dianne Hackborn289b9b62010-07-09 11:44:11 -070059struct ActivityWork {
60 int32_t cmd;
61 int32_t arg1;
62 int32_t arg2;
63};
64
65enum {
66 CMD_DEF_KEY = 1,
Dianne Hackborndb28a942010-10-21 17:22:30 -070067 CMD_FINISH,
Dianne Hackborn289b9b62010-07-09 11:44:11 -070068 CMD_SET_WINDOW_FORMAT,
69 CMD_SET_WINDOW_FLAGS,
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070070 CMD_SHOW_SOFT_INPUT,
71 CMD_HIDE_SOFT_INPUT,
Dianne Hackborn289b9b62010-07-09 11:44:11 -070072};
73
74static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
75 ActivityWork work;
76 work.cmd = cmd;
77 work.arg1 = arg1;
78 work.arg2 = arg2;
79
Dianne Hackbornd76b67c2010-07-13 17:48:30 -070080 LOG_TRACE("write_work: cmd=%d", cmd);
81
Dianne Hackborn289b9b62010-07-09 11:44:11 -070082restart:
83 int res = write(fd, &work, sizeof(work));
84 if (res < 0 && errno == EINTR) {
85 goto restart;
86 }
87
88 if (res == sizeof(work)) return;
89
Steve Block8564c8d2012-01-05 23:22:43 +000090 if (res < 0) ALOGW("Failed writing to work fd: %s", strerror(errno));
91 else ALOGW("Truncated writing to work fd: %d", res);
Dianne Hackborn289b9b62010-07-09 11:44:11 -070092}
93
94static bool read_work(int fd, ActivityWork* outWork) {
95 int res = read(fd, outWork, sizeof(ActivityWork));
96 // no need to worry about EINTR, poll loop will just come back again.
97 if (res == sizeof(ActivityWork)) return true;
98
Steve Block8564c8d2012-01-05 23:22:43 +000099 if (res < 0) ALOGW("Failed reading work fd: %s", strerror(errno));
100 else ALOGW("Truncated reading work fd: %d", res);
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700101 return false;
102}
103
104// ------------------------------------------------------------------------
105
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700106} // namespace android
107
108using namespace android;
109
110AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) :
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700111 mWorkWrite(workWrite), mConsumer(channel), mSeq(0) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700112 int msgpipe[2];
113 if (pipe(msgpipe)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000114 ALOGW("could not create pipe: %s", strerror(errno));
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700115 mDispatchKeyRead = mDispatchKeyWrite = -1;
116 } else {
117 mDispatchKeyRead = msgpipe[0];
118 mDispatchKeyWrite = msgpipe[1];
119 int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK);
120 SLOGW_IF(result != 0, "Could not make AInputQueue read pipe "
121 "non-blocking: %s", strerror(errno));
122 result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK);
123 SLOGW_IF(result != 0, "Could not make AInputQueue write pipe "
124 "non-blocking: %s", strerror(errno));
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700125 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700126}
127
128AInputQueue::~AInputQueue() {
129 close(mDispatchKeyRead);
130 close(mDispatchKeyWrite);
131}
132
Dianne Hackborn42c03e52010-09-07 15:28:30 -0700133void AInputQueue::attachLooper(ALooper* looper, int ident,
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700134 ALooper_callbackFunc callback, void* data) {
135 mLooper = static_cast<android::Looper*>(looper);
Jeff Browncbee6d62012-02-03 20:11:27 -0800136 mLooper->addFd(mConsumer.getChannel()->getFd(),
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700137 ident, ALOOPER_EVENT_INPUT, callback, data);
138 mLooper->addFd(mDispatchKeyRead,
139 ident, ALOOPER_EVENT_INPUT, callback, data);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700140}
141
142void AInputQueue::detachLooper() {
Jeff Browncbee6d62012-02-03 20:11:27 -0800143 mLooper->removeFd(mConsumer.getChannel()->getFd());
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700144 mLooper->removeFd(mDispatchKeyRead);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700145}
146
147int32_t AInputQueue::hasEvents() {
148 struct pollfd pfd[2];
149
Jeff Browncbee6d62012-02-03 20:11:27 -0800150 pfd[0].fd = mConsumer.getChannel()->getFd();
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700151 pfd[0].events = POLLIN;
152 pfd[0].revents = 0;
153 pfd[1].fd = mDispatchKeyRead;
Kenny Root2bb10f42011-02-22 15:00:35 -0800154 pfd[1].events = POLLIN;
155 pfd[1].revents = 0;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700156
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700157 int nfd = poll(pfd, 2, 0);
158 if (nfd <= 0) return 0;
Kenny Root2bb10f42011-02-22 15:00:35 -0800159 return ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN)) ? 1 : -1;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700160}
161
162int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
163 *outEvent = NULL;
164
165 char byteread;
166 ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700167
168 Mutex::Autolock _l(mLock);
169
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700170 if (nRead == 1) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700171 if (mDispatchingKeys.size() > 0) {
172 KeyEvent* kevent = mDispatchingKeys[0];
173 *outEvent = kevent;
174 mDispatchingKeys.removeAt(0);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700175 in_flight_event inflight;
176 inflight.event = kevent;
177 inflight.seq = -1;
Jeff Brown072ec962012-02-07 14:46:57 -0800178 inflight.finishSeq = 0;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700179 mInFlightEvents.push(inflight);
180 }
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700181
182 bool finishNow = false;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700183 if (mFinishPreDispatches.size() > 0) {
184 finish_pre_dispatch finish(mFinishPreDispatches[0]);
185 mFinishPreDispatches.removeAt(0);
186 const size_t N = mInFlightEvents.size();
187 for (size_t i=0; i<N; i++) {
188 const in_flight_event& inflight(mInFlightEvents[i]);
189 if (inflight.seq == finish.seq) {
190 *outEvent = inflight.event;
191 finishNow = finish.handled;
192 }
193 }
194 if (*outEvent == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000195 ALOGW("getEvent couldn't find inflight for seq %d", finish.seq);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700196 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700197 }
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700198
199 if (finishNow) {
Jeff Brown3915bb82010-11-05 15:02:16 -0700200 finishEvent(*outEvent, true, false);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700201 *outEvent = NULL;
202 return -1;
203 } else if (*outEvent != NULL) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700204 return 0;
205 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700206 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700207
Jeff Brown072ec962012-02-07 14:46:57 -0800208 uint32_t consumerSeq;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700209 InputEvent* myEvent = NULL;
Jeff Brown771526c2012-04-27 15:13:25 -0700210 status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/, -1,
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700211 &consumerSeq, &myEvent);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700212 if (res != android::OK) {
Jeff Brown072ec962012-02-07 14:46:57 -0800213 if (res != android::WOULD_BLOCK) {
214 ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
215 mConsumer.getChannel()->getName().string(), res);
216 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700217 return -1;
218 }
219
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700220 if (mConsumer.hasDeferredEvent()) {
221 wakeupDispatchLocked();
222 }
223
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700224 in_flight_event inflight;
225 inflight.event = myEvent;
226 inflight.seq = -1;
Jeff Brown072ec962012-02-07 14:46:57 -0800227 inflight.finishSeq = consumerSeq;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700228 mInFlightEvents.push(inflight);
229
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700230 *outEvent = myEvent;
231 return 0;
232}
233
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700234bool AInputQueue::preDispatchEvent(AInputEvent* event) {
235 if (((InputEvent*)event)->getType() != AINPUT_EVENT_TYPE_KEY) {
236 // The IME only cares about key events.
237 return false;
238 }
239
240 // For now we only send system keys to the IME... this avoids having
241 // critical keys like DPAD go through this path. We really need to have
242 // the IME report which keys it wants.
243 if (!((KeyEvent*)event)->isSystemKey()) {
244 return false;
245 }
246
247 return preDispatchKey((KeyEvent*)event);
248}
249
Jeff Brown3915bb82010-11-05 15:02:16 -0700250void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultHandling) {
251 LOG_TRACE("finishEvent: %p handled=%d, didDefaultHandling=%d", event,
252 handled ? 1 : 0, didDefaultHandling ? 1 : 0);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700253
Jeff Brown3915bb82010-11-05 15:02:16 -0700254 if (!handled && !didDefaultHandling
255 && ((InputEvent*)event)->getType() == AINPUT_EVENT_TYPE_KEY
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700256 && ((KeyEvent*)event)->hasDefaultAction()) {
257 // The app didn't handle this, but it may have a default action
258 // associated with it. We need to hand this back to Java to be
259 // executed.
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700260 doUnhandledKey((KeyEvent*)event);
261 return;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700262 }
263
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700264 Mutex::Autolock _l(mLock);
265
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700266 const size_t N = mInFlightEvents.size();
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700267 for (size_t i=0; i<N; i++) {
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700268 const in_flight_event& inflight(mInFlightEvents[i]);
269 if (inflight.event == event) {
Jeff Brown072ec962012-02-07 14:46:57 -0800270 if (inflight.finishSeq) {
271 status_t res = mConsumer.sendFinishedSignal(inflight.finishSeq, handled);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700272 if (res != android::OK) {
Steve Block8564c8d2012-01-05 23:22:43 +0000273 ALOGW("Failed to send finished signal on channel '%s'. status=%d",
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700274 mConsumer.getChannel()->getName().string(), res);
275 }
276 }
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700277 mPooledInputEventFactory.recycle(static_cast<InputEvent*>(event));
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700278 mInFlightEvents.removeAt(i);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700279 return;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700280 }
281 }
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700282
Steve Block8564c8d2012-01-05 23:22:43 +0000283 ALOGW("finishEvent called for unknown event: %p", event);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700284}
285
286void AInputQueue::dispatchEvent(android::KeyEvent* event) {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700287 Mutex::Autolock _l(mLock);
288
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700289 LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
290 mDispatchKeyWrite);
291 mDispatchingKeys.add(event);
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700292 wakeupDispatchLocked();
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700293}
294
295void AInputQueue::finishPreDispatch(int seq, bool handled) {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700296 Mutex::Autolock _l(mLock);
297
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700298 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);
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700303 wakeupDispatchLocked();
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700304}
305
306KeyEvent* AInputQueue::consumeUnhandledEvent() {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700307 Mutex::Autolock _l(mLock);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700308
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700309 KeyEvent* event = NULL;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700310 if (mUnhandledKeys.size() > 0) {
311 event = mUnhandledKeys[0];
312 mUnhandledKeys.removeAt(0);
313 }
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700314
315 LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700316 return event;
317}
318
319KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700320 Mutex::Autolock _l(mLock);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700321
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700322 KeyEvent* event = NULL;
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700323 if (mPreDispatchingKeys.size() > 0) {
324 const in_flight_event& inflight(mPreDispatchingKeys[0]);
325 event = static_cast<KeyEvent*>(inflight.event);
326 *outSeq = inflight.seq;
327 mPreDispatchingKeys.removeAt(0);
328 }
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700329
330 LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700331 return event;
332}
333
334KeyEvent* AInputQueue::createKeyEvent() {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700335 Mutex::Autolock _l(mLock);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700336
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700337 return mPooledInputEventFactory.createKeyEvent();
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700338}
339
340void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700341 Mutex::Autolock _l(mLock);
342
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700343 LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite);
344 if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) {
345 write_work(mWorkWrite, CMD_DEF_KEY);
346 }
347 mUnhandledKeys.add(keyEvent);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700348}
349
350bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700351 Mutex::Autolock _l(mLock);
352
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700353 LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite);
354 const size_t N = mInFlightEvents.size();
355 for (size_t i=0; i<N; i++) {
356 in_flight_event& inflight(mInFlightEvents.editItemAt(i));
357 if (inflight.event == keyEvent) {
358 if (inflight.seq >= 0) {
359 // This event has already been pre-dispatched!
360 LOG_TRACE("Event already pre-dispatched!");
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700361 return false;
362 }
363 mSeq++;
364 if (mSeq < 0) mSeq = 1;
365 inflight.seq = mSeq;
366
367 if (mPreDispatchingKeys.size() <= 0 && mWorkWrite >= 0) {
368 write_work(mWorkWrite, CMD_DEF_KEY);
369 }
370 mPreDispatchingKeys.add(inflight);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700371 return true;
372 }
373 }
374
Steve Block8564c8d2012-01-05 23:22:43 +0000375 ALOGW("preDispatchKey called for unknown event: %p", keyEvent);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700376 return false;
377}
378
Jeff Brown2b6c32c2012-03-13 15:00:09 -0700379void AInputQueue::wakeupDispatchLocked() {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700380restart:
381 char dummy = 0;
382 int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
383 if (res < 0 && errno == EINTR) {
384 goto restart;
385 }
386
387 if (res == sizeof(dummy)) return;
388
Steve Block8564c8d2012-01-05 23:22:43 +0000389 if (res < 0) ALOGW("Failed writing to dispatch fd: %s", strerror(errno));
390 else ALOGW("Truncated writing to dispatch fd: %d", res);
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700391}
392
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700393namespace android {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700394
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700395// ------------------------------------------------------------------------
396
397/*
398 * Native state for interacting with the NativeActivity class.
399 */
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700400struct NativeCode : public ANativeActivity {
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700401 NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700402 memset((ANativeActivity*)this, 0, sizeof(ANativeActivity));
403 memset(&callbacks, 0, sizeof(callbacks));
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700404 dlhandle = _dlhandle;
405 createActivityFunc = _createFunc;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700406 nativeWindow = NULL;
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700407 inputChannel = NULL;
408 nativeInputQueue = NULL;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700409 mainWorkRead = mainWorkWrite = -1;
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700410 }
411
412 ~NativeCode() {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700413 if (callbacks.onDestroy != NULL) {
414 callbacks.onDestroy(this);
415 }
416 if (env != NULL && clazz != NULL) {
417 env->DeleteGlobalRef(clazz);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700418 }
Jeff Brown603b4452012-04-06 17:39:41 -0700419 if (messageQueue != NULL && mainWorkRead >= 0) {
420 messageQueue->getLooper()->removeFd(mainWorkRead);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700421 }
422 if (nativeInputQueue != NULL) {
423 nativeInputQueue->mWorkWrite = -1;
424 }
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700425 setSurface(NULL);
426 setInputChannel(NULL);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700427 if (mainWorkRead >= 0) close(mainWorkRead);
428 if (mainWorkWrite >= 0) close(mainWorkWrite);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700429 if (dlhandle != NULL) {
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700430 // for now don't unload... we probably should clean this
431 // up and only keep one open dlhandle per proc, since there
432 // is really no benefit to unloading the code.
433 //dlclose(dlhandle);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700434 }
435 }
436
437 void setSurface(jobject _surface) {
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700438 if (_surface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700439 nativeWindow = android_view_Surface_getNativeWindow(env, _surface);
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700440 } else {
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700441 nativeWindow = NULL;
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700442 }
443 }
444
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700445 status_t setInputChannel(jobject _channel) {
446 if (inputChannel != NULL) {
447 delete nativeInputQueue;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700448 env->DeleteGlobalRef(inputChannel);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700449 }
450 inputChannel = NULL;
451 nativeInputQueue = NULL;
452 if (_channel != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700453 inputChannel = env->NewGlobalRef(_channel);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700454 sp<InputChannel> ic =
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700455 android_view_InputChannel_getInputChannel(env, _channel);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700456 if (ic != NULL) {
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700457 nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700458 } else {
459 return UNKNOWN_ERROR;
460 }
461 }
462 return OK;
463 }
464
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700465 ANativeActivityCallbacks callbacks;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700466
467 void* dlhandle;
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700468 ANativeActivity_createFunc* createActivityFunc;
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700469
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800470 String8 internalDataPathObj;
471 String8 externalDataPathObj;
472 String8 obbPathObj;
Dianne Hackborn68267412010-07-02 18:52:01 -0700473
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700474 sp<ANativeWindow> nativeWindow;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700475 int32_t lastWindowWidth;
476 int32_t lastWindowHeight;
477
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700478 jobject inputChannel;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700479 struct AInputQueue* nativeInputQueue;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700480
481 // These are used to wake up the main thread to process work.
482 int mainWorkRead;
483 int mainWorkWrite;
Jeff Brown603b4452012-04-06 17:39:41 -0700484 sp<MessageQueue> messageQueue;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700485};
486
Dianne Hackborndb28a942010-10-21 17:22:30 -0700487void android_NativeActivity_finish(ANativeActivity* activity) {
488 NativeCode* code = static_cast<NativeCode*>(activity);
489 write_work(code->mainWorkWrite, CMD_FINISH, 0);
490}
491
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700492void android_NativeActivity_setWindowFormat(
493 ANativeActivity* activity, int32_t format) {
494 NativeCode* code = static_cast<NativeCode*>(activity);
495 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format);
496}
497
498void android_NativeActivity_setWindowFlags(
499 ANativeActivity* activity, int32_t values, int32_t mask) {
500 NativeCode* code = static_cast<NativeCode*>(activity);
501 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
502}
503
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700504void android_NativeActivity_showSoftInput(
505 ANativeActivity* activity, int32_t flags) {
506 NativeCode* code = static_cast<NativeCode*>(activity);
507 write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags);
508}
509
510void android_NativeActivity_hideSoftInput(
511 ANativeActivity* activity, int32_t flags) {
512 NativeCode* code = static_cast<NativeCode*>(activity);
513 write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags);
514}
515
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700516// ------------------------------------------------------------------------
517
518/*
519 * Callback for handling native events on the application's main thread.
520 */
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700521static int mainWorkCallback(int fd, int events, void* data) {
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700522 NativeCode* code = (NativeCode*)data;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700523 if ((events & POLLIN) == 0) {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700524 return 1;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700525 }
526
527 ActivityWork work;
528 if (!read_work(code->mainWorkRead, &work)) {
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700529 return 1;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700530 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700531
532 LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
533
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700534 switch (work.cmd) {
535 case CMD_DEF_KEY: {
536 KeyEvent* keyEvent;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700537 while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700538 jobject inputEventObj = android_view_KeyEvent_fromNative(
539 code->env, keyEvent);
Jeff Brown1f245102010-11-18 20:53:46 -0800540 jboolean handled;
541 if (inputEventObj) {
542 handled = code->env->CallBooleanMethod(code->clazz,
543 gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
Jeff Brown603b4452012-04-06 17:39:41 -0700544 code->messageQueue->raiseAndClearException(
545 code->env, "dispatchUnhandledKeyEvent");
Jeff Brown1f245102010-11-18 20:53:46 -0800546 code->env->DeleteLocalRef(inputEventObj);
547 } else {
Steve Block3762c312012-01-06 19:20:56 +0000548 ALOGE("Failed to obtain key event for dispatchUnhandledKeyEvent.");
Jeff Brown1f245102010-11-18 20:53:46 -0800549 handled = false;
550 }
Jeff Brown3915bb82010-11-05 15:02:16 -0700551 code->nativeInputQueue->finishEvent(keyEvent, handled, true);
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700552 }
553 int seq;
554 while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) {
555 jobject inputEventObj = android_view_KeyEvent_fromNative(
556 code->env, keyEvent);
Jeff Brown1f245102010-11-18 20:53:46 -0800557 if (inputEventObj) {
558 code->env->CallVoidMethod(code->clazz,
559 gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
Jeff Brown603b4452012-04-06 17:39:41 -0700560 code->messageQueue->raiseAndClearException(code->env, "preDispatchKeyEvent");
Jeff Brown1f245102010-11-18 20:53:46 -0800561 code->env->DeleteLocalRef(inputEventObj);
562 } else {
Steve Block3762c312012-01-06 19:20:56 +0000563 ALOGE("Failed to obtain key event for preDispatchKeyEvent.");
Jeff Brown1f245102010-11-18 20:53:46 -0800564 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700565 }
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700566 } break;
Dianne Hackborndb28a942010-10-21 17:22:30 -0700567 case CMD_FINISH: {
568 code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish);
Jeff Brown603b4452012-04-06 17:39:41 -0700569 code->messageQueue->raiseAndClearException(code->env, "finish");
Dianne Hackborndb28a942010-10-21 17:22:30 -0700570 } break;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700571 case CMD_SET_WINDOW_FORMAT: {
572 code->env->CallVoidMethod(code->clazz,
573 gNativeActivityClassInfo.setWindowFormat, work.arg1);
Jeff Brown603b4452012-04-06 17:39:41 -0700574 code->messageQueue->raiseAndClearException(code->env, "setWindowFormat");
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700575 } break;
576 case CMD_SET_WINDOW_FLAGS: {
577 code->env->CallVoidMethod(code->clazz,
578 gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
Jeff Brown603b4452012-04-06 17:39:41 -0700579 code->messageQueue->raiseAndClearException(code->env, "setWindowFlags");
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700580 } break;
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700581 case CMD_SHOW_SOFT_INPUT: {
582 code->env->CallVoidMethod(code->clazz,
583 gNativeActivityClassInfo.showIme, work.arg1);
Jeff Brown603b4452012-04-06 17:39:41 -0700584 code->messageQueue->raiseAndClearException(code->env, "showIme");
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700585 } break;
586 case CMD_HIDE_SOFT_INPUT: {
587 code->env->CallVoidMethod(code->clazz,
588 gNativeActivityClassInfo.hideIme, work.arg1);
Jeff Brown603b4452012-04-06 17:39:41 -0700589 code->messageQueue->raiseAndClearException(code->env, "hideIme");
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700590 } break;
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700591 default:
Steve Block8564c8d2012-01-05 23:22:43 +0000592 ALOGW("Unknown work command: %d", work.cmd);
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700593 break;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700594 }
595
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700596 return 1;
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700597}
598
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700599// ------------------------------------------------------------------------
600
Dianne Hackborn69969e42010-05-04 11:40:40 -0700601static jint
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700602loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800603 jobject messageQueue, jstring internalDataDir, jstring obbDir,
604 jstring externalDataDir, int sdkVersion,
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700605 jobject jAssetMgr, jbyteArray savedState)
Dianne Hackborn69969e42010-05-04 11:40:40 -0700606{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700607 LOG_TRACE("loadNativeCode_native");
608
Dianne Hackborn69969e42010-05-04 11:40:40 -0700609 const char* pathStr = env->GetStringUTFChars(path, NULL);
610 NativeCode* code = NULL;
611
612 void* handle = dlopen(pathStr, RTLD_LAZY);
613
614 env->ReleaseStringUTFChars(path, pathStr);
615
616 if (handle != NULL) {
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700617 const char* funcStr = env->GetStringUTFChars(funcName, NULL);
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700618 code = new NativeCode(handle, (ANativeActivity_createFunc*)
Dianne Hackborne21d91c62010-10-24 14:56:38 -0700619 dlsym(handle, funcStr));
620 env->ReleaseStringUTFChars(funcName, funcStr);
621
Dianne Hackborn69969e42010-05-04 11:40:40 -0700622 if (code->createActivityFunc == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000623 ALOGW("ANativeActivity_onCreate not found");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700624 delete code;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700625 return 0;
626 }
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700627
Jeff Brown603b4452012-04-06 17:39:41 -0700628 code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue);
629 if (code->messageQueue == NULL) {
630 ALOGW("Unable to retrieve native MessageQueue");
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700631 delete code;
632 return 0;
633 }
634
635 int msgpipe[2];
636 if (pipe(msgpipe)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000637 ALOGW("could not create pipe: %s", strerror(errno));
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700638 delete code;
639 return 0;
640 }
641 code->mainWorkRead = msgpipe[0];
642 code->mainWorkWrite = msgpipe[1];
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700643 int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
644 SLOGW_IF(result != 0, "Could not make main work read pipe "
645 "non-blocking: %s", strerror(errno));
646 result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
647 SLOGW_IF(result != 0, "Could not make main work write pipe "
648 "non-blocking: %s", strerror(errno));
Jeff Brown603b4452012-04-06 17:39:41 -0700649 code->messageQueue->getLooper()->addFd(
650 code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -0700651
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700652 code->ANativeActivity::callbacks = &code->callbacks;
653 if (env->GetJavaVM(&code->vm) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000654 ALOGW("NativeActivity GetJavaVM failed");
Dianne Hackborn2e9f93e2010-06-28 15:27:30 -0700655 delete code;
656 return 0;
657 }
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700658 code->env = env;
659 code->clazz = env->NewGlobalRef(clazz);
Christopher Tate6cce32b2010-07-12 18:21:36 -0700660
Dianne Hackborn68267412010-07-02 18:52:01 -0700661 const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800662 code->internalDataPathObj = dirStr;
663 code->internalDataPath = code->internalDataPathObj.string();
664 env->ReleaseStringUTFChars(internalDataDir, dirStr);
Dianne Hackborn68267412010-07-02 18:52:01 -0700665
666 dirStr = env->GetStringUTFChars(externalDataDir, NULL);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800667 code->externalDataPathObj = dirStr;
668 code->externalDataPath = code->externalDataPathObj.string();
669 env->ReleaseStringUTFChars(externalDataDir, dirStr);
Christopher Tate6cce32b2010-07-12 18:21:36 -0700670
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700671 code->sdkVersion = sdkVersion;
Dianne Hackborn68267412010-07-02 18:52:01 -0700672
Christopher Tate6cce32b2010-07-12 18:21:36 -0700673 code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
674
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800675 dirStr = env->GetStringUTFChars(obbDir, NULL);
676 code->obbPathObj = dirStr;
677 code->obbPath = code->obbPathObj.string();
678 env->ReleaseStringUTFChars(obbDir, dirStr);
679
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700680 jbyte* rawSavedState = NULL;
681 jsize rawSavedSize = 0;
682 if (savedState != NULL) {
683 rawSavedState = env->GetByteArrayElements(savedState, NULL);
684 rawSavedSize = env->GetArrayLength(savedState);
685 }
686
687 code->createActivityFunc(code, rawSavedState, rawSavedSize);
688
689 if (rawSavedState != NULL) {
690 env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
691 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700692 }
693
694 return (jint)code;
695}
696
697static void
698unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
699{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700700 LOG_TRACE("unloadNativeCode_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700701 if (handle != 0) {
702 NativeCode* code = (NativeCode*)handle;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700703 delete code;
704 }
705}
706
707static void
708onStart_native(JNIEnv* env, jobject clazz, jint handle)
709{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700710 LOG_TRACE("onStart_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700711 if (handle != 0) {
712 NativeCode* code = (NativeCode*)handle;
713 if (code->callbacks.onStart != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700714 code->callbacks.onStart(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700715 }
716 }
717}
718
719static void
720onResume_native(JNIEnv* env, jobject clazz, jint handle)
721{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700722 LOG_TRACE("onResume_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700723 if (handle != 0) {
724 NativeCode* code = (NativeCode*)handle;
725 if (code->callbacks.onResume != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700726 code->callbacks.onResume(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700727 }
728 }
729}
730
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700731static jbyteArray
Dianne Hackborn69969e42010-05-04 11:40:40 -0700732onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
733{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700734 LOG_TRACE("onSaveInstanceState_native");
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700735
736 jbyteArray array = NULL;
737
Dianne Hackborn69969e42010-05-04 11:40:40 -0700738 if (handle != 0) {
739 NativeCode* code = (NativeCode*)handle;
740 if (code->callbacks.onSaveInstanceState != NULL) {
741 size_t len = 0;
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700742 jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len);
743 if (len > 0) {
744 array = env->NewByteArray(len);
745 if (array != NULL) {
746 env->SetByteArrayRegion(array, 0, len, state);
747 }
748 }
749 if (state != NULL) {
750 free(state);
751 }
Dianne Hackborn69969e42010-05-04 11:40:40 -0700752 }
753 }
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700754
755 return array;
Dianne Hackborn69969e42010-05-04 11:40:40 -0700756}
757
758static void
759onPause_native(JNIEnv* env, jobject clazz, jint handle)
760{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700761 LOG_TRACE("onPause_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700762 if (handle != 0) {
763 NativeCode* code = (NativeCode*)handle;
764 if (code->callbacks.onPause != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700765 code->callbacks.onPause(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700766 }
767 }
768}
769
770static void
771onStop_native(JNIEnv* env, jobject clazz, jint handle)
772{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700773 LOG_TRACE("onStop_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700774 if (handle != 0) {
775 NativeCode* code = (NativeCode*)handle;
776 if (code->callbacks.onStop != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700777 code->callbacks.onStop(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700778 }
779 }
780}
781
782static void
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700783onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle)
784{
785 LOG_TRACE("onConfigurationChanged_native");
786 if (handle != 0) {
787 NativeCode* code = (NativeCode*)handle;
788 if (code->callbacks.onConfigurationChanged != NULL) {
789 code->callbacks.onConfigurationChanged(code);
790 }
791 }
792}
793
794static void
Dianne Hackborn69969e42010-05-04 11:40:40 -0700795onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
796{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700797 LOG_TRACE("onLowMemory_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700798 if (handle != 0) {
799 NativeCode* code = (NativeCode*)handle;
800 if (code->callbacks.onLowMemory != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700801 code->callbacks.onLowMemory(code);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700802 }
803 }
804}
805
806static void
807onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
808{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700809 LOG_TRACE("onWindowFocusChanged_native");
Dianne Hackborn69969e42010-05-04 11:40:40 -0700810 if (handle != 0) {
811 NativeCode* code = (NativeCode*)handle;
812 if (code->callbacks.onWindowFocusChanged != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700813 code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
Dianne Hackborn69969e42010-05-04 11:40:40 -0700814 }
815 }
816}
817
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700818static void
819onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
820{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700821 LOG_TRACE("onSurfaceCreated_native");
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700822 if (handle != 0) {
823 NativeCode* code = (NativeCode*)handle;
824 code->setSurface(surface);
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700825 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700826 code->callbacks.onNativeWindowCreated(code,
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700827 code->nativeWindow.get());
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700828 }
829 }
830}
831
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700832static int32_t getWindowProp(ANativeWindow* window, int what) {
833 int value;
834 int res = window->query(window, what, &value);
835 return res < 0 ? res : value;
836}
837
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700838static void
839onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
840 jint format, jint width, jint height)
841{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700842 LOG_TRACE("onSurfaceChanged_native");
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700843 if (handle != 0) {
844 NativeCode* code = (NativeCode*)handle;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700845 sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
846 code->setSurface(surface);
847 if (oldNativeWindow != code->nativeWindow) {
Dianne Hackborn8ae5a8e2010-07-01 18:44:46 -0700848 if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700849 code->callbacks.onNativeWindowDestroyed(code,
Dianne Hackborn8ae5a8e2010-07-01 18:44:46 -0700850 oldNativeWindow.get());
851 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700852 if (code->nativeWindow != NULL) {
853 if (code->callbacks.onNativeWindowCreated != NULL) {
854 code->callbacks.onNativeWindowCreated(code,
855 code->nativeWindow.get());
856 }
857 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
858 NATIVE_WINDOW_WIDTH);
859 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
860 NATIVE_WINDOW_HEIGHT);
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700861 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700862 } else {
863 // Maybe it resized?
864 int32_t newWidth = getWindowProp(code->nativeWindow.get(),
865 NATIVE_WINDOW_WIDTH);
866 int32_t newHeight = getWindowProp(code->nativeWindow.get(),
867 NATIVE_WINDOW_HEIGHT);
868 if (newWidth != code->lastWindowWidth
869 || newHeight != code->lastWindowHeight) {
870 if (code->callbacks.onNativeWindowResized != NULL) {
871 code->callbacks.onNativeWindowResized(code,
872 code->nativeWindow.get());
873 }
874 }
875 }
876 }
877}
878
879static void
880onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle)
881{
882 LOG_TRACE("onSurfaceRedrawNeeded_native");
883 if (handle != 0) {
884 NativeCode* code = (NativeCode*)handle;
885 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
886 code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700887 }
888 }
889}
890
891static void
892onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
893{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700894 LOG_TRACE("onSurfaceDestroyed_native");
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700895 if (handle != 0) {
896 NativeCode* code = (NativeCode*)handle;
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700897 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700898 code->callbacks.onNativeWindowDestroyed(code,
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700899 code->nativeWindow.get());
Dianne Hackborn74323fd2010-05-18 17:56:23 -0700900 }
901 code->setSurface(NULL);
902 }
903}
904
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700905static void
906onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
907{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700908 LOG_TRACE("onInputChannelCreated_native");
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700909 if (handle != 0) {
910 NativeCode* code = (NativeCode*)handle;
911 status_t err = code->setInputChannel(channel);
912 if (err != OK) {
913 jniThrowException(env, "java/lang/IllegalStateException",
914 "Error setting input channel");
915 return;
916 }
917 if (code->callbacks.onInputQueueCreated != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700918 code->callbacks.onInputQueueCreated(code,
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700919 code->nativeInputQueue);
920 }
921 }
922}
923
924static void
925onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
926{
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700927 LOG_TRACE("onInputChannelDestroyed_native");
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700928 if (handle != 0) {
929 NativeCode* code = (NativeCode*)handle;
930 if (code->nativeInputQueue != NULL
931 && code->callbacks.onInputQueueDestroyed != NULL) {
Dianne Hackborn289b9b62010-07-09 11:44:11 -0700932 code->callbacks.onInputQueueDestroyed(code,
Dianne Hackborna95e4cb2010-06-18 18:09:33 -0700933 code->nativeInputQueue);
934 }
935 code->setInputChannel(NULL);
936 }
937}
938
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700939static void
940onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle,
941 jint x, jint y, jint w, jint h)
942{
943 LOG_TRACE("onContentRectChanged_native");
944 if (handle != 0) {
945 NativeCode* code = (NativeCode*)handle;
946 if (code->callbacks.onContentRectChanged != NULL) {
947 ARect rect;
948 rect.left = x;
949 rect.top = y;
950 rect.right = x+w;
951 rect.bottom = y+h;
952 code->callbacks.onContentRectChanged(code, &rect);
953 }
954 }
955}
956
957static void
958dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj)
959{
960 LOG_TRACE("dispatchKeyEvent_native");
961 if (handle != 0) {
962 NativeCode* code = (NativeCode*)handle;
963 if (code->nativeInputQueue != NULL) {
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700964 KeyEvent* event = code->nativeInputQueue->createKeyEvent();
Jeff Brown1f245102010-11-18 20:53:46 -0800965 status_t status = android_view_KeyEvent_toNative(env, eventObj, event);
966 if (status) {
967 delete event;
968 jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
969 return;
970 }
Dianne Hackbornd76b67c2010-07-13 17:48:30 -0700971 code->nativeInputQueue->dispatchEvent(event);
972 }
973 }
974}
975
Dianne Hackborn2c6081c2010-07-15 17:44:53 -0700976static void
977finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle,
978 jint seq, jboolean handled)
979{
980 LOG_TRACE("finishPreDispatchKeyEvent_native");
981 if (handle != 0) {
982 NativeCode* code = (NativeCode*)handle;
983 if (code->nativeInputQueue != NULL) {
984 code->nativeInputQueue->finishPreDispatch(seq, handled ? true : false);
985 }
986 }
987}
988
Dianne Hackborn69969e42010-05-04 11:40:40 -0700989static const JNINativeMethod g_methods[] = {
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800990 { "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 -0700991 (void*)loadNativeCode_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -0700992 { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
993 { "onStartNative", "(I)V", (void*)onStart_native },
994 { "onResumeNative", "(I)V", (void*)onResume_native },
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700995 { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -0700996 { "onPauseNative", "(I)V", (void*)onPause_native },
997 { "onStopNative", "(I)V", (void*)onStop_native },
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -0700998 { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -0700999 { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
1000 { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001001 { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
1002 { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001003 { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001004 { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
Dianne Hackborna95e4cb2010-06-18 18:09:33 -07001005 { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
1006 { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001007 { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native },
1008 { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native },
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001009 { "finishPreDispatchKeyEventNative", "(IIZ)V", (void*)finishPreDispatchKeyEvent_native },
Dianne Hackborn69969e42010-05-04 11:40:40 -07001010};
1011
1012static const char* const kNativeActivityPathName = "android/app/NativeActivity";
1013
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -07001014#define FIND_CLASS(var, className) \
1015 var = env->FindClass(className); \
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001016 LOG_FATAL_IF(! var, "Unable to find class %s", className);
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -07001017
1018#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
1019 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
1020 LOG_FATAL_IF(! var, "Unable to find method" methodName);
1021
Dianne Hackborn69969e42010-05-04 11:40:40 -07001022int register_android_app_NativeActivity(JNIEnv* env)
1023{
Steve Block5baa3a62011-12-20 16:23:08 +00001024 //ALOGD("register_android_app_NativeActivity");
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001025 jclass clazz;
1026 FIND_CLASS(clazz, kNativeActivityPathName);
Dianne Hackborn69969e42010-05-04 11:40:40 -07001027
Dianne Hackborn3c80a4a2010-06-29 19:20:40 -07001028 GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001029 clazz,
Jeff Brown3915bb82010-11-05 15:02:16 -07001030 "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)Z");
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001031 GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001032 clazz,
Dianne Hackborn2c6081c2010-07-15 17:44:53 -07001033 "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V");
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001034
Dianne Hackborndb28a942010-10-21 17:22:30 -07001035 GET_METHOD_ID(gNativeActivityClassInfo.finish,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001036 clazz,
Dianne Hackborndb28a942010-10-21 17:22:30 -07001037 "finish", "()V");
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001038 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001039 clazz,
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001040 "setWindowFlags", "(II)V");
1041 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001042 clazz,
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001043 "setWindowFormat", "(I)V");
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001044 GET_METHOD_ID(gNativeActivityClassInfo.showIme,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001045 clazz,
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001046 "showIme", "(I)V");
1047 GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
Carl Shapiro17cc33a2011-03-05 20:53:16 -08001048 clazz,
Dianne Hackbornd76b67c2010-07-13 17:48:30 -07001049 "hideIme", "(I)V");
Dianne Hackborn54a181b2010-06-30 18:35:14 -07001050
Dianne Hackborn69969e42010-05-04 11:40:40 -07001051 return AndroidRuntime::registerNativeMethods(
1052 env, kNativeActivityPathName,
1053 g_methods, NELEM(g_methods));
1054}
1055
Dianne Hackborna95e4cb2010-06-18 18:09:33 -07001056} // namespace android