| OLD | NEW |
| 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 Loading... |
| 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 |
| OLD | NEW |