Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: runtime/embedders/openglui/android/eventloop.cc

Issue 25081002: Remove openglui embedder code (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "embedders/openglui/android/eventloop.h"
6
7 #include <time.h>
8 #include "embedders/openglui/common/log.h"
9
10 /*
11 * The Android lifecycle events are:
12 *
13 * OnCreate: In NDK this is the call to android_main
14 *
15 * OnStart: technically, called to initiate the “visible” lifespan of the
16 * app; at any time between OnStart and OnStop, the app may be visible.
17 * We can either be OnResume’d or OnStop’ped from this state. Note that
18 * there is also an event for OnRestart, which is called before OnStart
19 * if the application is transitioning from OnStop to OnStart instead of
20 * being started from scratch.
21 *
22 * OnResume: technically, the start of the “foreground” lifespan of the app,
23 * but this does not mean that the app is fully visible and should be
24 * rendering – more on that later
25 *
26 * OnPause: the app is losing its foregrounded state; this is normally an
27 * indication that something is fully covering the app. On versions of
28 * Android before Honeycomb, once we returned from this callback, we
29 * could be killed at any time with no further app code called. We can
30 * either be OnResume’d or OnStop’ped from this state. OnPause halts the
31 * visible UI thread and so should be handled as quickly as possible.
32 *
33 * OnStop: the end of the current visible lifespan of the app – we may
34 * transition to On(Re)Start to become visible again, or to OnDestroy if
35 * we are shutting down entirely. Once we return from this callback, we
36 * can be killed at any time with no further app code called on any
37 * version of Android.
38 *
39 * OnDestroy: this can only be followed by the application being killed or
40 * restarted with OnCreate.
41 *
42 * The above events occur in fixed orders. The events below can occur at
43 * various times:
44 *
45 * OnGainedFocus: happens between OnResume and OnPause.
46 * OnLostFocus: may occur at arbitrary times, and may in fact not happen
47 * at all if the app is being destroyed. So OnPause and OnGainedFocus/
48 * OnLostFocus must be used together to determine the visible and
49 * interactable state of the app.
50 *
51 * OnCreateWindow: usually happens in the resumed state
52 * OnDestroyWindow: can happen after OnPause or OnDestroy, so apps may
53 * need to handle shutting down EGL before their surfaces are
54 * destroyed.
55 * OnConfigurationChanged: typically means the size has changed
56 *
57 * An application's EGL surface may only exist between the OnCreateWindow
58 * and OnDestroyWindow callbacks.
59 *
60 * An application is "killable" after OnStop or OnDestroy (in earlier
61 * Android versions, after OnPause too). That means any critical state
62 * or resources must be handled by any of these callbacks.
63 *
64 * These callbacks run on the main thread. If they block any event
65 * processing for more than 5 seconds this will result in an ANR
66 * (Application Not Responding message).
67 *
68 * On application launch, this sequence will occur:
69 *
70 * - OnCreate
71 * - OnStart
72 * - OnResume
73 * - OnCreateWindow
74 * - OnConfigurationChanged
75 * - OnGainedFocus
76 *
77 * If the back button is pressed, and the app does not handle it,
78 * Android will pop the app of the UI stack and destroy the application's
79 * activity:
80 *
81 * - OnPause
82 * - OnLostFocus
83 * - OnDestroyWindow
84 * - OnStop
85 * - OnDestroy
86 *
87 * If the home button is pressed, the app is sent down in the UI stack.
88 * The app's Activity still exists but may be killed at any time, and
89 * it loses its rendering surface:
90 *
91 * - OnPause
92 * - OnLostFocus
93 * - OnDestroyWindow
94 * - OnStop
95 *
96 * If the app is then restarted (without having been killed in between):
97 *
98 * - OnRestart
99 * - OnStart
100 * - OnResume
101 * - OnCreateWindow
102 * - OnConfigurationChanged
103 * - OnGainedFocus
104 *
105 * If a status icon pop up is opened, the app is still visible and can render
106 * but is not focused and cannot receive input:
107 *
108 * - OnLostFocus
109 *
110 * When the popup is dismissed, the app regains focus:
111 *
112 * - OnGainedFocus
113 *
114 * When the device is suspended (power button or screen saver), the application
115 * will typically be paused and lose focus:
116 *
117 * - OnPause
118 * - OnLostFocus (sometimes this will only come when the device is resumed
119 * to the lock screen)
120 *
121 * The application should have stopped all rendering and sound and any
122 * non-critical background processing.
123 *
124 * When the device is resumed but not yet unlocked, the app will be resumed:
125 *
126 * - OnResume
127 *
128 * The application should not perform sound or graphics yet. If the lock
129 * screen times out, the app will be paused again. If the screen is
130 * unlocked, the app will regain focus.
131 *
132 * Turning all of this into a general framework, we can use the following:
133 *
134 * 1. In OnCreate/android_main, set up the main classes and possibly
135 * load some lightweight resources.
136 * 2. In OnCreateWindow, create the EGLSurface, bind the context, load
137 * OpenGL resources. No rendering.
138 * 3. When we are between OnResume and OnPause, and between OnCreateWindow
139 * and OnDestroyWindow, and between OnGainedFocus and OnLostFocus,
140 * we can render and process input.
141 * 4. In OnLostFocus, stop sounds from playing, and stop rendering.
142 * 5. In OnPause, stop all rendering
143 * 6. In OnResume, prepare to start rendering again, but don't render.
144 * 7. In OnGainedFocus after OnResume, start rendering and sound again.
145 * 8. In OnStop, free all graphic resources, either through GLES calls
146 * if the EGLContext is still bound, or via eglDestroyContext if the
147 * context has been unbound because the rendering surface was destroyed.
148 * 9. In OnDestroy, release all other resources.
149 */
150 EventLoop::EventLoop(android_app* application)
151 : enabled_(false),
152 quit_(false),
153 isResumed_(false),
154 hasSurface_(false),
155 hasFocus_(false),
156 application_(application),
157 lifecycle_handler_(NULL),
158 input_handler_(NULL),
159 sensor_manager_(NULL),
160 sensor_event_queue_(NULL),
161 sensor_poll_source_() {
162 application_->onAppCmd = ActivityCallback;
163 application_->onInputEvent = InputCallback;
164 application_->userData = this;
165 }
166
167 static int64_t getTimeInMillis() {
168 struct timespec res;
169 clock_gettime(CLOCK_REALTIME, &res);
170 return 1000 * res.tv_sec + res.tv_nsec / 1000000;
171 }
172
173 void EventLoop::Run(LifeCycleHandler* lifecycle_handler,
174 InputHandler* input_handler) {
175 int32_t result;
176 int32_t events;
177 android_poll_source* source;
178
179 lifecycle_handler_ = lifecycle_handler;
180 input_handler_ = input_handler;
181 int64_t last_frame_time = getTimeInMillis();
182 if (lifecycle_handler_->OnStart() == 0) {
183 LOGI("Starting event loop");
184 while (!quit_) {
185 // If not enabled, block indefinitely on events. If enabled, block
186 // briefly so we can do useful work in onStep, but only long
187 // enough that we can still do work at 60fps if possible.
188 int64_t next_frame_time = last_frame_time + (1000/60);
189 int64_t next_frame_delay = next_frame_time - getTimeInMillis();
190 if (next_frame_delay < 0) next_frame_delay = 0;
191 while ((result = ALooper_pollAll(enabled_ ? next_frame_delay : -1, NULL,
192 &events, reinterpret_cast<void**>(&source))) >= 0) {
193 if (source != NULL) {
194 source->process(application_, source);
195 }
196 if (application_->destroyRequested) {
197 return;
198 }
199 }
200 if (enabled_ && !quit_) {
201 int64_t now = getTimeInMillis();
202 if (now >= next_frame_time) {
203 LOGI("step");
204 last_frame_time = now;
205 if (lifecycle_handler_->OnStep() != 0) {
206 quit_ = true;
207 }
208 }
209 }
210 }
211 }
212 ANativeActivity_finish(application_->activity);
213 }
214
215 void EventLoop::EnableSensorEvents() {
216 sensor_poll_source_.id = LOOPER_ID_USER;
217 sensor_poll_source_.app = application_;
218 sensor_poll_source_.process = SensorCallback;
219 sensor_manager_ = ASensorManager_getInstance();
220 if (sensor_manager_ != NULL) {
221 sensor_event_queue_ = ASensorManager_createEventQueue(
222 sensor_manager_, application_->looper,
223 LOOPER_ID_USER, NULL, &sensor_poll_source_);
224
225 sensor_ = ASensorManager_getDefaultSensor(sensor_manager_,
226 ASENSOR_TYPE_ACCELEROMETER);
227 if (sensor_ != NULL) {
228 int32_t min_delay = ASensor_getMinDelay(sensor_);
229 if (ASensorEventQueue_enableSensor(sensor_event_queue_, sensor_) < 0 ||
230 ASensorEventQueue_setEventRate(sensor_event_queue_, sensor_,
231 min_delay) < 0) {
232 LOGE("Error while activating sensor.");
233 DisableSensorEvents();
234 return;
235 }
236 LOGI("Activating sensor:");
237 LOGI("Name : %s", ASensor_getName(sensor_));
238 LOGI("Vendor : %s", ASensor_getVendor(sensor_));
239 LOGI("Resolution : %f", ASensor_getResolution(sensor_));
240 LOGI("Min Delay : %d", min_delay);
241 } else {
242 LOGI("No sensor");
243 }
244 }
245 }
246
247 void EventLoop::DisableSensorEvents() {
248 if (sensor_ != NULL) {
249 if (ASensorEventQueue_disableSensor(sensor_event_queue_, sensor_) < 0) {
250 LOGE("Error while deactivating sensor.");
251 }
252 sensor_ = NULL;
253 }
254 if (sensor_event_queue_ != NULL) {
255 ASensorManager_destroyEventQueue(sensor_manager_,
256 sensor_event_queue_);
257 sensor_event_queue_ = NULL;
258 }
259 sensor_manager_ = NULL;
260 }
261
262 void EventLoop::ProcessActivityEvent(int32_t command) {
263 switch (command) {
264 case APP_CMD_INIT_WINDOW:
265 if (lifecycle_handler_->Activate() != 0) {
266 quit_ = true;
267 } else {
268 hasSurface_ = true;
269 }
270 break;
271 case APP_CMD_CONFIG_CHANGED:
272 lifecycle_handler_->OnConfigurationChanged();
273 break;
274 case APP_CMD_DESTROY:
275 hasFocus_ = false;
276 lifecycle_handler_->FreeAllResources();
277 break;
278 case APP_CMD_GAINED_FOCUS:
279 hasFocus_ = true;
280 if (hasSurface_ && isResumed_ && hasFocus_) {
281 enabled_ = (lifecycle_handler_->Resume() == 0);
282 if (enabled_) {
283 EnableSensorEvents();
284 }
285 }
286 break;
287 case APP_CMD_LOST_FOCUS:
288 hasFocus_ = false;
289 enabled_ = false;
290 DisableSensorEvents();
291 lifecycle_handler_->Pause();
292 break;
293 case APP_CMD_LOW_MEMORY:
294 lifecycle_handler_->OnLowMemory();
295 break;
296 case APP_CMD_PAUSE:
297 isResumed_ = false;
298 enabled_ = false;
299 DisableSensorEvents();
300 lifecycle_handler_->Pause();
301 break;
302 case APP_CMD_RESUME:
303 isResumed_ = true;
304 break;
305 case APP_CMD_SAVE_STATE:
306 lifecycle_handler_->OnSaveState(&application_->savedState,
307 &application_->savedStateSize);
308 break;
309 case APP_CMD_START:
310 break;
311 case APP_CMD_STOP:
312 hasFocus_ = false;
313 lifecycle_handler_->Deactivate();
314 break;
315 case APP_CMD_TERM_WINDOW:
316 hasFocus_ = false;
317 hasSurface_ = false;
318 enabled_ = false;
319 DisableSensorEvents();
320 lifecycle_handler_->Pause();
321 break;
322 default:
323 break;
324 }
325 }
326
327 void EventLoop::ProcessSensorEvent() {
328 ASensorEvent event;
329 while (ASensorEventQueue_getEvents(sensor_event_queue_, &event, 1) > 0) {
330 switch (event.type) {
331 case ASENSOR_TYPE_ACCELEROMETER:
332 input_handler_->OnAccelerometerEvent(event.vector.x,
333 event.vector.y, event.vector.z);
334 break;
335 }
336 }
337 }
338
339 bool EventLoop::OnTouchEvent(AInputEvent* event) {
340 int32_t type = AMotionEvent_getAction(event);
341 MotionEvent motion_event;
342 switch (type) {
343 case AMOTION_EVENT_ACTION_DOWN:
344 motion_event = kMotionDown;
345 break;
346 case AMOTION_EVENT_ACTION_UP:
347 motion_event = kMotionUp;
348 break;
349 case AMOTION_EVENT_ACTION_MOVE:
350 motion_event = kMotionMove;
351 break;
352 case AMOTION_EVENT_ACTION_CANCEL:
353 motion_event = kMotionCancel;
354 break;
355 case AMOTION_EVENT_ACTION_OUTSIDE:
356 motion_event = kMotionOutside;
357 break;
358 case AMOTION_EVENT_ACTION_POINTER_DOWN:
359 motion_event = kMotionPointerDown;
360 break;
361 case AMOTION_EVENT_ACTION_POINTER_UP:
362 motion_event = kMotionPointerUp;
363 break;
364 default:
365 return false;
366 }
367 // For now we just get the last coords.
368 float move_x = AMotionEvent_getX(event, 0);
369 float move_y = AMotionEvent_getY(event, 0);
370 int64_t when = AMotionEvent_getEventTime(event);
371 LOGI("Got motion event %d at %f, %f", type, move_x, move_y);
372
373 if (input_handler_->OnMotionEvent(motion_event, when, move_x, move_y) != 0) {
374 return false;
375 }
376 return true;
377 }
378
379 bool EventLoop::OnKeyEvent(AInputEvent* event) {
380 int32_t type = AKeyEvent_getAction(event);
381 KeyEvent key_event;
382 switch (type) {
383 case AKEY_EVENT_ACTION_DOWN:
384 key_event = kKeyDown;
385 break;
386 case AKEY_EVENT_ACTION_UP:
387 key_event = kKeyUp;
388 break;
389 case AKEY_EVENT_ACTION_MULTIPLE:
390 key_event = kKeyMultiple;
391 break;
392 default:
393 return false;
394 }
395 /* Get the key code of the key event.
396 * This is the physical key that was pressed, not the Unicode character. */
397 int32_t key_code = AKeyEvent_getKeyCode(event);
398 /* Get the meta key state. */
399 int32_t meta_state = AKeyEvent_getMetaState(event);
400 /* Get the repeat count of the event.
401 * For both key up an key down events, this is the number of times the key
402 * has repeated with the first down starting at 0 and counting up from
403 * there. For multiple key events, this is the number of down/up pairs
404 * that have occurred. */
405 int32_t repeat = AKeyEvent_getRepeatCount(event);
406
407 /* Get the time of the most recent key down event, in the
408 * java.lang.System.nanoTime() time base. If this is a down event,
409 * this will be the same as eventTime.
410 * Note that when chording keys, this value is the down time of the most
411 * recently pressed key, which may not be the same physical key of this
412 * event. */
413 // TODO(gram): Use or remove this.
414 // int64_t key_down_time = AKeyEvent_getDownTime(event);
415
416 /* Get the time this event occurred, in the
417 * java.lang.System.nanoTime() time base. */
418 int64_t when = AKeyEvent_getEventTime(event);
419 bool isAltKeyDown = (meta_state & AMETA_ALT_ON) != 0;
420 bool isShiftKeyDown = (meta_state & AMETA_SHIFT_ON) != 0;
421 bool isCtrlKeyDown = key_code < 32;
422
423 LOGI("Got key event %d %d", type, key_code);
424
425 if (input_handler_->OnKeyEvent(key_event, when, key_code,
426 isAltKeyDown, isCtrlKeyDown, isShiftKeyDown,
427 repeat) != 0) {
428 return false;
429 }
430 return true;
431 }
432
433 int32_t EventLoop::ProcessInputEvent(AInputEvent* event) {
434 int32_t event_type = AInputEvent_getType(event);
435 LOGI("Got input event type %d", event_type);
436 switch (event_type) {
437 case AINPUT_EVENT_TYPE_MOTION:
438 if (AInputEvent_getSource(event) == AINPUT_SOURCE_TOUCHSCREEN) {
439 return OnTouchEvent(event);
440 }
441 break;
442 case AINPUT_EVENT_TYPE_KEY:
443 return OnKeyEvent(event);
444 }
445 return 0;
446 }
447
448 void EventLoop::ActivityCallback(android_app* application, int32_t command) {
449 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData);
450 event_loop->ProcessActivityEvent(command);
451 }
452
453 int32_t EventLoop::InputCallback(android_app* application,
454 AInputEvent* event) {
455 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData);
456 return event_loop->ProcessInputEvent(event);
457 }
458
459 void EventLoop::SensorCallback(android_app* application,
460 android_poll_source* source) {
461 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData);
462 event_loop->ProcessSensorEvent();
463 }
464
OLDNEW
« no previous file with comments | « runtime/embedders/openglui/android/eventloop.h ('k') | runtime/embedders/openglui/android/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698