/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_UI_WINDOWED_APP_CONTEXT_ANDROID_H_ #define XENIA_UI_WINDOWED_APP_CONTEXT_ANDROID_H_ #include #include #include #include #include #include #include #include "xenia/ui/windowed_app_context.h" namespace xe { namespace ui { class AndroidWindow; class WindowedApp; class AndroidWindowedAppContext final : public WindowedAppContext { public: WindowedApp* app() const { return app_.get(); } void NotifyUILoopOfPendingFunctions() override; void PlatformQuitFromUIThread() override; uint32_t GetPixelDensity() const { return configuration_ ? uint32_t(AConfiguration_getDensity(configuration_)) : 160; } int32_t window_surface_layout_left() const { return window_surface_layout_left_; } int32_t window_surface_layout_top() const { return window_surface_layout_top_; } int32_t window_surface_layout_right() const { return window_surface_layout_right_; } int32_t window_surface_layout_bottom() const { return window_surface_layout_bottom_; } ANativeWindow* GetWindowSurface() const { return window_surface_; } void PostInvalidateWindowSurface(); // The single Window instance that will be receiving window callbacks. // Multiple windows cannot be created as one activity or fragment can have // only one layout. This window acts purely as a proxy between the activity // and the Xenia logic. May be done during Window destruction, so must not // interact with it. AndroidWindow* GetActivityWindow() const { return activity_window_; } void SetActivityWindow(AndroidWindow* window) { activity_window_ = window; } // For calling from WindowedAppActivity native methods. static AndroidWindowedAppContext* JniActivityInitializeWindowedAppOnCreate( JNIEnv* jni_env, jobject activity, jstring windowed_app_identifier, jobject asset_manager); void JniActivityOnDestroy(); void JniActivityOnWindowSurfaceLayoutChange(jint left, jint top, jint right, jint bottom); void JniActivityOnWindowSurfaceChanged(jobject window_surface_object); void JniActivityPaintWindow(bool force_paint); private: enum class UIThreadLooperCallbackCommand : uint8_t { kDestroy, kExecutePendingFunctions, }; AndroidWindowedAppContext() = default; // Don't delete this object directly externally if successfully initialized as // the looper may still execute the callback for pending commands after an // external ALooper_removeFd, and the callback receives a pointer to the // context - deletion must be deferred and done in the callback itself. // Defined in the translation unit where WindowedApp is complete because of // std::unique_ptr. ~AndroidWindowedAppContext(); bool Initialize(JNIEnv* ui_thread_jni_env, jobject activity, jobject asset_manager); void Shutdown(); // Call this function instead of deleting the object directly, so if needed, // deletion will be deferred until the callback (receiving a pointer to the // context) can no longer be executed by the looper (will be done inside the // callback). void RequestDestruction(); static int UIThreadLooperCallback(int fd, int events, void* data); bool InitializeApp(std::unique_ptr (*app_creator)( WindowedAppContext& app_context)); JNIEnv* ui_thread_jni_env_ = nullptr; // The object reference must be held by the app according to // AAssetManager_fromJava documentation. jobject asset_manager_jobject_ = nullptr; AAssetManager* asset_manager_ = nullptr; AConfiguration* configuration_ = nullptr; jclass activity_class_ = nullptr; bool android_base_initialized_ = false; jobject activity_ = nullptr; jmethodID activity_method_finish_ = nullptr; jmethodID activity_method_post_invalidate_window_surface_ = nullptr; // May be read by non-UI threads in NotifyUILoopOfPendingFunctions. ALooper* ui_thread_looper_ = nullptr; // [1] (the write file descriptor) may be referenced as read-only by non-UI // threads in NotifyUILoopOfPendingFunctions. std::array ui_thread_looper_callback_pipe_{-1, -1}; bool ui_thread_looper_callback_registered_ = false; int32_t window_surface_layout_left_ = 0; int32_t window_surface_layout_top_ = 0; int32_t window_surface_layout_right_ = 0; int32_t window_surface_layout_bottom_ = 0; ANativeWindow* window_surface_ = nullptr; AndroidWindow* activity_window_ = nullptr; std::unique_ptr app_; }; } // namespace ui } // namespace xe #endif // XENIA_UI_WINDOWED_APP_CONTEXT_ANDROID_H_