1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // AndroidWindow.cpp: Implementation of OSWindow for Android
8
9 #include "util/android/AndroidWindow.h"
10
11 #include <pthread.h>
12
13 #include "common/debug.h"
14 #include "util/android/third_party/android_native_app_glue.h"
15
16 namespace
17 {
18 struct android_app *sApp = nullptr;
19 pthread_mutex_t sInitWindowMutex;
20 pthread_cond_t sInitWindowCond;
21 bool sInitWindowDone = false;
22 } // namespace
23
AndroidWindow()24 AndroidWindow::AndroidWindow() {}
25
~AndroidWindow()26 AndroidWindow::~AndroidWindow() {}
27
initialize(const std::string & name,int width,int height)28 bool AndroidWindow::initialize(const std::string &name, int width, int height)
29 {
30 return resize(width, height);
31 }
destroy()32 void AndroidWindow::destroy() {}
33
resetNativeWindow()34 void AndroidWindow::resetNativeWindow() {}
35
getNativeWindow() const36 EGLNativeWindowType AndroidWindow::getNativeWindow() const
37 {
38 // Return the entire Activity Surface for now
39 // sApp->window is valid only after sInitWindowDone, which is true after initialize()
40 return sApp->window;
41 }
42
getNativeDisplay() const43 EGLNativeDisplayType AndroidWindow::getNativeDisplay() const
44 {
45 return EGL_DEFAULT_DISPLAY;
46 }
47
messageLoop()48 void AndroidWindow::messageLoop()
49 {
50 // TODO: accumulate events in the real message loop of android_main,
51 // and process them here
52 }
53
setMousePosition(int x,int y)54 void AndroidWindow::setMousePosition(int x, int y)
55 {
56 UNIMPLEMENTED();
57 }
58
setPosition(int x,int y)59 bool AndroidWindow::setPosition(int x, int y)
60 {
61 UNIMPLEMENTED();
62 return false;
63 }
64
resize(int width,int height)65 bool AndroidWindow::resize(int width, int height)
66 {
67 mWidth = width;
68 mHeight = height;
69
70 // sApp->window used below is valid only after Activity Surface is created
71 pthread_mutex_lock(&sInitWindowMutex);
72 while (!sInitWindowDone)
73 {
74 pthread_cond_wait(&sInitWindowCond, &sInitWindowMutex);
75 }
76 pthread_mutex_unlock(&sInitWindowMutex);
77
78 // TODO: figure out a way to set the format as well,
79 // which is available only after EGLWindow initialization
80 int32_t err = ANativeWindow_setBuffersGeometry(sApp->window, mWidth, mHeight, 0);
81 return err == 0;
82 }
83
setVisible(bool isVisible)84 void AndroidWindow::setVisible(bool isVisible) {}
85
signalTestEvent()86 void AndroidWindow::signalTestEvent()
87 {
88 UNIMPLEMENTED();
89 }
90
onAppCmd(struct android_app * app,int32_t cmd)91 static void onAppCmd(struct android_app *app, int32_t cmd)
92 {
93 switch (cmd)
94 {
95 case APP_CMD_INIT_WINDOW:
96 pthread_mutex_lock(&sInitWindowMutex);
97 sInitWindowDone = true;
98 pthread_cond_broadcast(&sInitWindowCond);
99 pthread_mutex_unlock(&sInitWindowMutex);
100 break;
101 // TODO: process other commands and pass them to AndroidWindow for handling
102 // TODO: figure out how to handle APP_CMD_PAUSE,
103 // which should immediately halt all the rendering,
104 // since Activity Surface is no longer available.
105 // Currently tests crash when paused, for example, due to device changing orientation
106 }
107 }
108
onInputEvent(struct android_app * app,AInputEvent * event)109 static int32_t onInputEvent(struct android_app *app, AInputEvent *event)
110 {
111 // TODO: Handle input events
112 return 0; // 0 == not handled
113 }
114
android_main(struct android_app * app)115 void android_main(struct android_app *app)
116 {
117 int events;
118 struct android_poll_source *source;
119
120 sApp = app;
121 pthread_mutex_init(&sInitWindowMutex, nullptr);
122 pthread_cond_init(&sInitWindowCond, nullptr);
123
124 // Event handlers, invoked from source->process()
125 app->onAppCmd = onAppCmd;
126 app->onInputEvent = onInputEvent;
127
128 // Message loop, polling for events indefinitely (due to -1 timeout)
129 // Must be here in order to handle APP_CMD_INIT_WINDOW event,
130 // which occurs after AndroidWindow::initialize(), but before AndroidWindow::messageLoop
131 while (ALooper_pollAll(-1, nullptr, &events, reinterpret_cast<void **>(&source)) >= 0)
132 {
133 if (source != nullptr)
134 {
135 source->process(app, source);
136 }
137 }
138 }
139
140 // static
New()141 OSWindow *OSWindow::New()
142 {
143 // There should be only one live instance of AndroidWindow at a time,
144 // as there is only one Activity Surface behind it.
145 // Creating a new AndroidWindow each time works for ANGLETest,
146 // as it destroys an old window before creating a new one.
147 // TODO: use GLSurfaceView to support multiple windows
148 return new AndroidWindow();
149 }
150