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

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

Issue 12340036: Android improvements: (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 10 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
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "embedders/openglui/android/eventloop.h" 5 #include "embedders/openglui/android/eventloop.h"
6 6
7 #include "embedders/openglui/common/log.h" 7 #include "embedders/openglui/common/log.h"
8 8
9 /*
10 * The Android lifecycle events are:
11 *
12 * OnCreate: In NDK this is the call to android_main
13 *
14 * OnStart: technically, called to initiate the “visible” lifespan of the
15 * app; at any time between OnStart and OnStop, the app may be visible.
16 * We can either be OnResume’d or OnStop’ped from this state. Note that
17 * there is also an event for OnRestart, which is called before OnStart
18 * if the application is transitioning from OnStop to OnStart instead of
19 * being started from scratch.
20 *
21 * OnResume: technically, the start of the “foreground” lifespan of the app,
22 * but this does not mean that the app is fully visible and should be
23 * rendering – more on that later
24 *
25 * OnPause: the app is losing its foregrounded state; this is normally an
26 * indication that something is fully covering the app. On versions of
27 * Android before Honeycomb, once we returned from this callback, we
28 * could be killed at any time with no further app code called. We can
29 * either be OnResume’d or OnStop’ped from this state. OnPause halts the
30 * visible UI thread and so should be handled as quickly as possible.
31 *
32 * OnStop: the end of the current visible lifespan of the app – we may
33 * transition to On(Re)Start to become visible again, or to OnDestroy if
34 * we are shutting down entirely. Once we return from this callback, we
35 * can be killed at any time with no further app code called on any
36 * version of Android.
37 *
38 * OnDestroy: this can only be followed by the application being killed or
39 * restarted with OnCreate.
40 *
41 * The above events occur in fixed orders. The events below can occur at
42 * various times:
43 *
44 * OnGainedFocus: happens between OnResume and OnPause.
45 * OnLostFocus: may occur at arbitrary times, and may in fact not happen
46 * at all if the app is being destroyed. So OnPause and OnGainedFocus/
47 * OnLostFocus must be used together to determine the visible and
48 * interactable state of the app.
49 *
50 * OnCreateWindow: usually happens in the resumed state
51 * OnDestroyWindow: can happen after OnPause or OnDestroy, so apps may
52 * need to handle shutting down EGL before their surfaces are
53 * destroyed.
54 * OnConfigurationChanged: typically means the size has changed
55 *
56 * An application's EGL surface may only exist between the OnCreateWindow
57 * and OnDestroyWindow callbacks.
58 *
59 * An application is "killable" after OnStop or OnDestroy (in earlier
60 * Android versions, after OnPause too). That means any critical state
61 * or resources must be handled by any of these callbacks.
62 *
63 * These callbacks run on the main thread. If they block any event
64 * processing for more than 5 seconds this will result in an ANR
65 * (Application Not Responding message).
66 *
67 * On application launch, this sequence will occur:
68 *
69 * - OnCreate
70 * - OnStart
71 * - OnResume
72 * - OnCreateWindow
73 * - OnConfigurationChanged
74 * - OnGainedFocus
75 *
76 * If the back button is pressed, and the app does not handle it,
77 * Android will pop the app of the UI stack and destroy the application's
78 * activity:
79 *
80 * - OnPause
81 * - OnLostFocus
82 * - OnDestroyWindow
83 * - OnStop
84 * - OnDestroy
85 *
86 * If the home button is pressed, the app is sent down in the UI stack.
87 * The app's Activity still exists but may be killed at any time, and
88 * it loses its rendering surface:
89 *
90 * - OnPause
91 * - OnLostFocus
92 * - OnDestroyWindow
93 * - OnStop
94 *
95 * If the app is then restarted (without having been killed in between):
96 *
97 * - OnRestart
98 * - OnStart
99 * - OnResume
100 * - OnCreateWindow
101 * - OnConfigurationChanged
102 * - OnGainedFocus
103 *
104 * If a status icon pop up is opened, the app is still visible and can render
105 * but is not focused and cannot receive input:
106 *
107 * - OnLostFocus
108 *
109 * When the popup is dismissed, the app regains focus:
110 *
111 * - OnGainedFocus
112 *
113 * When the device is suspended (power button or screen saver), the application
114 * will typically be paused and lose focus:
115 *
116 * - OnPause
117 * - OnLostFocus (sometimes this will only come when the device is resumed
118 * to the lock screen)
119 *
120 * The application should have stopped all rendering and sound and any
121 * non-critical background processing.
122 *
123 * When the device is resumed but not yet unlocked, the app will be resumed:
124 *
125 * - OnResume
126 *
127 * The application should not perform sound or graphics yet. If the lock
128 * screen times out, the app will be paused again. If the screen is
129 * unlocked, the app will regain focus.
130 *
131 * Turning all of this into a general framework, we can use the following:
132 *
133 * 1. In OnCreate/android_main, set up the main classes and possibly
134 * load some lightweight resources.
135 * 2. In OnCreateWindow, create the EGLSurface, bind the context, load
136 * OpenGL resources. No rendering.
137 * 3. When we are between OnResume and OnPause, and between OnCreateWindow
138 * and OnDestroyWindow, and between OnGainedFocus and OnLostFocus,
139 * we can render and process input.
140 * 4. In OnLostFocus, stop sounds from playing, and stop rendering.
141 * 5. In OnPause, stop all rendering
142 * 6. In OnResume, prepare to start rendering again, but don't render.
143 * 7. In OnGainedFocus after OnResume, start rendering and sound again.
144 * 8. In OnStop, free all graphic resources, either through GLES calls
145 * if the EGLContext is still bound, or via eglDestroyContext if the
146 * context has been unbound because the rendering surface was destroyed.
147 * 9. In OnDestroy, release all other resources.
148 */
9 EventLoop::EventLoop(android_app* application) 149 EventLoop::EventLoop(android_app* application)
10 : enabled_(false), 150 : enabled_(false),
11 quit_(false), 151 quit_(false),
152 isResumed_(false),
153 hasSurface_(false),
154 hasFocus_(false),
12 application_(application), 155 application_(application),
13 lifecycle_handler_(NULL), 156 lifecycle_handler_(NULL),
14 input_handler_(NULL) { 157 input_handler_(NULL) {
15 application_->onAppCmd = ActivityCallback; 158 application_->onAppCmd = ActivityCallback;
16 application_->onInputEvent = InputCallback; 159 application_->onInputEvent = InputCallback;
17 application_->userData = this; 160 application_->userData = this;
18 } 161 }
19 162
20 void EventLoop::Run(LifeCycleHandler* lifecycle_handler, 163 void EventLoop::Run(LifeCycleHandler* lifecycle_handler,
21 InputHandler* input_handler) { 164 InputHandler* input_handler) {
22 int32_t result; 165 int32_t result;
23 int32_t events; 166 int32_t events;
24 android_poll_source* source; 167 android_poll_source* source;
25 168
26 lifecycle_handler_ = lifecycle_handler; 169 lifecycle_handler_ = lifecycle_handler;
27 input_handler_ = input_handler; 170 input_handler_ = input_handler;
28 LOGI("Starting event loop"); 171 if (lifecycle_handler_->OnStart() == 0) {
29 while (true) { 172 LOGI("Starting event loop");
30 // If not enabled, block indefinitely on events. If enabled, block 173 while (!quit_) {
31 // briefly so we can do useful work in onStep. Ultimately this is 174 // If not enabled, block indefinitely on events. If enabled, block
32 // where we would want to look at elapsed time since the last call 175 // briefly so we can do useful work in onStep. Ultimately this is
33 // to onStep completed and use a delay that gives us ~60fps. 176 // where we would want to look at elapsed time since the last call
34 while ((result = ALooper_pollAll(enabled_ ? (1000/60) : -1, 177 // to onStep completed and use a delay that gives us ~60fps.
35 NULL, 178 while ((result = ALooper_pollAll(enabled_ ? (1000/60) : -1, NULL,
36 &events, 179 &events, reinterpret_cast<void**>(&source))) >= 0) {
37 reinterpret_cast<void**>(&source))) >= 0) { 180 if (source != NULL) {
38 if (source != NULL) { 181 source->process(application_, source);
39 source->process(application_, source); 182 }
183 if (application_->destroyRequested) {
184 return;
185 }
40 } 186 }
41 if (application_->destroyRequested) { 187 if (enabled_ && !quit_) {
42 return; 188 LOGI("step");
43 } 189 if (lifecycle_handler_->OnStep() != 0) {
44 } 190 quit_ = true;
45 if (enabled_ && !quit_) { 191 }
46 LOGI("step");
47 if (lifecycle_handler_->OnStep() != 0) {
48 quit_ = true;
49 ANativeActivity_finish(application_->activity);
50 } 192 }
51 } 193 }
52 } 194 }
53 } 195 ANativeActivity_finish(application_->activity);
54
55 // Called when we gain focus.
56 void EventLoop::Activate() {
57 LOGI("activate");
58 if (!enabled_ && application_->window != NULL) {
59 quit_ = false;
60 enabled_ = true;
61 if (lifecycle_handler_->OnActivate() != 0) {
62 quit_ = true;
63 ANativeActivity_finish(application_->activity);
64 }
65 }
66 }
67
68 // Called when we lose focus.
69 void EventLoop::Deactivate() {
70 LOGI("deactivate");
71 if (enabled_) {
72 lifecycle_handler_->OnDeactivate();
73 enabled_ = false;
74 }
75 } 196 }
76 197
77 void EventLoop::ProcessActivityEvent(int32_t command) { 198 void EventLoop::ProcessActivityEvent(int32_t command) {
78 switch (command) { 199 switch (command) {
200 case APP_CMD_INIT_WINDOW:
201 if (lifecycle_handler_->Activate() != 0) {
202 quit_ = true;
203 } else {
204 hasSurface_ = true;
205 }
206 break;
79 case APP_CMD_CONFIG_CHANGED: 207 case APP_CMD_CONFIG_CHANGED:
80 lifecycle_handler_->OnConfigurationChanged(); 208 lifecycle_handler_->OnConfigurationChanged();
81 break; 209 break;
82 case APP_CMD_INIT_WINDOW:
83 lifecycle_handler_->OnCreateWindow();
84 break;
85 case APP_CMD_DESTROY: 210 case APP_CMD_DESTROY:
86 lifecycle_handler_->OnDestroy(); 211 hasFocus_ = false;
212 lifecycle_handler_->FreeAllResources();
87 break; 213 break;
88 case APP_CMD_GAINED_FOCUS: 214 case APP_CMD_GAINED_FOCUS:
89 Activate(); 215 hasFocus_ = true;
90 lifecycle_handler_->OnGainedFocus(); 216 if (hasSurface_ && isResumed_ && hasFocus_) {
217 enabled_ = (lifecycle_handler_->Resume() == 0);
218 }
91 break; 219 break;
92 case APP_CMD_LOST_FOCUS: 220 case APP_CMD_LOST_FOCUS:
93 lifecycle_handler_->OnLostFocus(); 221 hasFocus_ = false;
94 Deactivate(); 222 enabled_ = false;
223 lifecycle_handler_->Pause();
95 break; 224 break;
96 case APP_CMD_LOW_MEMORY: 225 case APP_CMD_LOW_MEMORY:
97 lifecycle_handler_->OnLowMemory(); 226 lifecycle_handler_->OnLowMemory();
98 break; 227 break;
99 case APP_CMD_PAUSE: 228 case APP_CMD_PAUSE:
100 lifecycle_handler_->OnPause(); 229 isResumed_ = false;
101 Deactivate(); 230 enabled_ = false;
231 lifecycle_handler_->Pause();
102 break; 232 break;
103 case APP_CMD_RESUME: 233 case APP_CMD_RESUME:
104 lifecycle_handler_->OnResume(); 234 isResumed_ = true;
105 break; 235 break;
106 case APP_CMD_SAVE_STATE: 236 case APP_CMD_SAVE_STATE:
107 lifecycle_handler_->OnSaveState(&application_->savedState, 237 lifecycle_handler_->OnSaveState(&application_->savedState,
108 &application_->savedStateSize); 238 &application_->savedStateSize);
109 break; 239 break;
110 case APP_CMD_START: 240 case APP_CMD_START:
111 lifecycle_handler_->OnStart();
112 break; 241 break;
113 case APP_CMD_STOP: 242 case APP_CMD_STOP:
114 lifecycle_handler_->OnStop(); 243 hasFocus_ = false;
244 lifecycle_handler_->Deactivate();
115 break; 245 break;
116 case APP_CMD_TERM_WINDOW: 246 case APP_CMD_TERM_WINDOW:
117 lifecycle_handler_->OnDestroyWindow(); 247 hasFocus_ = false;
118 Deactivate(); 248 hasSurface_ = false;
249 enabled_ = false;
250 lifecycle_handler_->Pause();
119 break; 251 break;
120 default: 252 default:
121 break; 253 break;
122 } 254 }
123 } 255 }
124 256
125 bool EventLoop::OnTouchEvent(AInputEvent* event) { 257 bool EventLoop::OnTouchEvent(AInputEvent* event) {
126 int32_t type = AMotionEvent_getAction(event); 258 int32_t type = AMotionEvent_getAction(event);
127 MotionEvent motion_event; 259 MotionEvent motion_event;
128 switch (type) { 260 switch (type) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData); 363 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData);
232 event_loop->ProcessActivityEvent(command); 364 event_loop->ProcessActivityEvent(command);
233 } 365 }
234 366
235 int32_t EventLoop::InputCallback(android_app* application, 367 int32_t EventLoop::InputCallback(android_app* application,
236 AInputEvent* event) { 368 AInputEvent* event) {
237 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData); 369 EventLoop* event_loop = reinterpret_cast<EventLoop*>(application->userData);
238 return event_loop->ProcessInputEvent(event); 370 return event_loop->ProcessInputEvent(event);
239 } 371 }
240 372
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