| // | |
| // Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // AndroidWindow.cpp: Implementation of OSWindow for Android | |
| #include "android/AndroidWindow.h" | |
| #include <pthread.h> | |
| #include "android/third_party/android_native_app_glue.h" | |
| #include "common/debug.h" | |
| namespace | |
| { | |
| struct android_app *sApp = nullptr; | |
| pthread_mutex_t sInitWindowMutex; | |
| pthread_cond_t sInitWindowCond; | |
| bool sInitWindowDone = false; | |
| } // namespace | |
| AndroidWindow::AndroidWindow() | |
| { | |
| } | |
| AndroidWindow::~AndroidWindow() | |
| { | |
| } | |
| bool AndroidWindow::initialize(const std::string &name, size_t width, size_t height) | |
| { | |
| return resize(width, height); | |
| } | |
| void AndroidWindow::destroy() | |
| { | |
| } | |
| EGLNativeWindowType AndroidWindow::getNativeWindow() const | |
| { | |
| // Return the entire Activity Surface for now | |
| // sApp->window is valid only after sInitWindowDone, which is true after initialize() | |
| return sApp->window; | |
| } | |
| EGLNativeDisplayType AndroidWindow::getNativeDisplay() const | |
| { | |
| return EGL_DEFAULT_DISPLAY; | |
| } | |
| void AndroidWindow::messageLoop() | |
| { | |
| // TODO: accumulate events in the real message loop of android_main, | |
| // and process them here | |
| } | |
| void AndroidWindow::setMousePosition(int x, int y) | |
| { | |
| UNIMPLEMENTED(); | |
| } | |
| bool AndroidWindow::setPosition(int x, int y) | |
| { | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool AndroidWindow::resize(int width, int height) | |
| { | |
| mWidth = width; | |
| mHeight = height; | |
| // sApp->window used below is valid only after Activity Surface is created | |
| pthread_mutex_lock(&sInitWindowMutex); | |
| while (!sInitWindowDone) | |
| { | |
| pthread_cond_wait(&sInitWindowCond, &sInitWindowMutex); | |
| } | |
| pthread_mutex_unlock(&sInitWindowMutex); | |
| // TODO: figure out a way to set the format as well, | |
| // which is available only after EGLWindow initialization | |
| int32_t err = ANativeWindow_setBuffersGeometry(sApp->window, mWidth, mHeight, 0); | |
| return err == 0; | |
| } | |
| void AndroidWindow::setVisible(bool isVisible) | |
| { | |
| } | |
| void AndroidWindow::signalTestEvent() | |
| { | |
| UNIMPLEMENTED(); | |
| } | |
| OSWindow *CreateOSWindow() | |
| { | |
| // There should be only one live instance of AndroidWindow at a time, | |
| // as there is only one Activity Surface behind it. | |
| // Creating a new AndroidWindow each time works for ANGLETest, | |
| // as it destroys an old window before creating a new one. | |
| // TODO: use GLSurfaceView to support multiple windows | |
| return new AndroidWindow(); | |
| } | |
| static void onAppCmd(struct android_app *app, int32_t cmd) | |
| { | |
| switch (cmd) | |
| { | |
| case APP_CMD_INIT_WINDOW: | |
| pthread_mutex_lock(&sInitWindowMutex); | |
| sInitWindowDone = true; | |
| pthread_cond_broadcast(&sInitWindowCond); | |
| pthread_mutex_unlock(&sInitWindowMutex); | |
| break; | |
| // TODO: process other commands and pass them to AndroidWindow for handling | |
| // TODO: figure out how to handle APP_CMD_PAUSE, | |
| // which should immediately halt all the rendering, | |
| // since Activity Surface is no longer available. | |
| // Currently tests crash when paused, for example, due to device changing orientation | |
| } | |
| } | |
| static int32_t onInputEvent(struct android_app *app, AInputEvent *event) | |
| { | |
| // TODO: Handle input events | |
| return 0; // 0 == not handled | |
| } | |
| void android_main(struct android_app *app) | |
| { | |
| int events; | |
| struct android_poll_source *source; | |
| sApp = app; | |
| pthread_mutex_init(&sInitWindowMutex, nullptr); | |
| pthread_cond_init(&sInitWindowCond, nullptr); | |
| // Event handlers, invoked from source->process() | |
| app->onAppCmd = onAppCmd; | |
| app->onInputEvent = onInputEvent; | |
| // Message loop, polling for events indefinitely (due to -1 timeout) | |
| // Must be here in order to handle APP_CMD_INIT_WINDOW event, | |
| // which occurs after AndroidWindow::initialize(), but before AndroidWindow::messageLoop | |
| while (ALooper_pollAll(-1, nullptr, &events, reinterpret_cast<void **>(&source)) >= 0) | |
| { | |
| if (source != nullptr) | |
| { | |
| source->process(app, source); | |
| } | |
| } | |
| } |