/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Window_android.h" #include "VulkanTestContext_android.h" Window* Window::CreateNativeWindow(void* platformData) { Window_android* window = new Window_android(); if (!window->init((android_app*)platformData)) { delete window; return nullptr; } return window; } static void handle_cmd(struct android_app* app, int32_t cmd); static int32_t handle_input(struct android_app* app, AInputEvent* event); bool Window_android::init(android_app* app) { SkASSERT(app); mApp = app; mApp->userData = this; mApp->onAppCmd = handle_cmd; mApp->onInputEvent = handle_input; return true; } void Window_android::setTitle(const char* title) { //todo SkDebugf("Title: %s", title); } bool Window_android::attach(BackEndType attachType, int msaaSampleCount, AttachmentInfo*) { if (kVulkan_BackendType != attachType) { return false; } mSampleCount = msaaSampleCount; // We delay the creation of fTestContext until Android informs us that // the native window is ready to use. return true; } void Window_android::initDisplay(ANativeWindow* window) { SkASSERT(window); ContextPlatformData_android platformData; platformData.fNativeWindow = window; fTestContext = VulkanTestContext::Create((void*)&platformData, mSampleCount); } static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { SkDebugf("Failure writing android_app cmd: %s\n", strerror(errno)); } } void Window_android::inval() { android_app_write_cmd(mApp, APP_CMD_INVAL_WINDOW); } void Window_android::paintIfNeeded() { if (mApp->window || !mContentRect.isEmpty()) { this->onPaint(); } } /** * Process the next main command. */ static void handle_cmd(struct android_app* app, int32_t cmd) { Window_android* window = (Window_android*)app->userData; switch (cmd) { case APP_CMD_INIT_WINDOW: // The window is being shown, get it ready. SkASSERT(app->window); window->initDisplay(app->window); window->paintIfNeeded(); break; case APP_CMD_WINDOW_RESIZED: { int width = ANativeWindow_getWidth(app->window); int height = ANativeWindow_getHeight(app->window); window->onResize(width, height); break; } case APP_CMD_CONTENT_RECT_CHANGED: window->setContentRect(app->contentRect.left, app->contentRect.top, app->contentRect.right, app->contentRect.bottom); window->paintIfNeeded(); break; case APP_CMD_TERM_WINDOW: // The window is being hidden or closed, clean it up. window->detach(); break; case APP_CMD_INVAL_WINDOW: window->paintIfNeeded(); break; } } static Window::Key get_key(int32_t keycode) { static const struct { int32_t fAndroidKey; Window::Key fWindowKey; } gPair[] = { { AKEYCODE_BACK, Window::kBack_Key }, { AKEYCODE_VOLUME_UP, Window::kLeft_Key }, { AKEYCODE_VOLUME_DOWN, Window::kRight_Key } }; for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { if (gPair[i].fAndroidKey == keycode) { return gPair[i].fWindowKey; } } return Window::kNONE_Key; } static Window::InputState get_action(int32_t action) { static const struct { int32_t fAndroidAction; Window::InputState fInputState; } gPair[] = { { AKEY_STATE_DOWN, Window::kDown_InputState }, { AKEY_STATE_UP, Window::kUp_InputState }, }; for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { if (gPair[i].fAndroidAction == action) { return gPair[i].fInputState; } } return Window::kMove_InputState; } static int32_t get_key_modifiers(AInputEvent* event) { static const struct { int32_t fAndroidState; int32_t fWindowModifier; } gPair[] = { { AMETA_SHIFT_ON, Window::kShift_ModifierKey }, { AMETA_CTRL_ON, Window::kControl_ModifierKey }, }; int32_t metaState = AKeyEvent_getMetaState(event); int32_t modifiers = 0; if (AKeyEvent_getRepeatCount(event) == 0) { modifiers |= Window::kFirstPress_ModifierKey; } for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { if (gPair[i].fAndroidState == metaState) { modifiers |= gPair[i].fWindowModifier; } } return modifiers; } /** * Process the next input event. */ static int32_t handle_input(struct android_app* app, AInputEvent* event) { Window_android* window = (Window_android*)app->userData; switch(AInputEvent_getType(event)) { case AINPUT_EVENT_TYPE_MOTION: break; case AINPUT_EVENT_TYPE_KEY: Window::Key key = get_key(AKeyEvent_getKeyCode(event)); Window::InputState state = get_action(AKeyEvent_getAction(event)); int32_t mod = get_key_modifiers(event); window->onKey(key, state, mod); return true; // eat all key events } return 0; }