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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: runtime/embedders/openglui/android/eventloop.cc
===================================================================
--- runtime/embedders/openglui/android/eventloop.cc (revision 18917)
+++ runtime/embedders/openglui/android/eventloop.cc (working copy)
@@ -6,9 +6,152 @@
#include "embedders/openglui/common/log.h"
+/*
+ * The Android lifecycle events are:
+ *
+ * OnCreate: In NDK this is the call to android_main
+ *
+ * OnStart: technically, called to initiate the “visible” lifespan of the
+ * app; at any time between OnStart and OnStop, the app may be visible.
+ * We can either be OnResume’d or OnStop’ped from this state. Note that
+ * there is also an event for OnRestart, which is called before OnStart
+ * if the application is transitioning from OnStop to OnStart instead of
+ * being started from scratch.
+ *
+ * OnResume: technically, the start of the “foreground” lifespan of the app,
+ * but this does not mean that the app is fully visible and should be
+ * rendering – more on that later
+ *
+ * OnPause: the app is losing its foregrounded state; this is normally an
+ * indication that something is fully covering the app. On versions of
+ * Android before Honeycomb, once we returned from this callback, we
+ * could be killed at any time with no further app code called. We can
+ * either be OnResume’d or OnStop’ped from this state. OnPause halts the
+ * visible UI thread and so should be handled as quickly as possible.
+ *
+ * OnStop: the end of the current visible lifespan of the app – we may
+ * transition to On(Re)Start to become visible again, or to OnDestroy if
+ * we are shutting down entirely. Once we return from this callback, we
+ * can be killed at any time with no further app code called on any
+ * version of Android.
+ *
+ * OnDestroy: this can only be followed by the application being killed or
+ * restarted with OnCreate.
+ *
+ * The above events occur in fixed orders. The events below can occur at
+ * various times:
+ *
+ * OnGainedFocus: happens between OnResume and OnPause.
+ * OnLostFocus: may occur at arbitrary times, and may in fact not happen
+ * at all if the app is being destroyed. So OnPause and OnGainedFocus/
+ * OnLostFocus must be used together to determine the visible and
+ * interactable state of the app.
+ *
+ * OnCreateWindow: usually happens in the resumed state
+ * OnDestroyWindow: can happen after OnPause or OnDestroy, so apps may
+ * need to handle shutting down EGL before their surfaces are
+ * destroyed.
+ * OnConfigurationChanged: typically means the size has changed
+ *
+ * An application's EGL surface may only exist between the OnCreateWindow
+ * and OnDestroyWindow callbacks.
+ *
+ * An application is "killable" after OnStop or OnDestroy (in earlier
+ * Android versions, after OnPause too). That means any critical state
+ * or resources must be handled by any of these callbacks.
+ *
+ * These callbacks run on the main thread. If they block any event
+ * processing for more than 5 seconds this will result in an ANR
+ * (Application Not Responding message).
+ *
+ * On application launch, this sequence will occur:
+ *
+ * - OnCreate
+ * - OnStart
+ * - OnResume
+ * - OnCreateWindow
+ * - OnConfigurationChanged
+ * - OnGainedFocus
+ *
+ * If the back button is pressed, and the app does not handle it,
+ * Android will pop the app of the UI stack and destroy the application's
+ * activity:
+ *
+ * - OnPause
+ * - OnLostFocus
+ * - OnDestroyWindow
+ * - OnStop
+ * - OnDestroy
+ *
+ * If the home button is pressed, the app is sent down in the UI stack.
+ * The app's Activity still exists but may be killed at any time, and
+ * it loses its rendering surface:
+ *
+ * - OnPause
+ * - OnLostFocus
+ * - OnDestroyWindow
+ * - OnStop
+ *
+ * If the app is then restarted (without having been killed in between):
+ *
+ * - OnRestart
+ * - OnStart
+ * - OnResume
+ * - OnCreateWindow
+ * - OnConfigurationChanged
+ * - OnGainedFocus
+ *
+ * If a status icon pop up is opened, the app is still visible and can render
+ * but is not focused and cannot receive input:
+ *
+ * - OnLostFocus
+ *
+ * When the popup is dismissed, the app regains focus:
+ *
+ * - OnGainedFocus
+ *
+ * When the device is suspended (power button or screen saver), the application
+ * will typically be paused and lose focus:
+ *
+ * - OnPause
+ * - OnLostFocus (sometimes this will only come when the device is resumed
+ * to the lock screen)
+ *
+ * The application should have stopped all rendering and sound and any
+ * non-critical background processing.
+ *
+ * When the device is resumed but not yet unlocked, the app will be resumed:
+ *
+ * - OnResume
+ *
+ * The application should not perform sound or graphics yet. If the lock
+ * screen times out, the app will be paused again. If the screen is
+ * unlocked, the app will regain focus.
+ *
+ * Turning all of this into a general framework, we can use the following:
+ *
+ * 1. In OnCreate/android_main, set up the main classes and possibly
+ * load some lightweight resources.
+ * 2. In OnCreateWindow, create the EGLSurface, bind the context, load
+ * OpenGL resources. No rendering.
+ * 3. When we are between OnResume and OnPause, and between OnCreateWindow
+ * and OnDestroyWindow, and between OnGainedFocus and OnLostFocus,
+ * we can render and process input.
+ * 4. In OnLostFocus, stop sounds from playing, and stop rendering.
+ * 5. In OnPause, stop all rendering
+ * 6. In OnResume, prepare to start rendering again, but don't render.
+ * 7. In OnGainedFocus after OnResume, start rendering and sound again.
+ * 8. In OnStop, free all graphic resources, either through GLES calls
+ * if the EGLContext is still bound, or via eglDestroyContext if the
+ * context has been unbound because the rendering surface was destroyed.
+ * 9. In OnDestroy, release all other resources.
+ */
EventLoop::EventLoop(android_app* application)
: enabled_(false),
quit_(false),
+ isResumed_(false),
+ hasSurface_(false),
+ hasFocus_(false),
application_(application),
lifecycle_handler_(NULL),
input_handler_(NULL) {
@@ -25,97 +168,86 @@
lifecycle_handler_ = lifecycle_handler;
input_handler_ = input_handler;
- LOGI("Starting event loop");
- while (true) {
- // If not enabled, block indefinitely on events. If enabled, block
- // briefly so we can do useful work in onStep. Ultimately this is
- // where we would want to look at elapsed time since the last call
- // to onStep completed and use a delay that gives us ~60fps.
- while ((result = ALooper_pollAll(enabled_ ? (1000/60) : -1,
- NULL,
- &events,
- reinterpret_cast<void**>(&source))) >= 0) {
- if (source != NULL) {
- source->process(application_, source);
+ if (lifecycle_handler_->OnStart() == 0) {
+ LOGI("Starting event loop");
+ while (!quit_) {
+ // If not enabled, block indefinitely on events. If enabled, block
+ // briefly so we can do useful work in onStep. Ultimately this is
+ // where we would want to look at elapsed time since the last call
+ // to onStep completed and use a delay that gives us ~60fps.
+ while ((result = ALooper_pollAll(enabled_ ? (1000/60) : -1, NULL,
+ &events, reinterpret_cast<void**>(&source))) >= 0) {
+ if (source != NULL) {
+ source->process(application_, source);
+ }
+ if (application_->destroyRequested) {
+ return;
+ }
}
- if (application_->destroyRequested) {
- return;
+ if (enabled_ && !quit_) {
+ LOGI("step");
+ if (lifecycle_handler_->OnStep() != 0) {
+ quit_ = true;
+ }
}
}
- if (enabled_ && !quit_) {
- LOGI("step");
- if (lifecycle_handler_->OnStep() != 0) {
- quit_ = true;
- ANativeActivity_finish(application_->activity);
- }
- }
}
+ ANativeActivity_finish(application_->activity);
}
-// Called when we gain focus.
-void EventLoop::Activate() {
- LOGI("activate");
- if (!enabled_ && application_->window != NULL) {
- quit_ = false;
- enabled_ = true;
- if (lifecycle_handler_->OnActivate() != 0) {
- quit_ = true;
- ANativeActivity_finish(application_->activity);
- }
- }
-}
-
-// Called when we lose focus.
-void EventLoop::Deactivate() {
- LOGI("deactivate");
- if (enabled_) {
- lifecycle_handler_->OnDeactivate();
- enabled_ = false;
- }
-}
-
void EventLoop::ProcessActivityEvent(int32_t command) {
switch (command) {
+ case APP_CMD_INIT_WINDOW:
+ if (lifecycle_handler_->Activate() != 0) {
+ quit_ = true;
+ } else {
+ hasSurface_ = true;
+ }
+ break;
case APP_CMD_CONFIG_CHANGED:
lifecycle_handler_->OnConfigurationChanged();
break;
- case APP_CMD_INIT_WINDOW:
- lifecycle_handler_->OnCreateWindow();
- break;
case APP_CMD_DESTROY:
- lifecycle_handler_->OnDestroy();
+ hasFocus_ = false;
+ lifecycle_handler_->FreeAllResources();
break;
case APP_CMD_GAINED_FOCUS:
- Activate();
- lifecycle_handler_->OnGainedFocus();
+ hasFocus_ = true;
+ if (hasSurface_ && isResumed_ && hasFocus_) {
+ enabled_ = (lifecycle_handler_->Resume() == 0);
+ }
break;
case APP_CMD_LOST_FOCUS:
- lifecycle_handler_->OnLostFocus();
- Deactivate();
+ hasFocus_ = false;
+ enabled_ = false;
+ lifecycle_handler_->Pause();
break;
case APP_CMD_LOW_MEMORY:
lifecycle_handler_->OnLowMemory();
break;
case APP_CMD_PAUSE:
- lifecycle_handler_->OnPause();
- Deactivate();
+ isResumed_ = false;
+ enabled_ = false;
+ lifecycle_handler_->Pause();
break;
case APP_CMD_RESUME:
- lifecycle_handler_->OnResume();
+ isResumed_ = true;
break;
case APP_CMD_SAVE_STATE:
lifecycle_handler_->OnSaveState(&application_->savedState,
&application_->savedStateSize);
break;
case APP_CMD_START:
- lifecycle_handler_->OnStart();
break;
case APP_CMD_STOP:
- lifecycle_handler_->OnStop();
+ hasFocus_ = false;
+ lifecycle_handler_->Deactivate();
break;
case APP_CMD_TERM_WINDOW:
- lifecycle_handler_->OnDestroyWindow();
- Deactivate();
+ hasFocus_ = false;
+ hasSurface_ = false;
+ enabled_ = false;
+ lifecycle_handler_->Pause();
break;
default:
break;

Powered by Google App Engine
This is Rietveld 408576698