Path: blob/main_old/util/android/AndroidWindow.cpp
1693 views
//1// Copyright 2016 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56// AndroidWindow.cpp: Implementation of OSWindow for Android78#include "util/android/AndroidWindow.h"910#include <pthread.h>11#include <iostream>1213#include "common/debug.h"14#include "util/android/third_party/android_native_app_glue.h"1516namespace17{18struct android_app *sApp = nullptr;19pthread_mutex_t sInitWindowMutex;20pthread_cond_t sInitWindowCond;21bool sInitWindowDone = false;22JNIEnv *gJni = nullptr;2324// SCREEN_ORIENTATION_LANDSCAPE and SCREEN_ORIENTATION_PORTRAIT are25// available from Android API level 126// https://developer.android.com/reference/android/app/Activity#setRequestedOrientation(int)27const int kScreenOrientationLandscape = 0;28const int kScreenOrientationPortrait = 1;2930JNIEnv *GetJniEnv()31{32if (gJni)33return gJni;3435sApp->activity->vm->AttachCurrentThread(&gJni, NULL);36return gJni;37}3839int SetScreenOrientation(struct android_app *app, int orientation)40{41// Use reverse JNI to call the Java entry point that rotates the42// display to respect width and height43JNIEnv *jni = GetJniEnv();44if (!jni)45{46std::cerr << "Failed to get JNI env for screen rotation";47return JNI_ERR;48}4950jclass clazz = jni->GetObjectClass(app->activity->clazz);51jmethodID methodID = jni->GetMethodID(clazz, "setRequestedOrientation", "(I)V");52jni->CallVoidMethod(app->activity->clazz, methodID, orientation);5354return 0;55}56} // namespace5758AndroidWindow::AndroidWindow() {}5960AndroidWindow::~AndroidWindow() {}6162bool AndroidWindow::initializeImpl(const std::string &name, int width, int height)63{64return resize(width, height);65}66void AndroidWindow::destroy() {}6768void AndroidWindow::disableErrorMessageDialog() {}6970void AndroidWindow::resetNativeWindow() {}7172EGLNativeWindowType AndroidWindow::getNativeWindow() const73{74// Return the entire Activity Surface for now75// sApp->window is valid only after sInitWindowDone, which is true after initializeImpl()76return sApp->window;77}7879EGLNativeDisplayType AndroidWindow::getNativeDisplay() const80{81return EGL_DEFAULT_DISPLAY;82}8384void AndroidWindow::messageLoop()85{86// TODO: accumulate events in the real message loop of android_main,87// and process them here88}8990void AndroidWindow::setMousePosition(int x, int y)91{92UNIMPLEMENTED();93}9495bool AndroidWindow::setOrientation(int width, int height)96{97// Set tests to run in correct orientation98int32_t err = SetScreenOrientation(99sApp, (width > height) ? kScreenOrientationLandscape : kScreenOrientationPortrait);100101return err == 0;102}103bool AndroidWindow::setPosition(int x, int y)104{105UNIMPLEMENTED();106return false;107}108109bool AndroidWindow::resize(int width, int height)110{111mWidth = width;112mHeight = height;113114// sApp->window used below is valid only after Activity Surface is created115pthread_mutex_lock(&sInitWindowMutex);116while (!sInitWindowDone)117{118pthread_cond_wait(&sInitWindowCond, &sInitWindowMutex);119}120pthread_mutex_unlock(&sInitWindowMutex);121122// TODO: figure out a way to set the format as well,123// which is available only after EGLWindow initialization124int32_t err = ANativeWindow_setBuffersGeometry(sApp->window, mWidth, mHeight, 0);125return err == 0;126}127128void AndroidWindow::setVisible(bool isVisible) {}129130void AndroidWindow::signalTestEvent()131{132UNIMPLEMENTED();133}134135static void onAppCmd(struct android_app *app, int32_t cmd)136{137switch (cmd)138{139case APP_CMD_INIT_WINDOW:140pthread_mutex_lock(&sInitWindowMutex);141sInitWindowDone = true;142pthread_cond_broadcast(&sInitWindowCond);143pthread_mutex_unlock(&sInitWindowMutex);144break;145case APP_CMD_DESTROY:146if (gJni)147{148sApp->activity->vm->DetachCurrentThread();149}150gJni = nullptr;151break;152153// TODO: process other commands and pass them to AndroidWindow for handling154// TODO: figure out how to handle APP_CMD_PAUSE,155// which should immediately halt all the rendering,156// since Activity Surface is no longer available.157// Currently tests crash when paused, for example, due to device changing orientation158}159}160161static int32_t onInputEvent(struct android_app *app, AInputEvent *event)162{163// TODO: Handle input events164return 0; // 0 == not handled165}166167void android_main(struct android_app *app)168{169int events;170struct android_poll_source *source;171172sApp = app;173pthread_mutex_init(&sInitWindowMutex, nullptr);174pthread_cond_init(&sInitWindowCond, nullptr);175176// Event handlers, invoked from source->process()177app->onAppCmd = onAppCmd;178app->onInputEvent = onInputEvent;179180// Message loop, polling for events indefinitely (due to -1 timeout)181// Must be here in order to handle APP_CMD_INIT_WINDOW event,182// which occurs after AndroidWindow::initializeImpl(), but before AndroidWindow::messageLoop183while (ALooper_pollAll(-1, nullptr, &events, reinterpret_cast<void **>(&source)) >= 0)184{185if (source != nullptr)186{187source->process(app, source);188}189}190}191192// static193std::string AndroidWindow::GetExternalStorageDirectory()194{195// Use reverse JNI.196JNIEnv *jni = GetJniEnv();197if (!jni)198{199std::cerr << "GetExternalStorageDirectory:: Failed to get JNI env";200return "";201}202203jclass classEnvironment = jni->FindClass("android/os/Environment");204if (classEnvironment == 0)205{206std::cerr << "GetExternalStorageDirectory: Failed to find Environment";207return "";208}209210// public static File getExternalStorageDirectory ()211jmethodID methodIDgetExternalStorageDirectory =212jni->GetStaticMethodID(classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;");213if (methodIDgetExternalStorageDirectory == 0)214{215std::cerr << "GetExternalStorageDirectory: Failed to get static method";216return "";217}218219jobject objectFile =220jni->CallStaticObjectMethod(classEnvironment, methodIDgetExternalStorageDirectory);221jthrowable exception = jni->ExceptionOccurred();222if (exception != 0)223{224jni->ExceptionDescribe();225jni->ExceptionClear();226std::cerr << "GetExternalStorageDirectory: Failed because of exception";227return "";228}229230// Call method on File object to retrieve String object.231jclass classFile = jni->GetObjectClass(objectFile);232if (classEnvironment == 0)233{234std::cerr << "GetExternalStorageDirectory: Failed to find object class";235return "";236}237238jmethodID methodIDgetAbsolutePath =239jni->GetMethodID(classFile, "getAbsolutePath", "()Ljava/lang/String;");240if (methodIDgetAbsolutePath == 0)241{242std::cerr << "GetExternalStorageDirectory: Failed to get method ID";243return "";244}245246jstring stringPath =247static_cast<jstring>(jni->CallObjectMethod(objectFile, methodIDgetAbsolutePath));248249// TODO(jmadill): Find how to pass the root test directory to ANGLE. http://crbug.com/1097957250251// // https://stackoverflow.com/questions/12841240/android-pass-parameter-to-native-activity252// jclass clazz = jni->GetObjectClass(sApp->activity->clazz);253// if (clazz == 0)254// {255// std::cerr << "GetExternalStorageDirectory: Bad activity";256// return "";257// }258259// jmethodID giid = jni->GetMethodID(clazz, "getIntent", "()Landroid/content/Intent;");260// if (giid == 0)261// {262// std::cerr << "GetExternalStorageDirectory: Could not find getIntent";263// return "";264// }265266// jobject intent = jni->CallObjectMethod(sApp->activity->clazz, giid);267// if (intent == 0)268// {269// std::cerr << "GetExternalStorageDirectory: Error calling getIntent";270// return "";271// }272273// jclass icl = jni->GetObjectClass(intent);274// if (icl == 0)275// {276// std::cerr << "GetExternalStorageDirectory: Error getting getIntent class";277// return "";278// }279280// jmethodID gseid =281// jni->GetMethodID(icl, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");282// if (gseid == 0)283// {284// std::cerr << "GetExternalStorageDirectory: Could not find getStringExtra";285// return "";286// }287288// jstring stringPath = static_cast<jstring>(jni->CallObjectMethod(289// intent, gseid, jni->NewStringUTF("org.chromium.base.test.util.UrlUtils.RootDirectory")));290// if (stringPath != 0)291// {292// const char *path = jni->GetStringUTFChars(stringPath, nullptr);293// return std::string(path) + "/chromium_tests_root";294// }295296// jclass environment = jni->FindClass("org/chromium/base/test/util/UrlUtils");297// if (environment == 0)298// {299// std::cerr << "GetExternalStorageDirectory: Failed to find Environment";300// return "";301// }302303// jmethodID getDir =304// jni->GetStaticMethodID(environment, "getIsolatedTestRoot", "()Ljava/lang/String;");305// if (getDir == 0)306// {307// std::cerr << "GetExternalStorageDirectory: Failed to get static method";308// return "";309// }310311// stringPath = static_cast<jstring>(jni->CallStaticObjectMethod(environment, getDir));312313exception = jni->ExceptionOccurred();314if (exception != 0)315{316jni->ExceptionDescribe();317jni->ExceptionClear();318std::cerr << "GetExternalStorageDirectory: Failed because of exception";319return "";320}321322const char *path = jni->GetStringUTFChars(stringPath, nullptr);323return std::string(path) + "/chromium_tests_root";324}325326// static327OSWindow *OSWindow::New()328{329// There should be only one live instance of AndroidWindow at a time,330// as there is only one Activity Surface behind it.331// Creating a new AndroidWindow each time works for ANGLETest,332// as it destroys an old window before creating a new one.333// TODO: use GLSurfaceView to support multiple windows334return new AndroidWindow();335}336337338