diff options
Diffstat (limited to 'native')
-rw-r--r-- | native/android/input.cpp | 62 | ||||
-rw-r--r-- | native/android/native_activity.cpp | 8 | ||||
-rw-r--r-- | native/glue/threaded_app/threaded_app.c | 61 | ||||
-rw-r--r-- | native/include/android/input.h | 5 | ||||
-rw-r--r-- | native/include/android/keycodes.h | 218 | ||||
-rw-r--r-- | native/include/android/native_activity.h | 42 | ||||
-rw-r--r-- | native/include/android_glue/threaded_app.h | 32 |
7 files changed, 269 insertions, 159 deletions
diff --git a/native/android/input.cpp b/native/android/input.cpp index 89d53e2..a4dde51 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -22,6 +22,8 @@ #include <ui/InputTransport.h> #include <utils/PollLoop.h> +#include <android_runtime/android_app_NativeActivity.h> + #include <poll.h> using android::InputEvent; @@ -187,65 +189,21 @@ float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_i void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, ALooper_callbackFunc* callback, void* data) { - queue->setPollLoop(static_cast<android::PollLoop*>(looper)); - ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(), - POLLIN, callback, data); + queue->attachLooper(looper, callback, data); } void AInputQueue_detachLooper(AInputQueue* queue) { - queue->getPollLoop()->removeCallback( - queue->getConsumer().getChannel()->getReceivePipeFd()); + queue->detachLooper(); } int AInputQueue_hasEvents(AInputQueue* queue) { - struct pollfd pfd; - - pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd(); - pfd.events = POLLIN; - pfd.revents = 0; - - int nfd = poll(&pfd, 1, 0); - if (nfd <= 0) return nfd; - return pfd.revents == POLLIN ? 1 : -1; + return queue->hasEvents(); } int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) { - *outEvent = NULL; - - int32_t res = queue->getConsumer().receiveDispatchSignal(); - if (res != android::OK) { - LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d", - queue->getConsumer().getChannel()->getName().string(), res); - return -1; - } - - InputEvent* myEvent = NULL; - res = queue->consume(&myEvent); - if (res != android::OK) { - LOGW("channel '%s' ~ Failed to consume input event. status=%d", - queue->getConsumer().getChannel()->getName().string(), res); - queue->getConsumer().sendFinishedSignal(); - return -1; - } - - *outEvent = myEvent; - return 0; -} - -void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, - int handled) { - if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY - && ((KeyEvent*)event)->hasDefaultAction()) { - // The app didn't handle this, but it may have a default action - // associated with it. We need to hand this back to Java to be - // executed. - queue->doDefaultKey((KeyEvent*)event); - return; - } - - int32_t res = queue->getConsumer().sendFinishedSignal(); - if (res != android::OK) { - LOGW("Failed to send finished signal on channel '%s'. status=%d", - queue->getConsumer().getChannel()->getName().string(), res); - } + return queue->getEvent(outEvent); +} + +void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) { + queue->finishEvent(event, handled != 0); } diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp index 509cc33..0c6823a 100644 --- a/native/android/native_activity.cpp +++ b/native/android/native_activity.cpp @@ -29,3 +29,11 @@ void ANativeActivity_setWindowFlags(ANativeActivity* activity, uint32_t addFlags, uint32_t removeFlags) { android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags); } + +void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags) { + android_NativeActivity_showSoftInput(activity, flags); +} + +void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags) { + android_NativeActivity_hideSoftInput(activity, flags); +} diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c index 2411e93..452c735 100644 --- a/native/glue/threaded_app/threaded_app.c +++ b/native/glue/threaded_app/threaded_app.c @@ -18,6 +18,7 @@ #include <jni.h> #include <errno.h> +#include <fcntl.h> #include <string.h> #include <unistd.h> #include <sys/resource.h> @@ -75,6 +76,19 @@ int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) { pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; + + case APP_CMD_WINDOW_REDRAW_NEEDED: + LOGI("APP_CMD_WINDOW_REDRAW_NEEDED\n"); + pthread_mutex_lock(&android_app->mutex); + android_app->redrawNeeded = 0; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_CONTENT_RECT_CHANGED: + LOGI("APP_CMD_CONTENT_RECT_CHANGED\n"); + android_app->contentRect = android_app->pendingContentRect; + break; case APP_CMD_DESTROY: LOGI("APP_CMD_DESTROY\n"); @@ -133,6 +147,12 @@ static struct android_app* android_app_create(ANativeActivity* activity) { } android_app->msgread = msgpipe[0]; android_app->msgwrite = msgpipe[1]; + int result = fcntl(android_app->msgread, F_SETFL, O_NONBLOCK); + if (result != 0) LOGW("Could not make message read pipe " + "non-blocking: %s", strerror(errno)); + result = fcntl(android_app->msgwrite, F_SETFL, O_NONBLOCK); + if (result != 0) LOGW("Could not make message write pipe " + "non-blocking: %s", strerror(errno)); pthread_attr_t attr; pthread_attr_init(&attr); @@ -184,6 +204,23 @@ static void android_app_set_activity_state(struct android_app* android_app, int8 pthread_mutex_unlock(&android_app->mutex); } +static void android_app_wait_redraw(struct android_app* android_app) { + pthread_mutex_lock(&android_app->mutex); + android_app->redrawNeeded = 1; + android_app_write_cmd(android_app, APP_CMD_WINDOW_REDRAW_NEEDED); + while (android_app->redrawNeeded) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); +} + +static void android_app_set_content_rect(struct android_app* android_app, const ARect* rect) { + pthread_mutex_lock(&android_app->mutex); + android_app->pendingContentRect = *rect; + android_app_write_cmd(android_app, APP_CMD_CONTENT_RECT_CHANGED); + pthread_mutex_unlock(&android_app->mutex); +} + static void android_app_free(struct android_app* android_app) { pthread_mutex_lock(&android_app->mutex); android_app_write_cmd(android_app, APP_CMD_DESTROY); @@ -231,6 +268,8 @@ static void onStop(ANativeActivity* activity) { static void onLowMemory(ANativeActivity* activity) { LOGI("LowMemory: %p\n", activity); + android_app_write_cmd((struct android_app*)activity->instance, + APP_CMD_LOW_MEMORY); } static void onWindowFocusChanged(ANativeActivity* activity, int focused) { @@ -244,6 +283,23 @@ static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* wind android_app_set_window((struct android_app*)activity->instance, window); } +static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) { + LOGI("NativeWindowResized: %p -- %p\n", activity, window); + android_app_write_cmd((struct android_app*)activity->instance, + APP_CMD_WINDOW_RESIZED); +} + +static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) { + LOGI("NativeWindowRedrawNeeded: %p -- %p\n", activity, window); + android_app_wait_redraw((struct android_app*)activity->instance); +} + +static void onContentRectChanged(ANativeActivity* activity, const ARect* rect) { + LOGI("ContentRectChanged: %p -- (%d,%d)-(%d,%d)\n", activity, rect->left, + rect->top, rect->right, rect->bottom); + android_app_set_content_rect((struct android_app*)activity->instance, rect); +} + static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window); android_app_set_window((struct android_app*)activity->instance, NULL); @@ -268,12 +324,15 @@ void ANativeActivity_onCreate(ANativeActivity* activity, activity->callbacks->onSaveInstanceState = onSaveInstanceState; activity->callbacks->onPause = onPause; activity->callbacks->onStop = onStop; - activity->callbacks->onLowMemory = onLowMemory; activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; + activity->callbacks->onNativeWindowResized = onNativeWindowResized; + activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded; activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; activity->callbacks->onInputQueueCreated = onInputQueueCreated; activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; + activity->callbacks->onContentRectChanged = onContentRectChanged; + activity->callbacks->onLowMemory = onLowMemory; activity->instance = android_app_create(activity); } diff --git a/native/include/android/input.h b/native/include/android/input.h index 014b6a3..25dd68e 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -68,7 +68,10 @@ enum { INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010, /* The input device is a directional pad. */ - INPUT_DEVICE_CLASS_DPAD = 0x00000020 + INPUT_DEVICE_CLASS_DPAD = 0x00000020, + + /* The input device is a gamepad (implies keyboard). */ + INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040 }; /* diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h index 36855c5..496eccc 100644 --- a/native/include/android/keycodes.h +++ b/native/include/android/keycodes.h @@ -41,114 +41,122 @@ extern "C" { /* * Key codes. - * - * XXX: The declarations in <ui/KeycodeLabel.h> should be updated to use these instead. - * We should probably move this into android/keycodes.h and add some new API for - * getting labels so that we can remove the other tables also in KeycodeLabel.h. */ enum { - KEYCODE_UNKNOWN = 0, - KEYCODE_SOFT_LEFT = 1, - KEYCODE_SOFT_RIGHT = 2, - KEYCODE_HOME = 3, - KEYCODE_BACK = 4, - KEYCODE_CALL = 5, - KEYCODE_ENDCALL = 6, - KEYCODE_0 = 7, - KEYCODE_1 = 8, - KEYCODE_2 = 9, - KEYCODE_3 = 10, - KEYCODE_4 = 11, - KEYCODE_5 = 12, - KEYCODE_6 = 13, - KEYCODE_7 = 14, - KEYCODE_8 = 15, - KEYCODE_9 = 16, - KEYCODE_STAR = 17, - KEYCODE_POUND = 18, - KEYCODE_DPAD_UP = 19, - KEYCODE_DPAD_DOWN = 20, - KEYCODE_DPAD_LEFT = 21, - KEYCODE_DPAD_RIGHT = 22, - KEYCODE_DPAD_CENTER = 23, - KEYCODE_VOLUME_UP = 24, - KEYCODE_VOLUME_DOWN = 25, - KEYCODE_POWER = 26, - KEYCODE_CAMERA = 27, - KEYCODE_CLEAR = 28, - KEYCODE_A = 29, - KEYCODE_B = 30, - KEYCODE_C = 31, - KEYCODE_D = 32, - KEYCODE_E = 33, - KEYCODE_F = 34, - KEYCODE_G = 35, - KEYCODE_H = 36, - KEYCODE_I = 37, - KEYCODE_J = 38, - KEYCODE_K = 39, - KEYCODE_L = 40, - KEYCODE_M = 41, - KEYCODE_N = 42, - KEYCODE_O = 43, - KEYCODE_P = 44, - KEYCODE_Q = 45, - KEYCODE_R = 46, - KEYCODE_S = 47, - KEYCODE_T = 48, - KEYCODE_U = 49, - KEYCODE_V = 50, - KEYCODE_W = 51, - KEYCODE_X = 52, - KEYCODE_Y = 53, - KEYCODE_Z = 54, - KEYCODE_COMMA = 55, - KEYCODE_PERIOD = 56, - KEYCODE_ALT_LEFT = 57, - KEYCODE_ALT_RIGHT = 58, - KEYCODE_SHIFT_LEFT = 59, - KEYCODE_SHIFT_RIGHT = 60, - KEYCODE_TAB = 61, - KEYCODE_SPACE = 62, - KEYCODE_SYM = 63, - KEYCODE_EXPLORER = 64, - KEYCODE_ENVELOPE = 65, - KEYCODE_ENTER = 66, - KEYCODE_DEL = 67, - KEYCODE_GRAVE = 68, - KEYCODE_MINUS = 69, - KEYCODE_EQUALS = 70, - KEYCODE_LEFT_BRACKET = 71, - KEYCODE_RIGHT_BRACKET = 72, - KEYCODE_BACKSLASH = 73, - KEYCODE_SEMICOLON = 74, - KEYCODE_APOSTROPHE = 75, - KEYCODE_SLASH = 76, - KEYCODE_AT = 77, - KEYCODE_NUM = 78, - KEYCODE_HEADSETHOOK = 79, - KEYCODE_FOCUS = 80, // *Camera* focus - KEYCODE_PLUS = 81, - KEYCODE_MENU = 82, - KEYCODE_NOTIFICATION = 83, - KEYCODE_SEARCH = 84, - KEYCODE_MEDIA_PLAY_PAUSE= 85, - KEYCODE_MEDIA_STOP = 86, - KEYCODE_MEDIA_NEXT = 87, - KEYCODE_MEDIA_PREVIOUS = 88, - KEYCODE_MEDIA_REWIND = 89, - KEYCODE_MEDIA_FAST_FORWARD = 90, - KEYCODE_MUTE = 91, - KEYCODE_PAGE_UP = 92, - KEYCODE_PAGE_DOWN = 93 + AKEYCODE_UNKNOWN = 0, + AKEYCODE_SOFT_LEFT = 1, + AKEYCODE_SOFT_RIGHT = 2, + AKEYCODE_HOME = 3, + AKEYCODE_BACK = 4, + AKEYCODE_CALL = 5, + AKEYCODE_ENDCALL = 6, + AKEYCODE_0 = 7, + AKEYCODE_1 = 8, + AKEYCODE_2 = 9, + AKEYCODE_3 = 10, + AKEYCODE_4 = 11, + AKEYCODE_5 = 12, + AKEYCODE_6 = 13, + AKEYCODE_7 = 14, + AKEYCODE_8 = 15, + AKEYCODE_9 = 16, + AKEYCODE_STAR = 17, + AKEYCODE_POUND = 18, + AKEYCODE_DPAD_UP = 19, + AKEYCODE_DPAD_DOWN = 20, + AKEYCODE_DPAD_LEFT = 21, + AKEYCODE_DPAD_RIGHT = 22, + AKEYCODE_DPAD_CENTER = 23, + AKEYCODE_VOLUME_UP = 24, + AKEYCODE_VOLUME_DOWN = 25, + AKEYCODE_POWER = 26, + AKEYCODE_CAMERA = 27, + AKEYCODE_CLEAR = 28, + AKEYCODE_A = 29, + AKEYCODE_B = 30, + AKEYCODE_C = 31, + AKEYCODE_D = 32, + AKEYCODE_E = 33, + AKEYCODE_F = 34, + AKEYCODE_G = 35, + AKEYCODE_H = 36, + AKEYCODE_I = 37, + AKEYCODE_J = 38, + AKEYCODE_K = 39, + AKEYCODE_L = 40, + AKEYCODE_M = 41, + AKEYCODE_N = 42, + AKEYCODE_O = 43, + AKEYCODE_P = 44, + AKEYCODE_Q = 45, + AKEYCODE_R = 46, + AKEYCODE_S = 47, + AKEYCODE_T = 48, + AKEYCODE_U = 49, + AKEYCODE_V = 50, + AKEYCODE_W = 51, + AKEYCODE_X = 52, + AKEYCODE_Y = 53, + AKEYCODE_Z = 54, + AKEYCODE_COMMA = 55, + AKEYCODE_PERIOD = 56, + AKEYCODE_ALT_LEFT = 57, + AKEYCODE_ALT_RIGHT = 58, + AKEYCODE_SHIFT_LEFT = 59, + AKEYCODE_SHIFT_RIGHT = 60, + AKEYCODE_TAB = 61, + AKEYCODE_SPACE = 62, + AKEYCODE_SYM = 63, + AKEYCODE_EXPLORER = 64, + AKEYCODE_ENVELOPE = 65, + AKEYCODE_ENTER = 66, + AKEYCODE_DEL = 67, + AKEYCODE_GRAVE = 68, + AKEYCODE_MINUS = 69, + AKEYCODE_EQUALS = 70, + AKEYCODE_LEFT_BRACKET = 71, + AKEYCODE_RIGHT_BRACKET = 72, + AKEYCODE_BACKSLASH = 73, + AKEYCODE_SEMICOLON = 74, + AKEYCODE_APOSTROPHE = 75, + AKEYCODE_SLASH = 76, + AKEYCODE_AT = 77, + AKEYCODE_NUM = 78, + AKEYCODE_HEADSETHOOK = 79, + AKEYCODE_FOCUS = 80, // *Camera* focus + AKEYCODE_PLUS = 81, + AKEYCODE_MENU = 82, + AKEYCODE_NOTIFICATION = 83, + AKEYCODE_SEARCH = 84, + AKEYCODE_MEDIA_PLAY_PAUSE= 85, + AKEYCODE_MEDIA_STOP = 86, + AKEYCODE_MEDIA_NEXT = 87, + AKEYCODE_MEDIA_PREVIOUS = 88, + AKEYCODE_MEDIA_REWIND = 89, + AKEYCODE_MEDIA_FAST_FORWARD = 90, + AKEYCODE_MUTE = 91, + AKEYCODE_PAGE_UP = 92, + AKEYCODE_PAGE_DOWN = 93, + AKEYCODE_PICTSYMBOLS = 94, + AKEYCODE_SWITCH_CHARSET = 95, + AKEYCODE_BUTTON_A = 96, + AKEYCODE_BUTTON_B = 97, + AKEYCODE_BUTTON_C = 98, + AKEYCODE_BUTTON_X = 99, + AKEYCODE_BUTTON_Y = 100, + AKEYCODE_BUTTON_Z = 101, + AKEYCODE_BUTTON_L1 = 102, + AKEYCODE_BUTTON_R1 = 103, + AKEYCODE_BUTTON_L2 = 104, + AKEYCODE_BUTTON_R2 = 105, + AKEYCODE_BUTTON_THUMBL = 106, + AKEYCODE_BUTTON_THUMBR = 107, + AKEYCODE_BUTTON_START = 108, + AKEYCODE_BUTTON_SELECT = 109, + AKEYCODE_BUTTON_MODE = 110, - /* NOTE: If you add a new keycode here you must also add it to: - * native/include/android/keycodes.h - * frameworks/base/include/ui/KeycodeLabels.h - * frameworks/base/core/java/android/view/KeyEvent.java - * tools/puppet_master/PuppetMaster.nav_keys.py - * frameworks/base/core/res/res/values/attrs.xml - */ + // NOTE: If you add a new keycode here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. }; #ifdef __cplusplus diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h index d0ff052..ea6f05f 100644 --- a/native/include/android/native_activity.h +++ b/native/include/android/native_activity.h @@ -147,6 +147,21 @@ typedef struct ANativeActivityCallbacks { void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window); /** + * The drawing window for this native activity has been resized. You should + * retrieve the new size from the window and ensure that your rendering in + * it now matches. + */ + void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window); + + /** + * The drawing window for this native activity needs to be redrawn. To avoid + * transient artifacts during screen changes (such resizing after rotation), + * applications should not return from this function until they have finished + * drawing their window in its current state. + */ + void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window); + + /** * The drawing window for this native activity is going to be destroyed. * You MUST ensure that you do not touch the window object after returning * from this function: in the common case of drawing to the window from @@ -170,6 +185,11 @@ typedef struct ANativeActivityCallbacks { void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue); /** + * The rectangle in the window in which content should be placed has changed. + */ + void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect); + + /** * The system is running low on memory. Use this callback to release * resources you do not need, to help the system avoid killing more * important processes. @@ -197,6 +217,28 @@ void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); void ANativeActivity_setWindowFlags(ANativeActivity* activity, uint32_t addFlags, uint32_t removeFlags); +/** + * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager + * API for documentation. + */ +enum { + ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001, + ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, +}; + +void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags); + +/** + * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager + * API for documentation. + */ +enum { + ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001, + ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, +}; + +void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags); + #ifdef __cplusplus }; #endif diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h index adfdbea..2b58e9c 100644 --- a/native/include/android_glue/threaded_app.h +++ b/native/include/android_glue/threaded_app.h @@ -48,6 +48,10 @@ struct android_app { // When non-NULL, this is the window surface that the app can draw in. ANativeWindow* window; + // Current content rectangle of the window; this is the area where the + // window's content should be placed to be seen by the user. + ARect contentRect; + // Current state of the app's activity. May be either APP_CMD_START, // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. int activityState; @@ -69,8 +73,10 @@ struct android_app { int running; int destroyed; + int redrawNeeded; AInputQueue* pendingInputQueue; ANativeWindow* pendingWindow; + ARect pendingContentRect; }; enum { @@ -105,6 +111,26 @@ enum { APP_CMD_WINDOW_CHANGED, /** + * Command from main thread: the current ANativeWindow has been resized. + * Please redraw with its new size. + */ + APP_CMD_WINDOW_RESIZED, + + /** + * Command from main thread: the system needs that the current ANativeWindow + * be redrawn. You should redraw the window before handing this to + * android_app_exec_cmd() in order to avoid transient drawing glitches. + */ + APP_CMD_WINDOW_REDRAW_NEEDED, + + /** + * Command from main thread: the content area of the window has changed, + * such as from the soft input window being shown or hidden. You can + * find the new content rect in android_app::contentRect. + */ + APP_CMD_CONTENT_RECT_CHANGED, + + /** * Command from main thread: the app's activity window has gained * input focus. */ @@ -117,6 +143,12 @@ enum { APP_CMD_LOST_FOCUS, /** + * Command from main thread: the system is running low on memory. + * Try to reduce your memory use. + */ + APP_CMD_LOW_MEMORY, + + /** * Command from main thread: the app's activity has been started. */ APP_CMD_START, |