1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker
7*8975f5c5SAndroid Build Coastguard Worker // AndroidWindow.cpp: Implementation of OSWindow for Android
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker #include "util/android/AndroidWindow.h"
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Worker #include <pthread.h>
12*8975f5c5SAndroid Build Coastguard Worker #include <filesystem>
13*8975f5c5SAndroid Build Coastguard Worker #include <iostream>
14*8975f5c5SAndroid Build Coastguard Worker
15*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "util/android/third_party/android_native_app_glue.h"
17*8975f5c5SAndroid Build Coastguard Worker
18*8975f5c5SAndroid Build Coastguard Worker namespace
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker struct android_app *sApp = nullptr;
21*8975f5c5SAndroid Build Coastguard Worker pthread_mutex_t sInitWindowMutex;
22*8975f5c5SAndroid Build Coastguard Worker pthread_cond_t sInitWindowCond;
23*8975f5c5SAndroid Build Coastguard Worker bool sInitWindowDone = false;
24*8975f5c5SAndroid Build Coastguard Worker JNIEnv *gJni = nullptr;
25*8975f5c5SAndroid Build Coastguard Worker
26*8975f5c5SAndroid Build Coastguard Worker // SCREEN_ORIENTATION_LANDSCAPE and SCREEN_ORIENTATION_PORTRAIT are
27*8975f5c5SAndroid Build Coastguard Worker // available from Android API level 1
28*8975f5c5SAndroid Build Coastguard Worker // https://developer.android.com/reference/android/app/Activity#setRequestedOrientation(int)
29*8975f5c5SAndroid Build Coastguard Worker const int kScreenOrientationLandscape = 0;
30*8975f5c5SAndroid Build Coastguard Worker const int kScreenOrientationPortrait = 1;
31*8975f5c5SAndroid Build Coastguard Worker
GetJniEnv()32*8975f5c5SAndroid Build Coastguard Worker JNIEnv *GetJniEnv()
33*8975f5c5SAndroid Build Coastguard Worker {
34*8975f5c5SAndroid Build Coastguard Worker if (gJni)
35*8975f5c5SAndroid Build Coastguard Worker return gJni;
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker sApp->activity->vm->AttachCurrentThread(&gJni, NULL);
38*8975f5c5SAndroid Build Coastguard Worker return gJni;
39*8975f5c5SAndroid Build Coastguard Worker }
40*8975f5c5SAndroid Build Coastguard Worker
SetScreenOrientation(struct android_app * app,int orientation)41*8975f5c5SAndroid Build Coastguard Worker int SetScreenOrientation(struct android_app *app, int orientation)
42*8975f5c5SAndroid Build Coastguard Worker {
43*8975f5c5SAndroid Build Coastguard Worker // Use reverse JNI to call the Java entry point that rotates the
44*8975f5c5SAndroid Build Coastguard Worker // display to respect width and height
45*8975f5c5SAndroid Build Coastguard Worker JNIEnv *jni = GetJniEnv();
46*8975f5c5SAndroid Build Coastguard Worker if (!jni)
47*8975f5c5SAndroid Build Coastguard Worker {
48*8975f5c5SAndroid Build Coastguard Worker std::cerr << "Failed to get JNI env for screen rotation";
49*8975f5c5SAndroid Build Coastguard Worker return JNI_ERR;
50*8975f5c5SAndroid Build Coastguard Worker }
51*8975f5c5SAndroid Build Coastguard Worker
52*8975f5c5SAndroid Build Coastguard Worker jclass clazz = jni->GetObjectClass(app->activity->clazz);
53*8975f5c5SAndroid Build Coastguard Worker jmethodID methodID = jni->GetMethodID(clazz, "setRequestedOrientation", "(I)V");
54*8975f5c5SAndroid Build Coastguard Worker jni->CallVoidMethod(app->activity->clazz, methodID, orientation);
55*8975f5c5SAndroid Build Coastguard Worker
56*8975f5c5SAndroid Build Coastguard Worker return 0;
57*8975f5c5SAndroid Build Coastguard Worker }
58*8975f5c5SAndroid Build Coastguard Worker } // namespace
59*8975f5c5SAndroid Build Coastguard Worker
AndroidWindow()60*8975f5c5SAndroid Build Coastguard Worker AndroidWindow::AndroidWindow() {}
61*8975f5c5SAndroid Build Coastguard Worker
~AndroidWindow()62*8975f5c5SAndroid Build Coastguard Worker AndroidWindow::~AndroidWindow() {}
63*8975f5c5SAndroid Build Coastguard Worker
initializeImpl(const std::string & name,int width,int height)64*8975f5c5SAndroid Build Coastguard Worker bool AndroidWindow::initializeImpl(const std::string &name, int width, int height)
65*8975f5c5SAndroid Build Coastguard Worker {
66*8975f5c5SAndroid Build Coastguard Worker return resize(width, height);
67*8975f5c5SAndroid Build Coastguard Worker }
destroy()68*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::destroy() {}
69*8975f5c5SAndroid Build Coastguard Worker
disableErrorMessageDialog()70*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::disableErrorMessageDialog() {}
71*8975f5c5SAndroid Build Coastguard Worker
resetNativeWindow()72*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::resetNativeWindow() {}
73*8975f5c5SAndroid Build Coastguard Worker
getNativeWindow() const74*8975f5c5SAndroid Build Coastguard Worker EGLNativeWindowType AndroidWindow::getNativeWindow() const
75*8975f5c5SAndroid Build Coastguard Worker {
76*8975f5c5SAndroid Build Coastguard Worker // Return the entire Activity Surface for now
77*8975f5c5SAndroid Build Coastguard Worker // sApp->window is valid only after sInitWindowDone, which is true after initializeImpl()
78*8975f5c5SAndroid Build Coastguard Worker return sApp->window;
79*8975f5c5SAndroid Build Coastguard Worker }
80*8975f5c5SAndroid Build Coastguard Worker
getNativeDisplay() const81*8975f5c5SAndroid Build Coastguard Worker EGLNativeDisplayType AndroidWindow::getNativeDisplay() const
82*8975f5c5SAndroid Build Coastguard Worker {
83*8975f5c5SAndroid Build Coastguard Worker return EGL_DEFAULT_DISPLAY;
84*8975f5c5SAndroid Build Coastguard Worker }
85*8975f5c5SAndroid Build Coastguard Worker
messageLoop()86*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::messageLoop()
87*8975f5c5SAndroid Build Coastguard Worker {
88*8975f5c5SAndroid Build Coastguard Worker // TODO: accumulate events in the real message loop of android_main,
89*8975f5c5SAndroid Build Coastguard Worker // and process them here
90*8975f5c5SAndroid Build Coastguard Worker }
91*8975f5c5SAndroid Build Coastguard Worker
setMousePosition(int x,int y)92*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::setMousePosition(int x, int y)
93*8975f5c5SAndroid Build Coastguard Worker {
94*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED();
95*8975f5c5SAndroid Build Coastguard Worker }
96*8975f5c5SAndroid Build Coastguard Worker
setOrientation(int width,int height)97*8975f5c5SAndroid Build Coastguard Worker bool AndroidWindow::setOrientation(int width, int height)
98*8975f5c5SAndroid Build Coastguard Worker {
99*8975f5c5SAndroid Build Coastguard Worker // Set tests to run in correct orientation
100*8975f5c5SAndroid Build Coastguard Worker int32_t err = SetScreenOrientation(
101*8975f5c5SAndroid Build Coastguard Worker sApp, (width > height) ? kScreenOrientationLandscape : kScreenOrientationPortrait);
102*8975f5c5SAndroid Build Coastguard Worker
103*8975f5c5SAndroid Build Coastguard Worker return err == 0;
104*8975f5c5SAndroid Build Coastguard Worker }
setPosition(int x,int y)105*8975f5c5SAndroid Build Coastguard Worker bool AndroidWindow::setPosition(int x, int y)
106*8975f5c5SAndroid Build Coastguard Worker {
107*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED();
108*8975f5c5SAndroid Build Coastguard Worker return false;
109*8975f5c5SAndroid Build Coastguard Worker }
110*8975f5c5SAndroid Build Coastguard Worker
resize(int width,int height)111*8975f5c5SAndroid Build Coastguard Worker bool AndroidWindow::resize(int width, int height)
112*8975f5c5SAndroid Build Coastguard Worker {
113*8975f5c5SAndroid Build Coastguard Worker mWidth = width;
114*8975f5c5SAndroid Build Coastguard Worker mHeight = height;
115*8975f5c5SAndroid Build Coastguard Worker
116*8975f5c5SAndroid Build Coastguard Worker // sApp->window used below is valid only after Activity Surface is created
117*8975f5c5SAndroid Build Coastguard Worker pthread_mutex_lock(&sInitWindowMutex);
118*8975f5c5SAndroid Build Coastguard Worker while (!sInitWindowDone)
119*8975f5c5SAndroid Build Coastguard Worker {
120*8975f5c5SAndroid Build Coastguard Worker pthread_cond_wait(&sInitWindowCond, &sInitWindowMutex);
121*8975f5c5SAndroid Build Coastguard Worker }
122*8975f5c5SAndroid Build Coastguard Worker pthread_mutex_unlock(&sInitWindowMutex);
123*8975f5c5SAndroid Build Coastguard Worker
124*8975f5c5SAndroid Build Coastguard Worker if (sApp->window == nullptr)
125*8975f5c5SAndroid Build Coastguard Worker {
126*8975f5c5SAndroid Build Coastguard Worker // Note: logging isn't initalized yet but this message shows up in logcat.
127*8975f5c5SAndroid Build Coastguard Worker FATAL() << "Window is NULL (is screen locked? e.g. SplashScreen in logcat)";
128*8975f5c5SAndroid Build Coastguard Worker }
129*8975f5c5SAndroid Build Coastguard Worker
130*8975f5c5SAndroid Build Coastguard Worker // TODO: figure out a way to set the format as well,
131*8975f5c5SAndroid Build Coastguard Worker // which is available only after EGLWindow initialization
132*8975f5c5SAndroid Build Coastguard Worker int32_t err = ANativeWindow_setBuffersGeometry(sApp->window, mWidth, mHeight, 0);
133*8975f5c5SAndroid Build Coastguard Worker return err == 0;
134*8975f5c5SAndroid Build Coastguard Worker }
135*8975f5c5SAndroid Build Coastguard Worker
setVisible(bool isVisible)136*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::setVisible(bool isVisible) {}
137*8975f5c5SAndroid Build Coastguard Worker
signalTestEvent()138*8975f5c5SAndroid Build Coastguard Worker void AndroidWindow::signalTestEvent()
139*8975f5c5SAndroid Build Coastguard Worker {
140*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED();
141*8975f5c5SAndroid Build Coastguard Worker }
142*8975f5c5SAndroid Build Coastguard Worker
onAppCmd(struct android_app * app,int32_t cmd)143*8975f5c5SAndroid Build Coastguard Worker static void onAppCmd(struct android_app *app, int32_t cmd)
144*8975f5c5SAndroid Build Coastguard Worker {
145*8975f5c5SAndroid Build Coastguard Worker switch (cmd)
146*8975f5c5SAndroid Build Coastguard Worker {
147*8975f5c5SAndroid Build Coastguard Worker case APP_CMD_INIT_WINDOW:
148*8975f5c5SAndroid Build Coastguard Worker pthread_mutex_lock(&sInitWindowMutex);
149*8975f5c5SAndroid Build Coastguard Worker sInitWindowDone = true;
150*8975f5c5SAndroid Build Coastguard Worker pthread_cond_broadcast(&sInitWindowCond);
151*8975f5c5SAndroid Build Coastguard Worker pthread_mutex_unlock(&sInitWindowMutex);
152*8975f5c5SAndroid Build Coastguard Worker break;
153*8975f5c5SAndroid Build Coastguard Worker case APP_CMD_DESTROY:
154*8975f5c5SAndroid Build Coastguard Worker if (gJni)
155*8975f5c5SAndroid Build Coastguard Worker {
156*8975f5c5SAndroid Build Coastguard Worker sApp->activity->vm->DetachCurrentThread();
157*8975f5c5SAndroid Build Coastguard Worker }
158*8975f5c5SAndroid Build Coastguard Worker gJni = nullptr;
159*8975f5c5SAndroid Build Coastguard Worker break;
160*8975f5c5SAndroid Build Coastguard Worker
161*8975f5c5SAndroid Build Coastguard Worker // TODO: process other commands and pass them to AndroidWindow for handling
162*8975f5c5SAndroid Build Coastguard Worker // TODO: figure out how to handle APP_CMD_PAUSE,
163*8975f5c5SAndroid Build Coastguard Worker // which should immediately halt all the rendering,
164*8975f5c5SAndroid Build Coastguard Worker // since Activity Surface is no longer available.
165*8975f5c5SAndroid Build Coastguard Worker // Currently tests crash when paused, for example, due to device changing orientation
166*8975f5c5SAndroid Build Coastguard Worker }
167*8975f5c5SAndroid Build Coastguard Worker }
168*8975f5c5SAndroid Build Coastguard Worker
onInputEvent(struct android_app * app,AInputEvent * event)169*8975f5c5SAndroid Build Coastguard Worker static int32_t onInputEvent(struct android_app *app, AInputEvent *event)
170*8975f5c5SAndroid Build Coastguard Worker {
171*8975f5c5SAndroid Build Coastguard Worker // TODO: Handle input events
172*8975f5c5SAndroid Build Coastguard Worker return 0; // 0 == not handled
173*8975f5c5SAndroid Build Coastguard Worker }
174*8975f5c5SAndroid Build Coastguard Worker
validPollResult(int result)175*8975f5c5SAndroid Build Coastguard Worker static bool validPollResult(int result)
176*8975f5c5SAndroid Build Coastguard Worker {
177*8975f5c5SAndroid Build Coastguard Worker return result >= 0 || result == ALOOPER_POLL_CALLBACK;
178*8975f5c5SAndroid Build Coastguard Worker }
179*8975f5c5SAndroid Build Coastguard Worker
android_main(struct android_app * app)180*8975f5c5SAndroid Build Coastguard Worker void android_main(struct android_app *app)
181*8975f5c5SAndroid Build Coastguard Worker {
182*8975f5c5SAndroid Build Coastguard Worker int events;
183*8975f5c5SAndroid Build Coastguard Worker struct android_poll_source *source;
184*8975f5c5SAndroid Build Coastguard Worker
185*8975f5c5SAndroid Build Coastguard Worker sApp = app;
186*8975f5c5SAndroid Build Coastguard Worker pthread_mutex_init(&sInitWindowMutex, nullptr);
187*8975f5c5SAndroid Build Coastguard Worker pthread_cond_init(&sInitWindowCond, nullptr);
188*8975f5c5SAndroid Build Coastguard Worker
189*8975f5c5SAndroid Build Coastguard Worker // Event handlers, invoked from source->process()
190*8975f5c5SAndroid Build Coastguard Worker app->onAppCmd = onAppCmd;
191*8975f5c5SAndroid Build Coastguard Worker app->onInputEvent = onInputEvent;
192*8975f5c5SAndroid Build Coastguard Worker
193*8975f5c5SAndroid Build Coastguard Worker // Message loop, polling for events indefinitely (due to -1 timeout)
194*8975f5c5SAndroid Build Coastguard Worker // Must be here in order to handle APP_CMD_INIT_WINDOW event,
195*8975f5c5SAndroid Build Coastguard Worker // which occurs after AndroidWindow::initializeImpl(), but before AndroidWindow::messageLoop
196*8975f5c5SAndroid Build Coastguard Worker while (
197*8975f5c5SAndroid Build Coastguard Worker validPollResult(ALooper_pollOnce(-1, nullptr, &events, reinterpret_cast<void **>(&source))))
198*8975f5c5SAndroid Build Coastguard Worker {
199*8975f5c5SAndroid Build Coastguard Worker if (source != nullptr)
200*8975f5c5SAndroid Build Coastguard Worker {
201*8975f5c5SAndroid Build Coastguard Worker source->process(app, source);
202*8975f5c5SAndroid Build Coastguard Worker }
203*8975f5c5SAndroid Build Coastguard Worker }
204*8975f5c5SAndroid Build Coastguard Worker }
205*8975f5c5SAndroid Build Coastguard Worker
GetApplicationDirectory()206*8975f5c5SAndroid Build Coastguard Worker std::string AndroidWindow::GetApplicationDirectory()
207*8975f5c5SAndroid Build Coastguard Worker {
208*8975f5c5SAndroid Build Coastguard Worker // Use reverse JNI.
209*8975f5c5SAndroid Build Coastguard Worker JNIEnv *jni = GetJniEnv();
210*8975f5c5SAndroid Build Coastguard Worker if (!jni)
211*8975f5c5SAndroid Build Coastguard Worker {
212*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory:: Failed to get JNI env";
213*8975f5c5SAndroid Build Coastguard Worker return "";
214*8975f5c5SAndroid Build Coastguard Worker }
215*8975f5c5SAndroid Build Coastguard Worker
216*8975f5c5SAndroid Build Coastguard Worker // Get the ANativeActivity class
217*8975f5c5SAndroid Build Coastguard Worker jclass nativeActivityClass = jni->GetObjectClass(sApp->activity->clazz);
218*8975f5c5SAndroid Build Coastguard Worker if (!nativeActivityClass)
219*8975f5c5SAndroid Build Coastguard Worker {
220*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to get ANativeActivity class";
221*8975f5c5SAndroid Build Coastguard Worker return "";
222*8975f5c5SAndroid Build Coastguard Worker }
223*8975f5c5SAndroid Build Coastguard Worker
224*8975f5c5SAndroid Build Coastguard Worker // Get the getApplicationContext() method ID
225*8975f5c5SAndroid Build Coastguard Worker jmethodID getApplicationContextMethod = jni->GetMethodID(
226*8975f5c5SAndroid Build Coastguard Worker nativeActivityClass, "getApplicationContext", "()Landroid/content/Context;");
227*8975f5c5SAndroid Build Coastguard Worker if (!getApplicationContextMethod)
228*8975f5c5SAndroid Build Coastguard Worker {
229*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to find getApplicationContext method";
230*8975f5c5SAndroid Build Coastguard Worker return "";
231*8975f5c5SAndroid Build Coastguard Worker }
232*8975f5c5SAndroid Build Coastguard Worker
233*8975f5c5SAndroid Build Coastguard Worker // Call getApplicationContext() to get the Context object
234*8975f5c5SAndroid Build Coastguard Worker jobject context = jni->CallObjectMethod(sApp->activity->clazz, getApplicationContextMethod);
235*8975f5c5SAndroid Build Coastguard Worker if (!context)
236*8975f5c5SAndroid Build Coastguard Worker {
237*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to get Context object";
238*8975f5c5SAndroid Build Coastguard Worker return "";
239*8975f5c5SAndroid Build Coastguard Worker }
240*8975f5c5SAndroid Build Coastguard Worker
241*8975f5c5SAndroid Build Coastguard Worker // Get the Context class
242*8975f5c5SAndroid Build Coastguard Worker jclass contextClass = jni->GetObjectClass(context);
243*8975f5c5SAndroid Build Coastguard Worker if (!contextClass)
244*8975f5c5SAndroid Build Coastguard Worker {
245*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to get Context class";
246*8975f5c5SAndroid Build Coastguard Worker return "";
247*8975f5c5SAndroid Build Coastguard Worker }
248*8975f5c5SAndroid Build Coastguard Worker
249*8975f5c5SAndroid Build Coastguard Worker // Get the getFilesDir() method ID
250*8975f5c5SAndroid Build Coastguard Worker jmethodID getFilesDirMethod = jni->GetMethodID(contextClass, "getFilesDir", "()Ljava/io/File;");
251*8975f5c5SAndroid Build Coastguard Worker if (!getFilesDirMethod)
252*8975f5c5SAndroid Build Coastguard Worker {
253*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to find getFilesDir method";
254*8975f5c5SAndroid Build Coastguard Worker return "";
255*8975f5c5SAndroid Build Coastguard Worker }
256*8975f5c5SAndroid Build Coastguard Worker
257*8975f5c5SAndroid Build Coastguard Worker // Call getFilesDir() to get the File object
258*8975f5c5SAndroid Build Coastguard Worker jobject fileObject = jni->CallObjectMethod(context, getFilesDirMethod);
259*8975f5c5SAndroid Build Coastguard Worker if (!fileObject)
260*8975f5c5SAndroid Build Coastguard Worker {
261*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to get File object";
262*8975f5c5SAndroid Build Coastguard Worker return "";
263*8975f5c5SAndroid Build Coastguard Worker }
264*8975f5c5SAndroid Build Coastguard Worker
265*8975f5c5SAndroid Build Coastguard Worker // Get the File class
266*8975f5c5SAndroid Build Coastguard Worker jclass fileClass = jni->GetObjectClass(fileObject);
267*8975f5c5SAndroid Build Coastguard Worker if (!fileClass)
268*8975f5c5SAndroid Build Coastguard Worker {
269*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to get File class";
270*8975f5c5SAndroid Build Coastguard Worker return "";
271*8975f5c5SAndroid Build Coastguard Worker }
272*8975f5c5SAndroid Build Coastguard Worker
273*8975f5c5SAndroid Build Coastguard Worker // Get the getAbsolutePath() method ID
274*8975f5c5SAndroid Build Coastguard Worker jmethodID getAbsolutePathMethod =
275*8975f5c5SAndroid Build Coastguard Worker jni->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
276*8975f5c5SAndroid Build Coastguard Worker if (!getAbsolutePathMethod)
277*8975f5c5SAndroid Build Coastguard Worker {
278*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to find getAbsolutePath method";
279*8975f5c5SAndroid Build Coastguard Worker return "";
280*8975f5c5SAndroid Build Coastguard Worker }
281*8975f5c5SAndroid Build Coastguard Worker
282*8975f5c5SAndroid Build Coastguard Worker // Call getAbsolutePath() to get the path as a jstring
283*8975f5c5SAndroid Build Coastguard Worker jstring pathString = (jstring)jni->CallObjectMethod(fileObject, getAbsolutePathMethod);
284*8975f5c5SAndroid Build Coastguard Worker if (!pathString)
285*8975f5c5SAndroid Build Coastguard Worker {
286*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetApplicationDirectory: Failed to get path string";
287*8975f5c5SAndroid Build Coastguard Worker return "";
288*8975f5c5SAndroid Build Coastguard Worker }
289*8975f5c5SAndroid Build Coastguard Worker
290*8975f5c5SAndroid Build Coastguard Worker // Convert the jstring to a std::string
291*8975f5c5SAndroid Build Coastguard Worker const char *pathChars = jni->GetStringUTFChars(pathString, nullptr);
292*8975f5c5SAndroid Build Coastguard Worker std::string filesDirPath(pathChars);
293*8975f5c5SAndroid Build Coastguard Worker jni->ReleaseStringUTFChars(pathString, pathChars);
294*8975f5c5SAndroid Build Coastguard Worker
295*8975f5c5SAndroid Build Coastguard Worker // Return the base directory, stripping "files" essentially
296*8975f5c5SAndroid Build Coastguard Worker std::filesystem::path fullPath(filesDirPath);
297*8975f5c5SAndroid Build Coastguard Worker return fullPath.parent_path();
298*8975f5c5SAndroid Build Coastguard Worker }
299*8975f5c5SAndroid Build Coastguard Worker
300*8975f5c5SAndroid Build Coastguard Worker // static
GetExternalStorageDirectory()301*8975f5c5SAndroid Build Coastguard Worker std::string AndroidWindow::GetExternalStorageDirectory()
302*8975f5c5SAndroid Build Coastguard Worker {
303*8975f5c5SAndroid Build Coastguard Worker // Use reverse JNI.
304*8975f5c5SAndroid Build Coastguard Worker JNIEnv *jni = GetJniEnv();
305*8975f5c5SAndroid Build Coastguard Worker if (!jni)
306*8975f5c5SAndroid Build Coastguard Worker {
307*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory:: Failed to get JNI env";
308*8975f5c5SAndroid Build Coastguard Worker return "";
309*8975f5c5SAndroid Build Coastguard Worker }
310*8975f5c5SAndroid Build Coastguard Worker
311*8975f5c5SAndroid Build Coastguard Worker jclass classEnvironment = jni->FindClass("android/os/Environment");
312*8975f5c5SAndroid Build Coastguard Worker if (classEnvironment == 0)
313*8975f5c5SAndroid Build Coastguard Worker {
314*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory: Failed to find Environment";
315*8975f5c5SAndroid Build Coastguard Worker return "";
316*8975f5c5SAndroid Build Coastguard Worker }
317*8975f5c5SAndroid Build Coastguard Worker
318*8975f5c5SAndroid Build Coastguard Worker // public static File getExternalStorageDirectory ()
319*8975f5c5SAndroid Build Coastguard Worker jmethodID methodIDgetExternalStorageDirectory =
320*8975f5c5SAndroid Build Coastguard Worker jni->GetStaticMethodID(classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;");
321*8975f5c5SAndroid Build Coastguard Worker if (methodIDgetExternalStorageDirectory == 0)
322*8975f5c5SAndroid Build Coastguard Worker {
323*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory: Failed to get static method";
324*8975f5c5SAndroid Build Coastguard Worker return "";
325*8975f5c5SAndroid Build Coastguard Worker }
326*8975f5c5SAndroid Build Coastguard Worker
327*8975f5c5SAndroid Build Coastguard Worker jobject objectFile =
328*8975f5c5SAndroid Build Coastguard Worker jni->CallStaticObjectMethod(classEnvironment, methodIDgetExternalStorageDirectory);
329*8975f5c5SAndroid Build Coastguard Worker jthrowable exception = jni->ExceptionOccurred();
330*8975f5c5SAndroid Build Coastguard Worker if (exception != 0)
331*8975f5c5SAndroid Build Coastguard Worker {
332*8975f5c5SAndroid Build Coastguard Worker jni->ExceptionDescribe();
333*8975f5c5SAndroid Build Coastguard Worker jni->ExceptionClear();
334*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory: Failed because of exception";
335*8975f5c5SAndroid Build Coastguard Worker return "";
336*8975f5c5SAndroid Build Coastguard Worker }
337*8975f5c5SAndroid Build Coastguard Worker
338*8975f5c5SAndroid Build Coastguard Worker // Call method on File object to retrieve String object.
339*8975f5c5SAndroid Build Coastguard Worker jclass classFile = jni->GetObjectClass(objectFile);
340*8975f5c5SAndroid Build Coastguard Worker if (classEnvironment == 0)
341*8975f5c5SAndroid Build Coastguard Worker {
342*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory: Failed to find object class";
343*8975f5c5SAndroid Build Coastguard Worker return "";
344*8975f5c5SAndroid Build Coastguard Worker }
345*8975f5c5SAndroid Build Coastguard Worker
346*8975f5c5SAndroid Build Coastguard Worker jmethodID methodIDgetAbsolutePath =
347*8975f5c5SAndroid Build Coastguard Worker jni->GetMethodID(classFile, "getAbsolutePath", "()Ljava/lang/String;");
348*8975f5c5SAndroid Build Coastguard Worker if (methodIDgetAbsolutePath == 0)
349*8975f5c5SAndroid Build Coastguard Worker {
350*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory: Failed to get method ID";
351*8975f5c5SAndroid Build Coastguard Worker return "";
352*8975f5c5SAndroid Build Coastguard Worker }
353*8975f5c5SAndroid Build Coastguard Worker
354*8975f5c5SAndroid Build Coastguard Worker jstring stringPath =
355*8975f5c5SAndroid Build Coastguard Worker static_cast<jstring>(jni->CallObjectMethod(objectFile, methodIDgetAbsolutePath));
356*8975f5c5SAndroid Build Coastguard Worker
357*8975f5c5SAndroid Build Coastguard Worker // TODO(jmadill): Find how to pass the root test directory to ANGLE. http://crbug.com/1097957
358*8975f5c5SAndroid Build Coastguard Worker
359*8975f5c5SAndroid Build Coastguard Worker // // https://stackoverflow.com/questions/12841240/android-pass-parameter-to-native-activity
360*8975f5c5SAndroid Build Coastguard Worker // jclass clazz = jni->GetObjectClass(sApp->activity->clazz);
361*8975f5c5SAndroid Build Coastguard Worker // if (clazz == 0)
362*8975f5c5SAndroid Build Coastguard Worker // {
363*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Bad activity";
364*8975f5c5SAndroid Build Coastguard Worker // return "";
365*8975f5c5SAndroid Build Coastguard Worker // }
366*8975f5c5SAndroid Build Coastguard Worker
367*8975f5c5SAndroid Build Coastguard Worker // jmethodID giid = jni->GetMethodID(clazz, "getIntent", "()Landroid/content/Intent;");
368*8975f5c5SAndroid Build Coastguard Worker // if (giid == 0)
369*8975f5c5SAndroid Build Coastguard Worker // {
370*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Could not find getIntent";
371*8975f5c5SAndroid Build Coastguard Worker // return "";
372*8975f5c5SAndroid Build Coastguard Worker // }
373*8975f5c5SAndroid Build Coastguard Worker
374*8975f5c5SAndroid Build Coastguard Worker // jobject intent = jni->CallObjectMethod(sApp->activity->clazz, giid);
375*8975f5c5SAndroid Build Coastguard Worker // if (intent == 0)
376*8975f5c5SAndroid Build Coastguard Worker // {
377*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Error calling getIntent";
378*8975f5c5SAndroid Build Coastguard Worker // return "";
379*8975f5c5SAndroid Build Coastguard Worker // }
380*8975f5c5SAndroid Build Coastguard Worker
381*8975f5c5SAndroid Build Coastguard Worker // jclass icl = jni->GetObjectClass(intent);
382*8975f5c5SAndroid Build Coastguard Worker // if (icl == 0)
383*8975f5c5SAndroid Build Coastguard Worker // {
384*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Error getting getIntent class";
385*8975f5c5SAndroid Build Coastguard Worker // return "";
386*8975f5c5SAndroid Build Coastguard Worker // }
387*8975f5c5SAndroid Build Coastguard Worker
388*8975f5c5SAndroid Build Coastguard Worker // jmethodID gseid =
389*8975f5c5SAndroid Build Coastguard Worker // jni->GetMethodID(icl, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
390*8975f5c5SAndroid Build Coastguard Worker // if (gseid == 0)
391*8975f5c5SAndroid Build Coastguard Worker // {
392*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Could not find getStringExtra";
393*8975f5c5SAndroid Build Coastguard Worker // return "";
394*8975f5c5SAndroid Build Coastguard Worker // }
395*8975f5c5SAndroid Build Coastguard Worker
396*8975f5c5SAndroid Build Coastguard Worker // jstring stringPath = static_cast<jstring>(jni->CallObjectMethod(
397*8975f5c5SAndroid Build Coastguard Worker // intent, gseid, jni->NewStringUTF("org.chromium.base.test.util.UrlUtils.RootDirectory")));
398*8975f5c5SAndroid Build Coastguard Worker // if (stringPath != 0)
399*8975f5c5SAndroid Build Coastguard Worker // {
400*8975f5c5SAndroid Build Coastguard Worker // const char *path = jni->GetStringUTFChars(stringPath, nullptr);
401*8975f5c5SAndroid Build Coastguard Worker // return std::string(path) + "/chromium_tests_root";
402*8975f5c5SAndroid Build Coastguard Worker // }
403*8975f5c5SAndroid Build Coastguard Worker
404*8975f5c5SAndroid Build Coastguard Worker // jclass environment = jni->FindClass("org/chromium/base/test/util/UrlUtils");
405*8975f5c5SAndroid Build Coastguard Worker // if (environment == 0)
406*8975f5c5SAndroid Build Coastguard Worker // {
407*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Failed to find Environment";
408*8975f5c5SAndroid Build Coastguard Worker // return "";
409*8975f5c5SAndroid Build Coastguard Worker // }
410*8975f5c5SAndroid Build Coastguard Worker
411*8975f5c5SAndroid Build Coastguard Worker // jmethodID getDir =
412*8975f5c5SAndroid Build Coastguard Worker // jni->GetStaticMethodID(environment, "getIsolatedTestRoot", "()Ljava/lang/String;");
413*8975f5c5SAndroid Build Coastguard Worker // if (getDir == 0)
414*8975f5c5SAndroid Build Coastguard Worker // {
415*8975f5c5SAndroid Build Coastguard Worker // std::cerr << "GetExternalStorageDirectory: Failed to get static method";
416*8975f5c5SAndroid Build Coastguard Worker // return "";
417*8975f5c5SAndroid Build Coastguard Worker // }
418*8975f5c5SAndroid Build Coastguard Worker
419*8975f5c5SAndroid Build Coastguard Worker // stringPath = static_cast<jstring>(jni->CallStaticObjectMethod(environment, getDir));
420*8975f5c5SAndroid Build Coastguard Worker
421*8975f5c5SAndroid Build Coastguard Worker exception = jni->ExceptionOccurred();
422*8975f5c5SAndroid Build Coastguard Worker if (exception != 0)
423*8975f5c5SAndroid Build Coastguard Worker {
424*8975f5c5SAndroid Build Coastguard Worker jni->ExceptionDescribe();
425*8975f5c5SAndroid Build Coastguard Worker jni->ExceptionClear();
426*8975f5c5SAndroid Build Coastguard Worker std::cerr << "GetExternalStorageDirectory: Failed because of exception";
427*8975f5c5SAndroid Build Coastguard Worker return "";
428*8975f5c5SAndroid Build Coastguard Worker }
429*8975f5c5SAndroid Build Coastguard Worker
430*8975f5c5SAndroid Build Coastguard Worker const char *path = jni->GetStringUTFChars(stringPath, nullptr);
431*8975f5c5SAndroid Build Coastguard Worker return std::string(path) + "/chromium_tests_root";
432*8975f5c5SAndroid Build Coastguard Worker }
433*8975f5c5SAndroid Build Coastguard Worker
434*8975f5c5SAndroid Build Coastguard Worker // static
New()435*8975f5c5SAndroid Build Coastguard Worker OSWindow *OSWindow::New()
436*8975f5c5SAndroid Build Coastguard Worker {
437*8975f5c5SAndroid Build Coastguard Worker // There should be only one live instance of AndroidWindow at a time,
438*8975f5c5SAndroid Build Coastguard Worker // as there is only one Activity Surface behind it.
439*8975f5c5SAndroid Build Coastguard Worker // Creating a new AndroidWindow each time works for ANGLETest,
440*8975f5c5SAndroid Build Coastguard Worker // as it destroys an old window before creating a new one.
441*8975f5c5SAndroid Build Coastguard Worker // TODO: use GLSurfaceView to support multiple windows
442*8975f5c5SAndroid Build Coastguard Worker return new AndroidWindow();
443*8975f5c5SAndroid Build Coastguard Worker }
444