From 6f4c66896a1cf2a33937e8a0a5d798e977690dea Mon Sep 17 00:00:00 2001 From: lhyqy5 Date: Fri, 31 Oct 2025 13:55:09 +0800 Subject: [PATCH] gpu,build,display,sensors,input --- myphoneinfo/andinfo/build.gradle.kts | 1 + .../andinfo/src/main/cpp/CMakeLists.txt | 14 +- myphoneinfo/andinfo/src/main/cpp/CpuJni.h | 12 +- myphoneinfo/andinfo/src/main/cpp/EglUtils.cpp | 123 +++++ myphoneinfo/andinfo/src/main/cpp/VkUtils.cpp | 80 ++++ .../andinfo/src/main/cpp/egl/EglContext.cpp | 33 ++ .../andinfo/src/main/cpp/egl/EglContext.h | 29 ++ .../andinfo/src/main/cpp/egl/EglSession.cpp | 67 +++ .../andinfo/src/main/cpp/egl/EglSession.h | 40 ++ .../andinfo/src/main/cpp/jni_utils.cpp | 31 ++ myphoneinfo/andinfo/src/main/cpp/jni_utils.h | 42 +- myphoneinfo/andinfo/src/main/cpp/logging.h | 11 + .../andinfo/src/main/cpp/vulkan/VkSession.cpp | 66 +++ .../andinfo/src/main/cpp/vulkan/VkSession.h | 31 ++ .../cpp/vulkan_wrapper/vulkan_wrapper.cpp | 215 +++++++++ .../main/cpp/vulkan_wrapper/vulkan_wrapper.h | 227 +++++++++ .../main/java/com/xyzshell/andinfo/AndInfo.kt | 48 +- .../com/xyzshell/andinfo/libs/BuildInfo.kt | 111 +++++ .../com/xyzshell/andinfo/libs/DeviceInfo.kt | 49 ++ .../com/xyzshell/andinfo/libs/DisplayInfo.kt | 64 +++ .../java/com/xyzshell/andinfo/libs/GpuInfo.kt | 49 ++ .../com/xyzshell/andinfo/libs/InputInfo.kt | 107 +++++ .../com/xyzshell/andinfo/libs/SensorInfo.kt | 86 ++++ .../andinfo/libs/gpu/models/EglInformation.kt | 9 + .../andinfo/libs/gpu/models/GlInformation.kt | 8 + .../andinfo/libs/gpu/models/VkApiVersion.kt | 49 ++ .../libs/gpu/models/VkPhysicalDevice.kt | 20 + .../libs/gpu/models/VkPhysicalDeviceType.kt | 14 + .../andinfo/libs/gpu/models/VkVendorId.kt | 17 + .../andinfo/libs/gpu/utils/EglUtils.kt | 62 +++ .../andinfo/libs/gpu/utils/VkUtils.kt | 35 ++ myphoneinfo/src/main/AndroidManifest.xml | 11 +- .../com/xyzshell/myphoneinfo/MainActivity.kt | 442 +++++++++++++++++- .../com/xyzshell/myphoneinfo/MyApplication.kt | 11 + 34 files changed, 2172 insertions(+), 42 deletions(-) create mode 100644 myphoneinfo/andinfo/src/main/cpp/EglUtils.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/VkUtils.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/egl/EglContext.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/egl/EglContext.h create mode 100644 myphoneinfo/andinfo/src/main/cpp/egl/EglSession.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/egl/EglSession.h create mode 100644 myphoneinfo/andinfo/src/main/cpp/jni_utils.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/logging.h create mode 100644 myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.h create mode 100644 myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.cpp create mode 100644 myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.h create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/BuildInfo.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DeviceInfo.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/InputInfo.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/SensorInfo.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/EglInformation.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/GlInformation.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkApiVersion.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDevice.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDeviceType.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkVendorId.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/EglUtils.kt create mode 100644 myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/VkUtils.kt create mode 100644 myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MyApplication.kt diff --git a/myphoneinfo/andinfo/build.gradle.kts b/myphoneinfo/andinfo/build.gradle.kts index 7e03f13..9aeed01 100644 --- a/myphoneinfo/andinfo/build.gradle.kts +++ b/myphoneinfo/andinfo/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { // implementation("androidx.datastore:datastore-preferences-rxjava3:1.1.7") implementation(libs.androidx.datastore) // implementation("androidx.datastore:datastore-rxjava3:1.1.7") + implementation("androidx.security:security-state:1.0.0-alpha04") testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/myphoneinfo/andinfo/src/main/cpp/CMakeLists.txt b/myphoneinfo/andinfo/src/main/cpp/CMakeLists.txt index d28ba81..e471048 100644 --- a/myphoneinfo/andinfo/src/main/cpp/CMakeLists.txt +++ b/myphoneinfo/andinfo/src/main/cpp/CMakeLists.txt @@ -6,9 +6,19 @@ add_subdirectory(cpuinfo) add_library(andinfo SHARED CpuInfoUtils.cpp - CpuJni.cpp) + CpuJni.cpp + jni_utils.cpp + EglUtils.cpp + VkUtils.cpp + egl/EglContext.cpp + egl/EglSession.cpp + vulkan/VkSession.cpp + vulkan_wrapper/vulkan_wrapper.cpp) target_link_libraries(andinfo android log - cpuinfo) + cpuinfo + GLESv2 + EGL + vulkan) diff --git a/myphoneinfo/andinfo/src/main/cpp/CpuJni.h b/myphoneinfo/andinfo/src/main/cpp/CpuJni.h index 75f69f3..e5482c0 100644 --- a/myphoneinfo/andinfo/src/main/cpp/CpuJni.h +++ b/myphoneinfo/andinfo/src/main/cpp/CpuJni.h @@ -31,19 +31,19 @@ DECLARE_CPU_CLASS(Cache, "IIIIIIII") -DECLARE_CPU_CLASS(Cluster, "IIIII" CPU_CLASS_SIG(Package) "IIIIJ") +DECLARE_CPU_CLASS(Cluster, "IIIII" "L" CPU_PACKAGE "/Package;" "IIIIJ") -DECLARE_CPU_CLASS(Core, "III" CPU_CLASS_SIG(Cluster) CPU_CLASS_SIG(Package) "IIIIJ") +DECLARE_CPU_CLASS(Core, "III" "L" CPU_PACKAGE "/Cluster;" "L" CPU_PACKAGE "/Package;" "IIIIJ") DECLARE_CPU_CLASS(Package, STRING_CLASS_SIG "IIIIII") DECLARE_CPU_CLASS(Processor, - "I" CPU_CLASS_SIG(Core) CPU_CLASS_SIG(Cluster) CPU_CLASS_SIG( - Package) "II" CPU_CLASS_SIG(ProcessorCache)) + "I" "L" CPU_PACKAGE "/Core;" "L" CPU_PACKAGE "/Cluster;" "L" CPU_PACKAGE + "/Package;" "II" "L" CPU_PACKAGE "/ProcessorCache;") DECLARE_CPU_CLASS(ProcessorCache, - CPU_CLASS_SIG(Cache) CPU_CLASS_SIG(Cache) CPU_CLASS_SIG(Cache) CPU_CLASS_SIG( - Cache) CPU_CLASS_SIG(Cache)) + "L" CPU_PACKAGE "/Cache;" "L" CPU_PACKAGE "/Cache;" "L" CPU_PACKAGE + "/Cache;" "L" CPU_PACKAGE "/Cache;" "L" CPU_PACKAGE "/Cache;") DECLARE_CPU_CLASS(Tlb, "IIJ") diff --git a/myphoneinfo/andinfo/src/main/cpp/EglUtils.cpp b/myphoneinfo/andinfo/src/main/cpp/EglUtils.cpp new file mode 100644 index 0000000..f56d215 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/EglUtils.cpp @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_TAG "EglUtils" + +#include +#include "jni_utils.h" +#include "logging.h" +#include "egl/EglSession.h" + +static const EGLint kConfigAttribs[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE +}; + +static const EGLint kContextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE +}; + +static void +maybeAddGlInformation(JNIEnv *env, EglSession &eglSession, jobject eglInformationBuilder) { + jclass eglInformationBuilderClass = withJniCheck(env, [=]() { + return env->FindClass("com/xyzshell/andinfo/libs/gpu/models/EglInformation$Builder"); + }); + + auto eglInformationAddGlInformationMethodId = withJniCheck(env, [=]() { + return env->GetMethodID( + eglInformationBuilderClass, + "addGlInformation", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + }); + + // Choose a configuration + auto eglConfig = eglSession.eglChooseConfig(kConfigAttribs); + if (!eglConfig) { + LOGE("Failed to choose EGL config"); + return; + } + + // Create a context + auto eglContext = eglSession.createEglContext(eglConfig.value(), kContextAttribs); + if (!eglContext) { + LOGE("Failed to create EGL context"); + return; + } + + // Make the context current + if (!eglSession.eglMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext->getContext())) { + LOGE("Failed to make EGL context current"); + return; + } + + auto glVendor = eglSession.glGetString(GL_VENDOR); + auto glRenderer = eglSession.glGetString(GL_RENDERER); + auto glVersion = eglSession.glGetString(GL_VERSION); + auto glExtensions = eglSession.glGetString(GL_EXTENSIONS); + + withJniCheck(env, [=]() { + return env->CallVoidMethod( + eglInformationBuilder, eglInformationAddGlInformationMethodId, + glVendor ? env->NewStringUTF(glVendor) : nullptr, + glRenderer ? env->NewStringUTF(glRenderer) : nullptr, + glVersion ? env->NewStringUTF(glVersion) : nullptr, + glExtensions ? env->NewStringUTF(glExtensions) : nullptr); + }); + + // Cleanup the current context + eglSession.eglMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +extern "C" +jobject Java_com_xyzshell_andinfo_libs_gpu_utils_EglUtils_getEglInformation( + JNIEnv *env, jobject thiz) { + jclass eglInformationBuilderClass = withJniCheck(env, [=]() { + return env->FindClass("com/xyzshell/andinfo/libs/gpu/models/EglInformation$Builder"); + }); + + auto eglInformationBuilderConstructorMethodId = withJniCheck(env, [=]() { + return env->GetMethodID( + eglInformationBuilderClass, + "", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + }); + + auto eglInformationBuilderBuildMethodId = withJniCheck(env, [=]() { + return env->GetMethodID( + eglInformationBuilderClass, + "build", + "()Lcom/xyzshell/andinfo/libs/gpu/models/EglInformation;"); + }); + + auto eglSession = EglSession::create(); + if (!eglSession) { + LOGE("Failed to create EGL session"); + return nullptr; + } + + const char *eglVendor = eglSession->eglQueryString(EGL_VENDOR); + const char *eglVersion = eglSession->eglQueryString(EGL_VERSION); + const char *eglExtensions = eglSession->eglQueryString(EGL_EXTENSIONS); + const char *eglClientApi = eglSession->eglQueryString(EGL_CLIENT_APIS); + + auto eglInformationBuild = withJniCheck(env, [=]() { + return env->NewObject( + eglInformationBuilderClass, + eglInformationBuilderConstructorMethodId, + eglVendor ? env->NewStringUTF(eglVendor) : nullptr, + eglVersion ? env->NewStringUTF(eglVersion) : nullptr, + eglExtensions ? env->NewStringUTF(eglExtensions) : nullptr, + eglClientApi ? env->NewStringUTF(eglClientApi) : nullptr); + }); + + maybeAddGlInformation(env, *eglSession, eglInformationBuild); + + auto eglInformation = withJniCheck(env, [=]() { + return env->CallObjectMethod(eglInformationBuild, eglInformationBuilderBuildMethodId); + }); + + return eglInformation; +} diff --git a/myphoneinfo/andinfo/src/main/cpp/VkUtils.cpp b/myphoneinfo/andinfo/src/main/cpp/VkUtils.cpp new file mode 100644 index 0000000..3fb37ba --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/VkUtils.cpp @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_TAG "VkUtils" + +#include +#include +#include "vulkan/VkSession.h" +#include "jni_utils.h" +#include "logging.h" + +static const std::vector kRequiredExtensions = { + "VK_KHR_surface", + "VK_KHR_android_surface" +}; + +extern "C" +JNIEXPORT jobject JNICALL +Java_com_xyzshell_andinfo_libs_gpu_utils_VkUtils_getVkInfo( + JNIEnv *env, jobject thiz) { + jclass vkPhysicalDevicesClass = withJniCheck(env, [=]() { + return env->FindClass("com/xyzshell/andinfo/libs/gpu/utils/VkUtils$VkPhysicalDevices"); + }); + auto vkPhysicalDevicesConstructorMethodId = withJniCheck(env, [=]() { + return env->GetMethodID(vkPhysicalDevicesClass, "", "()V"); + }); + auto addDeviceMethodId = withJniCheck(env, [=]() { + return env->GetMethodID( + vkPhysicalDevicesClass, + "addDevice", + "(JJJJJLjava/lang/String;)Z"); + }); + + VkApplicationInfo appInfo{ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "AndInfo", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "No Engine", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_0, + }; + + VkInstanceCreateInfo createInfo{ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &appInfo, + .enabledLayerCount = 0, + .enabledExtensionCount = (uint32_t) kRequiredExtensions.size(), + .ppEnabledExtensionNames = kRequiredExtensions.data(), + }; + + auto vkSession = VkSession::create(&createInfo, nullptr); + if (!vkSession) { + LOGE("Failed to create Vulkan session"); + return nullptr; + } + + auto physicalDevices = vkSession->vkEnumeratePhysicalDevices(); + + auto vkPhysicalDevices = env->NewObject(vkPhysicalDevicesClass, + vkPhysicalDevicesConstructorMethodId); + + for (const auto &device: physicalDevices) { + auto deviceProperties = vkSession->vkGetPhysicalDeviceProperties(device); + + withJniCheck(env, [=]() { + return env->CallBooleanMethod( + vkPhysicalDevices, addDeviceMethodId, + static_cast(deviceProperties.apiVersion), + static_cast(deviceProperties.driverVersion), + static_cast(deviceProperties.vendorID), + static_cast(deviceProperties.deviceID), + static_cast(deviceProperties.deviceType), + env->NewStringUTF(deviceProperties.deviceName)); + }); + } + + return vkPhysicalDevices; +} diff --git a/myphoneinfo/andinfo/src/main/cpp/egl/EglContext.cpp b/myphoneinfo/andinfo/src/main/cpp/egl/EglContext.cpp new file mode 100644 index 0000000..b6dcc5d --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/egl/EglContext.cpp @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "EglContext.h" + +#include + +EglContext::EglContext(EGLDisplay eglDisplay, EGLConfig config, const EGLint *attribList) { + mEglDisplay = eglDisplay; + mEglContext = ::eglCreateContext(eglDisplay, config, EGL_NO_CONTEXT, attribList); + if (mEglContext == EGL_NO_CONTEXT) { + throw std::runtime_error("Failed to create EGL context"); + } +} + +EglContext::~EglContext() { + ::eglDestroyContext(mEglDisplay, mEglContext); +} + +EGLContext EglContext::getContext() { + return mEglContext; +} + +std::unique_ptr +EglContext::create(EGLDisplay eglDisplay, EGLConfig config, const EGLint *attribList) { + try { + return std::unique_ptr(new EglContext(eglDisplay, config, attribList)); + } catch (...) { + return nullptr; + } +} diff --git a/myphoneinfo/andinfo/src/main/cpp/egl/EglContext.h b/myphoneinfo/andinfo/src/main/cpp/egl/EglContext.h new file mode 100644 index 0000000..0d4cfd1 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/egl/EglContext.h @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +class EglContext { +public: + EglContext(const EglContext &) = delete; + + ~EglContext(); + + EglContext &operator=(const EglContext &) = delete; + + EGLContext getContext(); + + static std::unique_ptr + create(EGLDisplay eglDisplay, EGLConfig config, const EGLint *attribList); + +private: + EglContext(EGLDisplay eglDisplay, EGLConfig config, const EGLint *attribList); + + EGLDisplay mEglDisplay; + EGLContext mEglContext; +}; diff --git a/myphoneinfo/andinfo/src/main/cpp/egl/EglSession.cpp b/myphoneinfo/andinfo/src/main/cpp/egl/EglSession.cpp new file mode 100644 index 0000000..ffae140 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/egl/EglSession.cpp @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_TAG "EglSession" + +#include +#include "EglSession.h" +#include "../logging.h" + +EglSession::EglSession() { + mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mDisplay == EGL_NO_DISPLAY) { + throw std::runtime_error("Failed to get EGL display"); + } + + if (!eglInitialize(mDisplay, &major, &minor)) { + throw std::runtime_error("Failed to initialize EGL"); + } +} + +EglSession::~EglSession() { + eglTerminate(mDisplay); +} + +const char *EglSession::eglQueryString(EGLint name) { + return ::eglQueryString(mDisplay, name); +} + +std::optional +EglSession::eglChooseConfig(const EGLint *attribList) { + EGLConfig config; + EGLint numConfigs; + if (!::eglChooseConfig(mDisplay, attribList, &config, 1, &numConfigs)) { + return nullptr; + } + + return config; +} + +std::unique_ptr +EglSession::createEglContext(EGLConfig config, const EGLint *attribList) { + try { + return EglContext::create(mDisplay, config, attribList); + } catch (std::runtime_error &error) { + LOGE("Failed to create EGL context: %s", error.what()); + return {}; + } +} + +bool EglSession::eglMakeCurrent(EGLSurface drawSurface, EGLSurface readSurface, + EGLContext context) { + return ::eglMakeCurrent(mDisplay, drawSurface, readSurface, context); +} + +const char *EglSession::glGetString(GLenum name) { + return reinterpret_cast(::glGetString(name)); +} + +std::unique_ptr EglSession::create() { + try { + return std::unique_ptr(new EglSession()); + } catch (...) { + return nullptr; + } +} diff --git a/myphoneinfo/andinfo/src/main/cpp/egl/EglSession.h b/myphoneinfo/andinfo/src/main/cpp/egl/EglSession.h new file mode 100644 index 0000000..f96eccc --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/egl/EglSession.h @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include +#include "EglContext.h" + +class EglSession { +public: + EglSession(const EglSession &) = delete; + + ~EglSession(); + + EglSession &operator=(const EglSession &) = delete; + + const char *eglQueryString(EGLint name); + + std::optional eglChooseConfig(const EGLint *attribList); + + std::unique_ptr + createEglContext(EGLConfig config, const EGLint *attribList); + + bool eglMakeCurrent(EGLSurface drawSurface, EGLSurface readSurface, EGLContext context); + + const char *glGetString(GLenum name); + + static std::unique_ptr create(); + +private: + EglSession(); + + EGLDisplay mDisplay = nullptr; + EGLint major = 0, minor = 0; +}; diff --git a/myphoneinfo/andinfo/src/main/cpp/jni_utils.cpp b/myphoneinfo/andinfo/src/main/cpp/jni_utils.cpp new file mode 100644 index 0000000..2774845 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/jni_utils.cpp @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "jni_utils.h" + +void withJniCheck(JNIEnv *env, const std::function &func) { + func(); + + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + throw std::runtime_error("JNI exception"); + } +} + +jmethodID getArrayListAddMethodID(JNIEnv *env, jobject object) { + jclass arrayListClazz = withJniCheck(env, [=]() { + return env->GetObjectClass(object); + }); + + auto methodID = withJniCheck(env, [=]() { + return env->GetMethodID( + arrayListClazz, + "add", + "(Ljava/lang/Object;)Z"); + }); + + return methodID; +} diff --git a/myphoneinfo/andinfo/src/main/cpp/jni_utils.h b/myphoneinfo/andinfo/src/main/cpp/jni_utils.h index e27cfce..d6e8860 100644 --- a/myphoneinfo/andinfo/src/main/cpp/jni_utils.h +++ b/myphoneinfo/andinfo/src/main/cpp/jni_utils.h @@ -5,26 +5,36 @@ #pragma once -#include +#include #include +#include // For std::runtime_error -#define JNI_CHECK(env) \ - do { \ - if (env->ExceptionCheck()) { \ - env->ExceptionDescribe(); \ - abort(); \ - } \ - } while (0) +// Helper for stringifying preprocessor macros +#define STRINGIFY_IMPL(x) #x +#define STRINGIFY(x) STRINGIFY_IMPL(x) -#define OBJECT_CLASS_SIG "Ljava/lang/Object;" -#define STRING_CLASS_SIG "Ljava/lang/String;" +#define JNI_CHECK(env) \ + if (env->ExceptionCheck()) { \ + env->ExceptionDescribe(); \ + env->ExceptionClear(); \ + throw std::runtime_error("JNI exception at " __FILE__ ":" STRINGIFY(__LINE__)); \ + } -static jmethodID getArrayListAddMethodID(JNIEnv *env, jobject object) { - auto arrayListClazz = env->GetObjectClass(object); - JNI_CHECK(env); +void withJniCheck(JNIEnv *env, const std::function &func); - auto methodID = env->GetMethodID(arrayListClazz, "add", "(" OBJECT_CLASS_SIG ")Z"); - JNI_CHECK(env); +template +T withJniCheck(JNIEnv *env, const std::function &func) { + T result = func(); - return methodID; + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + throw std::runtime_error("JNI exception"); + } + + return result; } + +jmethodID getArrayListAddMethodID(JNIEnv *env, jobject object); + +#define STRING_CLASS_SIG "Ljava/lang/String;" diff --git a/myphoneinfo/andinfo/src/main/cpp/logging.h b/myphoneinfo/andinfo/src/main/cpp/logging.h new file mode 100644 index 0000000..fea8be9 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/logging.h @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) diff --git a/myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.cpp b/myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.cpp new file mode 100644 index 0000000..57df7e1 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.cpp @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_TAG "VkSession" + +#include +#include "VkSession.h" +#include "../logging.h" + +VkSession::VkSession(const VkInstanceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator) { + if (!IsVulkanSupported()) { + throw std::runtime_error("Vulkan not supported"); + } + + if (vkCreateInstance(pCreateInfo, pAllocator, &mInstance) != VK_SUCCESS) { + throw std::runtime_error("Failed to create Vulkan instance"); + } +} + +VkSession::~VkSession() { + vkDestroyInstance(mInstance, nullptr); +} + +std::vector VkSession::vkEnumeratePhysicalDevices() { + VkResult result; + + uint32_t deviceCount = 0; + result = ::vkEnumeratePhysicalDevices(mInstance, &deviceCount, nullptr); + if (result != VK_SUCCESS) { + LOGE("Failed to enumerate Vulkan devices: %d", result); + return {}; + } + + if (deviceCount <= 0) { + LOGI("No Vulkan device found"); + return {}; + } + + std::vector devices(deviceCount); + result = ::vkEnumeratePhysicalDevices(mInstance, &deviceCount, devices.data()); + if (result != VK_SUCCESS) { + LOGE("Failed to enumerate Vulkan devices: %d", result); + return {}; + } + + return devices; +} + +VkPhysicalDeviceProperties VkSession::vkGetPhysicalDeviceProperties(VkPhysicalDevice device) { + VkPhysicalDeviceProperties properties; + ::vkGetPhysicalDeviceProperties(device, &properties); + return properties; +} + +std::unique_ptr VkSession::create(const VkInstanceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator) { + try { + return std::unique_ptr(new VkSession(pCreateInfo, pAllocator)); + } catch (std::runtime_error &error) { + LOGE("Failed to create Vulkan session: %s", error.what()); + return nullptr; + } +} diff --git a/myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.h b/myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.h new file mode 100644 index 0000000..99d4f29 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/vulkan/VkSession.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "../vulkan_wrapper/vulkan_wrapper.h" + +class VkSession { +public: + VkSession(const VkSession &) = delete; + + ~VkSession(); + + VkSession &operator=(const VkSession &) = delete; + + std::vector vkEnumeratePhysicalDevices(); + + static std::unique_ptr + create(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator); + + VkPhysicalDeviceProperties vkGetPhysicalDeviceProperties(VkPhysicalDevice device); + +private: + VkSession(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator); + + VkInstance mInstance = nullptr; +}; diff --git a/myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.cpp b/myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.cpp new file mode 100644 index 0000000..eb34b37 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.cpp @@ -0,0 +1,215 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +// This file is generated. + +#include "vulkan_wrapper.h" +#include + +/* + * Initialize the Vulkan function pointer variables declared in this header. + * Returns UNSUPPORTED if vulkan is not available, SUPPORTED if it is available. + */ +static VulkanWrapperStatus InitVulkan() { + void* libvulkan = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); + if (!libvulkan) { + return UNSUPPORTED; + } + + // Vulkan supported, set function addresses + vkCreateInstance = reinterpret_cast(dlsym(libvulkan, "vkCreateInstance")); + vkDestroyInstance = reinterpret_cast(dlsym(libvulkan, "vkDestroyInstance")); + vkEnumeratePhysicalDevices = reinterpret_cast(dlsym(libvulkan, "vkEnumeratePhysicalDevices")); + vkGetPhysicalDeviceFeatures = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceFeatures")); + vkGetPhysicalDeviceFormatProperties = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceFormatProperties")); + vkGetPhysicalDeviceImageFormatProperties = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceImageFormatProperties")); + vkGetPhysicalDeviceProperties = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceProperties")); + vkGetPhysicalDeviceQueueFamilyProperties = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceQueueFamilyProperties")); + vkGetPhysicalDeviceMemoryProperties = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceMemoryProperties")); + vkGetInstanceProcAddr = reinterpret_cast(dlsym(libvulkan, "vkGetInstanceProcAddr")); + vkGetDeviceProcAddr = reinterpret_cast(dlsym(libvulkan, "vkGetDeviceProcAddr")); + vkCreateDevice = reinterpret_cast(dlsym(libvulkan, "vkCreateDevice")); + vkDestroyDevice = reinterpret_cast(dlsym(libvulkan, "vkDestroyDevice")); + vkEnumerateInstanceExtensionProperties = reinterpret_cast(dlsym(libvulkan, "vkEnumerateInstanceExtensionProperties")); + vkEnumerateDeviceExtensionProperties = reinterpret_cast(dlsym(libvulkan, "vkEnumerateDeviceExtensionProperties")); + vkEnumerateInstanceLayerProperties = reinterpret_cast(dlsym(libvulkan, "vkEnumerateInstanceLayerProperties")); + vkEnumerateDeviceLayerProperties = reinterpret_cast(dlsym(libvulkan, "vkEnumerateDeviceLayerProperties")); + vkGetDeviceQueue = reinterpret_cast(dlsym(libvulkan, "vkGetDeviceQueue")); + vkQueueSubmit = reinterpret_cast(dlsym(libvulkan, "vkQueueSubmit")); + vkQueueWaitIdle = reinterpret_cast(dlsym(libvulkan, "vkQueueWaitIdle")); + vkDeviceWaitIdle = reinterpret_cast(dlsym(libvulkan, "vkDeviceWaitIdle")); + vkAllocateMemory = reinterpret_cast(dlsym(libvulkan, "vkAllocateMemory")); + vkFreeMemory = reinterpret_cast(dlsym(libvulkan, "vkFreeMemory")); + vkMapMemory = reinterpret_cast(dlsym(libvulkan, "vkMapMemory")); + vkUnmapMemory = reinterpret_cast(dlsym(libvulkan, "vkUnmapMemory")); + vkFlushMappedMemoryRanges = reinterpret_cast(dlsym(libvulkan, "vkFlushMappedMemoryRanges")); + vkInvalidateMappedMemoryRanges = reinterpret_cast(dlsym(libvulkan, "vkInvalidateMappedMemoryRanges")); + vkGetDeviceMemoryCommitment = reinterpret_cast(dlsym(libvulkan, "vkGetDeviceMemoryCommitment")); + vkBindBufferMemory = reinterpret_cast(dlsym(libvulkan, "vkBindBufferMemory")); + vkBindImageMemory = reinterpret_cast(dlsym(libvulkan, "vkBindImageMemory")); + vkGetBufferMemoryRequirements = reinterpret_cast(dlsym(libvulkan, "vkGetBufferMemoryRequirements")); + vkGetImageMemoryRequirements = reinterpret_cast(dlsym(libvulkan, "vkGetImageMemoryRequirements")); + vkGetImageSparseMemoryRequirements = reinterpret_cast(dlsym(libvulkan, "vkGetImageSparseMemoryRequirements")); + vkGetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceSparseImageFormatProperties")); + vkQueueBindSparse = reinterpret_cast(dlsym(libvulkan, "vkQueueBindSparse")); + vkCreateFence = reinterpret_cast(dlsym(libvulkan, "vkCreateFence")); + vkDestroyFence = reinterpret_cast(dlsym(libvulkan, "vkDestroyFence")); + vkResetFences = reinterpret_cast(dlsym(libvulkan, "vkResetFences")); + vkGetFenceStatus = reinterpret_cast(dlsym(libvulkan, "vkGetFenceStatus")); + vkWaitForFences = reinterpret_cast(dlsym(libvulkan, "vkWaitForFences")); + vkCreateSemaphore = reinterpret_cast(dlsym(libvulkan, "vkCreateSemaphore")); + vkDestroySemaphore = reinterpret_cast(dlsym(libvulkan, "vkDestroySemaphore")); + vkCreateEvent = reinterpret_cast(dlsym(libvulkan, "vkCreateEvent")); + vkDestroyEvent = reinterpret_cast(dlsym(libvulkan, "vkDestroyEvent")); + vkGetEventStatus = reinterpret_cast(dlsym(libvulkan, "vkGetEventStatus")); + vkSetEvent = reinterpret_cast(dlsym(libvulkan, "vkSetEvent")); + vkResetEvent = reinterpret_cast(dlsym(libvulkan, "vkResetEvent")); + vkCreateQueryPool = reinterpret_cast(dlsym(libvulkan, "vkCreateQueryPool")); + vkDestroyQueryPool = reinterpret_cast(dlsym(libvulkan, "vkDestroyQueryPool")); + vkGetQueryPoolResults = reinterpret_cast(dlsym(libvulkan, "vkGetQueryPoolResults")); + vkCreateBuffer = reinterpret_cast(dlsym(libvulkan, "vkCreateBuffer")); + vkDestroyBuffer = reinterpret_cast(dlsym(libvulkan, "vkDestroyBuffer")); + vkCreateBufferView = reinterpret_cast(dlsym(libvulkan, "vkCreateBufferView")); + vkDestroyBufferView = reinterpret_cast(dlsym(libvulkan, "vkDestroyBufferView")); + vkCreateImage = reinterpret_cast(dlsym(libvulkan, "vkCreateImage")); + vkDestroyImage = reinterpret_cast(dlsym(libvulkan, "vkDestroyImage")); + vkGetImageSubresourceLayout = reinterpret_cast(dlsym(libvulkan, "vkGetImageSubresourceLayout")); + vkCreateImageView = reinterpret_cast(dlsym(libvulkan, "vkCreateImageView")); + vkDestroyImageView = reinterpret_cast(dlsym(libvulkan, "vkDestroyImageView")); + vkCreateShaderModule = reinterpret_cast(dlsym(libvulkan, "vkCreateShaderModule")); + vkDestroyShaderModule = reinterpret_cast(dlsym(libvulkan, "vkDestroyShaderModule")); + vkCreatePipelineCache = reinterpret_cast(dlsym(libvulkan, "vkCreatePipelineCache")); + vkDestroyPipelineCache = reinterpret_cast(dlsym(libvulkan, "vkDestroyPipelineCache")); + vkGetPipelineCacheData = reinterpret_cast(dlsym(libvulkan, "vkGetPipelineCacheData")); + vkMergePipelineCaches = reinterpret_cast(dlsym(libvulkan, "vkMergePipelineCaches")); + vkCreateGraphicsPipelines = reinterpret_cast(dlsym(libvulkan, "vkCreateGraphicsPipelines")); + vkCreateComputePipelines = reinterpret_cast(dlsym(libvulkan, "vkCreateComputePipelines")); + vkDestroyPipeline = reinterpret_cast(dlsym(libvulkan, "vkDestroyPipeline")); + vkCreatePipelineLayout = reinterpret_cast(dlsym(libvulkan, "vkCreatePipelineLayout")); + vkDestroyPipelineLayout = reinterpret_cast(dlsym(libvulkan, "vkDestroyPipelineLayout")); + vkCreateSampler = reinterpret_cast(dlsym(libvulkan, "vkCreateSampler")); + vkDestroySampler = reinterpret_cast(dlsym(libvulkan, "vkDestroySampler")); + vkCreateDescriptorSetLayout = reinterpret_cast(dlsym(libvulkan, "vkCreateDescriptorSetLayout")); + vkDestroyDescriptorSetLayout = reinterpret_cast(dlsym(libvulkan, "vkDestroyDescriptorSetLayout")); + vkCreateDescriptorPool = reinterpret_cast(dlsym(libvulkan, "vkCreateDescriptorPool")); + vkDestroyDescriptorPool = reinterpret_cast(dlsym(libvulkan, "vkDestroyDescriptorPool")); + vkResetDescriptorPool = reinterpret_cast(dlsym(libvulkan, "vkResetDescriptorPool")); + vkAllocateDescriptorSets = reinterpret_cast(dlsym(libvulkan, "vkAllocateDescriptorSets")); + vkFreeDescriptorSets = reinterpret_cast(dlsym(libvulkan, "vkFreeDescriptorSets")); + vkUpdateDescriptorSets = reinterpret_cast(dlsym(libvulkan, "vkUpdateDescriptorSets")); + vkCreateFramebuffer = reinterpret_cast(dlsym(libvulkan, "vkCreateFramebuffer")); + vkDestroyFramebuffer = reinterpret_cast(dlsym(libvulkan, "vkDestroyFramebuffer")); + vkCreateRenderPass = reinterpret_cast(dlsym(libvulkan, "vkCreateRenderPass")); + vkDestroyRenderPass = reinterpret_cast(dlsym(libvulkan, "vkDestroyRenderPass")); + vkGetRenderAreaGranularity = reinterpret_cast(dlsym(libvulkan, "vkGetRenderAreaGranularity")); + vkCreateCommandPool = reinterpret_cast(dlsym(libvulkan, "vkCreateCommandPool")); + vkDestroyCommandPool = reinterpret_cast(dlsym(libvulkan, "vkDestroyCommandPool")); + vkResetCommandPool = reinterpret_cast(dlsym(libvulkan, "vkResetCommandPool")); + vkAllocateCommandBuffers = reinterpret_cast(dlsym(libvulkan, "vkAllocateCommandBuffers")); + vkFreeCommandBuffers = reinterpret_cast(dlsym(libvulkan, "vkFreeCommandBuffers")); + vkBeginCommandBuffer = reinterpret_cast(dlsym(libvulkan, "vkBeginCommandBuffer")); + vkEndCommandBuffer = reinterpret_cast(dlsym(libvulkan, "vkEndCommandBuffer")); + vkResetCommandBuffer = reinterpret_cast(dlsym(libvulkan, "vkResetCommandBuffer")); + vkCmdBindPipeline = reinterpret_cast(dlsym(libvulkan, "vkCmdBindPipeline")); + vkCmdSetViewport = reinterpret_cast(dlsym(libvulkan, "vkCmdSetViewport")); + vkCmdSetScissor = reinterpret_cast(dlsym(libvulkan, "vkCmdSetScissor")); + vkCmdSetLineWidth = reinterpret_cast(dlsym(libvulkan, "vkCmdSetLineWidth")); + vkCmdSetDepthBias = reinterpret_cast(dlsym(libvulkan, "vkCmdSetDepthBias")); + vkCmdSetBlendConstants = reinterpret_cast(dlsym(libvulkan, "vkCmdSetBlendConstants")); + vkCmdSetDepthBounds = reinterpret_cast(dlsym(libvulkan, "vkCmdSetDepthBounds")); + vkCmdSetStencilCompareMask = reinterpret_cast(dlsym(libvulkan, "vkCmdSetStencilCompareMask")); + vkCmdSetStencilWriteMask = reinterpret_cast(dlsym(libvulkan, "vkCmdSetStencilWriteMask")); + vkCmdSetStencilReference = reinterpret_cast(dlsym(libvulkan, "vkCmdSetStencilReference")); + vkCmdBindDescriptorSets = reinterpret_cast(dlsym(libvulkan, "vkCmdBindDescriptorSets")); + vkCmdBindIndexBuffer = reinterpret_cast(dlsym(libvulkan, "vkCmdBindIndexBuffer")); + vkCmdBindVertexBuffers = reinterpret_cast(dlsym(libvulkan, "vkCmdBindVertexBuffers")); + vkCmdDraw = reinterpret_cast(dlsym(libvulkan, "vkCmdDraw")); + vkCmdDrawIndexed = reinterpret_cast(dlsym(libvulkan, "vkCmdDrawIndexed")); + vkCmdDrawIndirect = reinterpret_cast(dlsym(libvulkan, "vkCmdDrawIndirect")); + vkCmdDrawIndexedIndirect = reinterpret_cast(dlsym(libvulkan, "vkCmdDrawIndexedIndirect")); + vkCmdDispatch = reinterpret_cast(dlsym(libvulkan, "vkCmdDispatch")); + vkCmdDispatchIndirect = reinterpret_cast(dlsym(libvulkan, "vkCmdDispatchIndirect")); + vkCmdCopyBuffer = reinterpret_cast(dlsym(libvulkan, "vkCmdCopyBuffer")); + vkCmdCopyImage = reinterpret_cast(dlsym(libvulkan, "vkCmdCopyImage")); + vkCmdBlitImage = reinterpret_cast(dlsym(libvulkan, "vkCmdBlitImage")); + vkCmdCopyBufferToImage = reinterpret_cast(dlsym(libvulkan, "vkCmdCopyBufferToImage")); + vkCmdCopyImageToBuffer = reinterpret_cast(dlsym(libvulkan, "vkCmdCopyImageToBuffer")); + vkCmdUpdateBuffer = reinterpret_cast(dlsym(libvulkan, "vkCmdUpdateBuffer")); + vkCmdFillBuffer = reinterpret_cast(dlsym(libvulkan, "vkCmdFillBuffer")); + vkCmdClearColorImage = reinterpret_cast(dlsym(libvulkan, "vkCmdClearColorImage")); + vkCmdClearDepthStencilImage = reinterpret_cast(dlsym(libvulkan, "vkCmdClearDepthStencilImage")); + vkCmdClearAttachments = reinterpret_cast(dlsym(libvulkan, "vkCmdClearAttachments")); + vkCmdResolveImage = reinterpret_cast(dlsym(libvulkan, "vkCmdResolveImage")); + vkCmdSetEvent = reinterpret_cast(dlsym(libvulkan, "vkCmdSetEvent")); + vkCmdResetEvent = reinterpret_cast(dlsym(libvulkan, "vkCmdResetEvent")); + vkCmdWaitEvents = reinterpret_cast(dlsym(libvulkan, "vkCmdWaitEvents")); + vkCmdPipelineBarrier = reinterpret_cast(dlsym(libvulkan, "vkCmdPipelineBarrier")); + vkCmdBeginQuery = reinterpret_cast(dlsym(libvulkan, "vkCmdBeginQuery")); + vkCmdEndQuery = reinterpret_cast(dlsym(libvulkan, "vkCmdEndQuery")); + vkCmdResetQueryPool = reinterpret_cast(dlsym(libvulkan, "vkCmdResetQueryPool")); + vkCmdWriteTimestamp = reinterpret_cast(dlsym(libvulkan, "vkCmdWriteTimestamp")); + vkCmdCopyQueryPoolResults = reinterpret_cast(dlsym(libvulkan, "vkCmdCopyQueryPoolResults")); + vkCmdPushConstants = reinterpret_cast(dlsym(libvulkan, "vkCmdPushConstants")); + vkCmdBeginRenderPass = reinterpret_cast(dlsym(libvulkan, "vkCmdBeginRenderPass")); + vkCmdNextSubpass = reinterpret_cast(dlsym(libvulkan, "vkCmdNextSubpass")); + vkCmdEndRenderPass = reinterpret_cast(dlsym(libvulkan, "vkCmdEndRenderPass")); + vkCmdExecuteCommands = reinterpret_cast(dlsym(libvulkan, "vkCmdExecuteCommands")); + vkDestroySurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkDestroySurfaceKHR")); + vkGetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceSurfaceSupportKHR")); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); + vkGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceSurfaceFormatsKHR")); + vkGetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceSurfacePresentModesKHR")); + vkCreateSwapchainKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateSwapchainKHR")); + vkDestroySwapchainKHR = reinterpret_cast(dlsym(libvulkan, "vkDestroySwapchainKHR")); + vkGetSwapchainImagesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetSwapchainImagesKHR")); + vkAcquireNextImageKHR = reinterpret_cast(dlsym(libvulkan, "vkAcquireNextImageKHR")); + vkQueuePresentKHR = reinterpret_cast(dlsym(libvulkan, "vkQueuePresentKHR")); + // vkGetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceDisplayPropertiesKHR")); + // vkGetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR")); + // vkGetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast(dlsym(libvulkan, "vkGetDisplayPlaneSupportedDisplaysKHR")); + // vkGetDisplayModePropertiesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetDisplayModePropertiesKHR")); + // vkCreateDisplayModeKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateDisplayModeKHR")); + // vkGetDisplayPlaneCapabilitiesKHR = reinterpret_cast(dlsym(libvulkan, "vkGetDisplayPlaneCapabilitiesKHR")); + // vkCreateDisplayPlaneSurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateDisplayPlaneSurfaceKHR")); + // vkCreateSharedSwapchainsKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateSharedSwapchainsKHR")); + +#ifdef VK_USE_PLATFORM_XLIB_KHR + // vkCreateXlibSurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateXlibSurfaceKHR")); + // vkGetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceXlibPresentationSupportKHR")); +#endif + +#ifdef VK_USE_PLATFORM_XCB_KHR + // vkCreateXcbSurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateXcbSurfaceKHR")); + // vkGetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceXcbPresentationSupportKHR")); +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + // vkCreateWaylandSurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateWaylandSurfaceKHR")); + // vkGetPhysicalDeviceWaylandPresentationSupportKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")); +#endif + +#ifdef VK_USE_PLATFORM_MIR_KHR + // vkCreateMirSurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateMirSurfaceKHR")); + // vkGetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceMirPresentationSupportKHR")); +#endif + +#ifdef VK_USE_PLATFORM_ANDROID_KHR + // vkCreateAndroidSurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateAndroidSurfaceKHR")); +#endif + +#ifdef VK_USE_PLATFORM_WIN32_KHR + // vkCreateWin32SurfaceKHR = reinterpret_cast(dlsym(libvulkan, "vkCreateWin32SurfaceKHR")); + // vkGetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast(dlsym(libvulkan, "vkGetPhysicalDeviceWin32PresentationSupportKHR")); +#endif +#ifdef USE_DEBUG_EXTENTIONS + vkCreateDebugReportCallbackEXT = reinterpret_cast(dlsym(libvulkan, "vkCreateDebugReportCallbackEXT")); + vkDestroyDebugReportCallbackEXT = reinterpret_cast(dlsym(libvulkan, "vkDestroyDebugReportCallbackEXT")); + vkDebugReportMessageEXT = reinterpret_cast(dlsym(libvulkan, "vkDebugReportMessageEXT")); +#endif + return SUPPORTED; +} + +bool IsVulkanSupported() { + return InitVulkan() == SUPPORTED; +} diff --git a/myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.h b/myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.h new file mode 100644 index 0000000..5b49408 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/cpp/vulkan_wrapper/vulkan_wrapper.h @@ -0,0 +1,227 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +// This file is generated. +#pragma once + +#define VK_NO_PROTOTYPES 1 +#include + +enum VulkanWrapperStatus { + UNSUPPORTED = 0, + SUPPORTED = 1, +}; + +/** + * Return whether Vulkan is supported in this system + */ +bool IsVulkanSupported(); + +// VK_core +extern PFN_vkCreateInstance vkCreateInstance; +extern PFN_vkDestroyInstance vkDestroyInstance; +extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; +extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; +extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; +extern PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties; +extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; +extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; +extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; +extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; +extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +extern PFN_vkCreateDevice vkCreateDevice; +extern PFN_vkDestroyDevice vkDestroyDevice; +extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; +extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; +extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; +extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties; +extern PFN_vkGetDeviceQueue vkGetDeviceQueue; +extern PFN_vkQueueSubmit vkQueueSubmit; +extern PFN_vkQueueWaitIdle vkQueueWaitIdle; +extern PFN_vkDeviceWaitIdle vkDeviceWaitIdle; +extern PFN_vkAllocateMemory vkAllocateMemory; +extern PFN_vkFreeMemory vkFreeMemory; +extern PFN_vkMapMemory vkMapMemory; +extern PFN_vkUnmapMemory vkUnmapMemory; +extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; +extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges; +extern PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment; +extern PFN_vkBindBufferMemory vkBindBufferMemory; +extern PFN_vkBindImageMemory vkBindImageMemory; +extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; +extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; +extern PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements; +extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties; +extern PFN_vkQueueBindSparse vkQueueBindSparse; +extern PFN_vkCreateFence vkCreateFence; +extern PFN_vkDestroyFence vkDestroyFence; +extern PFN_vkResetFences vkResetFences; +extern PFN_vkGetFenceStatus vkGetFenceStatus; +extern PFN_vkWaitForFences vkWaitForFences; +extern PFN_vkCreateSemaphore vkCreateSemaphore; +extern PFN_vkDestroySemaphore vkDestroySemaphore; +extern PFN_vkCreateEvent vkCreateEvent; +extern PFN_vkDestroyEvent vkDestroyEvent; +extern PFN_vkGetEventStatus vkGetEventStatus; +extern PFN_vkSetEvent vkSetEvent; +extern PFN_vkResetEvent vkResetEvent; +extern PFN_vkCreateQueryPool vkCreateQueryPool; +extern PFN_vkDestroyQueryPool vkDestroyQueryPool; +extern PFN_vkGetQueryPoolResults vkGetQueryPoolResults; +extern PFN_vkCreateBuffer vkCreateBuffer; +extern PFN_vkDestroyBuffer vkDestroyBuffer; +extern PFN_vkCreateBufferView vkCreateBufferView; +extern PFN_vkDestroyBufferView vkDestroyBufferView; +extern PFN_vkCreateImage vkCreateImage; +extern PFN_vkDestroyImage vkDestroyImage; +extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout; +extern PFN_vkCreateImageView vkCreateImageView; +extern PFN_vkDestroyImageView vkDestroyImageView; +extern PFN_vkCreateShaderModule vkCreateShaderModule; +extern PFN_vkDestroyShaderModule vkDestroyShaderModule; +extern PFN_vkCreatePipelineCache vkCreatePipelineCache; +extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache; +extern PFN_vkGetPipelineCacheData vkGetPipelineCacheData; +extern PFN_vkMergePipelineCaches vkMergePipelineCaches; +extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; +extern PFN_vkCreateComputePipelines vkCreateComputePipelines; +extern PFN_vkDestroyPipeline vkDestroyPipeline; +extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout; +extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; +extern PFN_vkCreateSampler vkCreateSampler; +extern PFN_vkDestroySampler vkDestroySampler; +extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; +extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; +extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool; +extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; +extern PFN_vkResetDescriptorPool vkResetDescriptorPool; +extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; +extern PFN_vkFreeDescriptorSets vkFreeDescriptorSets; +extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; +extern PFN_vkCreateFramebuffer vkCreateFramebuffer; +extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer; +extern PFN_vkCreateRenderPass vkCreateRenderPass; +extern PFN_vkDestroyRenderPass vkDestroyRenderPass; +extern PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity; +extern PFN_vkCreateCommandPool vkCreateCommandPool; +extern PFN_vkDestroyCommandPool vkDestroyCommandPool; +extern PFN_vkResetCommandPool vkResetCommandPool; +extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; +extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers; +extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer; +extern PFN_vkEndCommandBuffer vkEndCommandBuffer; +extern PFN_vkResetCommandBuffer vkResetCommandBuffer; +extern PFN_vkCmdBindPipeline vkCmdBindPipeline; +extern PFN_vkCmdSetViewport vkCmdSetViewport; +extern PFN_vkCmdSetScissor vkCmdSetScissor; +extern PFN_vkCmdSetLineWidth vkCmdSetLineWidth; +extern PFN_vkCmdSetDepthBias vkCmdSetDepthBias; +extern PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; +extern PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; +extern PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; +extern PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; +extern PFN_vkCmdSetStencilReference vkCmdSetStencilReference; +extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; +extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; +extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; +extern PFN_vkCmdDraw vkCmdDraw; +extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed; +extern PFN_vkCmdDrawIndirect vkCmdDrawIndirect; +extern PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect; +extern PFN_vkCmdDispatch vkCmdDispatch; +extern PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect; +extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; +extern PFN_vkCmdCopyImage vkCmdCopyImage; +extern PFN_vkCmdBlitImage vkCmdBlitImage; +extern PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; +extern PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; +extern PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer; +extern PFN_vkCmdFillBuffer vkCmdFillBuffer; +extern PFN_vkCmdClearColorImage vkCmdClearColorImage; +extern PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage; +extern PFN_vkCmdClearAttachments vkCmdClearAttachments; +extern PFN_vkCmdResolveImage vkCmdResolveImage; +extern PFN_vkCmdSetEvent vkCmdSetEvent; +extern PFN_vkCmdResetEvent vkCmdResetEvent; +extern PFN_vkCmdWaitEvents vkCmdWaitEvents; +extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; +extern PFN_vkCmdBeginQuery vkCmdBeginQuery; +extern PFN_vkCmdEndQuery vkCmdEndQuery; +extern PFN_vkCmdResetQueryPool vkCmdResetQueryPool; +extern PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp; +extern PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults; +extern PFN_vkCmdPushConstants vkCmdPushConstants; +extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; +extern PFN_vkCmdNextSubpass vkCmdNextSubpass; +extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass; +extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; + +// VK_KHR_surface +extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; +extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; +extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; +extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; +extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + +// VK_KHR_swapchain +extern PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; +extern PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; +extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; +extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; +extern PFN_vkQueuePresentKHR vkQueuePresentKHR; + +// VK_KHR_display +extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR; +extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR; +extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR; +extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR; +extern PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR; +extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR; +extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; + +// VK_KHR_display_swapchain +extern PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR; + +#ifdef VK_USE_PLATFORM_XLIB_KHR +// VK_KHR_xlib_surface +extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_XCB_KHR +// VK_KHR_xcb_surface +extern PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; +extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR +// VK_KHR_wayland_surface +extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR; +extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_MIR_KHR +// VK_KHR_mir_surface +extern PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR; +extern PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR; +#endif + +#ifdef VK_USE_PLATFORM_ANDROID_KHR +// VK_KHR_android_surface +extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; +#endif + +#ifdef VK_USE_PLATFORM_WIN32_KHR +// VK_KHR_win32_surface +extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR; +#endif + +#ifdef USE_DEBUG_EXTENTIONS +#include +// VK_EXT_debug_report +extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; +extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +extern PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT; +#endif diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt index ecb11b1..6ed81f2 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/AndInfo.kt @@ -1,24 +1,58 @@ package com.xyzshell.andinfo +import android.content.Context import com.xyzshell.andinfo.libs.CpuInfo +import com.xyzshell.andinfo.libs.DeviceInfo +import com.xyzshell.andinfo.libs.DisplayInfo +import com.xyzshell.andinfo.libs.SensorInfo +import com.xyzshell.andinfo.libs.BuildInfo +import com.xyzshell.andinfo.libs.GpuInfo +import com.xyzshell.andinfo.libs.InputInfo -class AndInfo private constructor() { +class AndInfo private constructor(private val applicationContext: Context) { companion object { - val instance = SingletonHolder.holder - } + private lateinit var INSTANCE: AndInfo - private object SingletonHolder { - val holder= AndInfo() + fun init(context: Context) { + INSTANCE = AndInfo(context.applicationContext) + } + + val instance: AndInfo + get() { + if (!::INSTANCE.isInitialized) { + throw IllegalStateException("AndInfo must be initialized with init(context) before use.") + } + return INSTANCE + } } private val _cpu: CpuInfo + private val _device: DeviceInfo + private val _display: DisplayInfo + private val _sensor: SensorInfo + private val _build: BuildInfo + private val _gpu: GpuInfo + private val _input: InputInfo + init { _cpu = CpuInfo() - + _device = DeviceInfo(applicationContext) + _display = DisplayInfo(applicationContext) + _sensor = SensorInfo(applicationContext) + _build = BuildInfo(applicationContext) + _gpu = GpuInfo(applicationContext) + _input = InputInfo(applicationContext) } val cpu get() = _cpu + val device get() = _device + val display get() = _display + val sensor get() = _sensor + val build get() = _build + val gpu get() = _gpu + val input get() = _input + val context get() = applicationContext -} \ No newline at end of file +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/BuildInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/BuildInfo.kt new file mode 100644 index 0000000..a36881f --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/BuildInfo.kt @@ -0,0 +1,111 @@ +package com.xyzshell.andinfo.libs + +import android.content.Context +import android.os.Build +// import androidx.security.state.SecurityStateManagerCompat +import java.util.Date + +class BuildInfo(private val context: Context) { + + // private val securityStateManager = SecurityStateManagerCompat(context) + // private val globalSecurityState = securityStateManager.getGlobalSecurityState() + + val fingerprint: String + get() = Build.FINGERPRINT + + val tags: String + get() = Build.TAGS + + val type: String + get() = Build.TYPE + + val buildDate: Date + get() = Date(Build.TIME) + + val host: String + get() = Build.HOST + + val user: String + get() = Build.USER + + val id: String + get() = Build.ID + + val display: String + get() = Build.DISPLAY + + val versionRelease: String + get() = Build.VERSION.RELEASE + + val versionCodename: String + get() = Build.VERSION.CODENAME + + val versionSdkInt: Int + get() = Build.VERSION.SDK_INT + + val versionPreviewSdkInt: Int + get() = Build.VERSION.PREVIEW_SDK_INT + + val securityPatch: String + get() = Build.VERSION.SECURITY_PATCH + + val baseOs: String + get() = Build.VERSION.BASE_OS + + val incremental: String + get() = Build.VERSION.INCREMENTAL + + val releaseOrCodename: String? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) Build.VERSION.RELEASE_OR_CODENAME else null + + val mediaPerformanceClass: Int + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Build.VERSION.MEDIA_PERFORMANCE_CLASS else 0 + + val releaseOrPreviewDisplay: String? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY else null + + val jvmName: String? + get() = System.getProperty("java.vm.name") + + val jvmVendor: String? + get() = System.getProperty("java.vm.vendor") + + val jvmVersion: String? + get() = System.getProperty("java.vm.version") + + val jvmClassVersion: String? + get() = System.getProperty("java.class.version") + + val jvmSpecificationName: String? + get() = System.getProperty("java.specification.name") + + val jvmSpecificationVendor: String? + get() = System.getProperty("java.specification.vendor") + + val jvmSpecificationVersion: String? + get() = System.getProperty("java.specification.version") + + val vendorSecurityPatchLevel: String? + get() = null // globalSecurityState.getString(SecurityStateManagerCompat.KEY_VENDOR_SPL) + + val kernelVersion: String? + get() = null // globalSecurityState.getString(SecurityStateManagerCompat.KEY_KERNEL_VERSION) + + val kernelCompleteVersion: String? + get() = System.getProperty("os.version") + + val bootloaderVersion: String + get() = Build.BOOTLOADER + + val radioVersion: String? + get() = Build.getRadioVersion() + + val fingerprintedPartitions: List + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Build.getFingerprintedPartitions().map { PartitionInfo(it.name, it.fingerprint) } + } else { + emptyList() + } + + data class PartitionInfo(val name: String, val fingerprint: String) +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DeviceInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DeviceInfo.kt new file mode 100644 index 0000000..74b114b --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DeviceInfo.kt @@ -0,0 +1,49 @@ +package com.xyzshell.andinfo.libs + +import android.app.ActivityManager +import android.content.Context +import android.os.Build + +class DeviceInfo(private val context: Context) { + + private val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + + val device: String + get() = Build.DEVICE + + val brand: String + get() = Build.BRAND + + val model: String + get() = Build.MODEL + + val manufacturer: String + get() = Build.MANUFACTURER + + val productName: String + get() = Build.PRODUCT + + val hardwareName: String + get() = Build.HARDWARE + + val boardName: String + get() = Build.BOARD + + val hardwareSku: String? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Build.SKU else null + + val odmSku: String? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Build.ODM_SKU else null + + val socManufacturer: String? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Build.SOC_MANUFACTURER else null + + val socModel: String? + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Build.SOC_MODEL else null + + fun getMemoryInfo(): ActivityManager.MemoryInfo { + val memoryInfo = ActivityManager.MemoryInfo() + activityManager.getMemoryInfo(memoryInfo) + return memoryInfo + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt new file mode 100644 index 0000000..ac76cf6 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt @@ -0,0 +1,64 @@ +package com.xyzshell.andinfo.libs + +import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Build +import android.view.Display +import android.graphics.Point +import android.util.DisplayMetrics + +class DisplayInfo(private val context: Context) { + + private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + + fun getDefaultDisplayInfo(): DefaultDisplayInfo? { + val defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY) ?: return null + + val displayMetrics = DisplayMetrics() + defaultDisplay.getMetrics(displayMetrics) + + val size = Point() + defaultDisplay.getSize(size) + + val mode = defaultDisplay.mode + val refreshRate = mode.refreshRate + + val isHdr = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + defaultDisplay.hdrCapabilities?.supportedHdrTypes?.isNotEmpty() ?: false + } else { + false + } + + val isWideColorGamut = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + defaultDisplay.isWideColorGamut + } else { + false + } + + return DefaultDisplayInfo( + id = defaultDisplay.displayId, + name = defaultDisplay.name, + widthPixels = displayMetrics.widthPixels, + heightPixels = displayMetrics.heightPixels, + densityDpi = displayMetrics.densityDpi, + xdpi = displayMetrics.xdpi, + ydpi = displayMetrics.ydpi, + refreshRate = refreshRate, + isHdr = isHdr, + isWideColorGamut = isWideColorGamut + ) + } + + data class DefaultDisplayInfo( + val id: Int, + val name: String, + val widthPixels: Int, + val heightPixels: Int, + val densityDpi: Int, + val xdpi: Float, + val ydpi: Float, + val refreshRate: Float, + val isHdr: Boolean, + val isWideColorGamut: Boolean + ) +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt new file mode 100644 index 0000000..4e9b90f --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt @@ -0,0 +1,49 @@ +package com.xyzshell.andinfo.libs + +import android.content.Context +import com.xyzshell.andinfo.libs.gpu.models.EglInformation +import com.xyzshell.andinfo.libs.gpu.models.GlInformation +import com.xyzshell.andinfo.libs.gpu.models.VkPhysicalDevice +import com.xyzshell.andinfo.libs.gpu.models.VkPhysicalDeviceType +import com.xyzshell.andinfo.libs.gpu.models.VkVendorId +import com.xyzshell.andinfo.libs.gpu.utils.EglUtils +import com.xyzshell.andinfo.libs.gpu.utils.VkUtils + +class GpuInfo(private val context: Context) { + + init { + System.loadLibrary("andinfo") + } + + fun getGpuInformation(): GpuInformationData { + val vkPhysicalDevices = VkUtils.getVkInfo() + val eglInformation = EglUtils.getEglInformation() + return GpuInformationData(vkPhysicalDevices, eglInformation) + } + + data class GpuInformationData( + val vkPhysicalDevices: List?, + val eglInformation: EglInformation? + ) + + companion object { + val vkPhysicalDeviceTypeToString = mapOf( + VkPhysicalDeviceType.OTHER.value to "Other", + VkPhysicalDeviceType.INTEGRATED_GPU.value to "Integrated GPU", + VkPhysicalDeviceType.DISCRETE_GPU.value to "Discrete GPU", + VkPhysicalDeviceType.VIRTUAL_GPU.value to "Virtual GPU", + VkPhysicalDeviceType.CPU.value to "CPU", + ) + + val vkVendorIdToString = mapOf( + VkVendorId.KHRONOS to "Khronos", + VkVendorId.VIV to "Vivante", + VkVendorId.VSI to "VeriSilicon", + VkVendorId.KAZAN to "Kazan", + VkVendorId.CODEPLAY to "Codeplay", + VkVendorId.MESA to "Mesa", + VkVendorId.POCL to "POCL", + VkVendorId.MOBILEYE to "Mobileye", + ) + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/InputInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/InputInfo.kt new file mode 100644 index 0000000..7a1685e --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/InputInfo.kt @@ -0,0 +1,107 @@ +package com.xyzshell.andinfo.libs + +import android.content.Context +import android.hardware.input.InputManager +import android.os.Build +import android.view.InputDevice +import android.view.KeyCharacterMap +import androidx.annotation.RequiresApi + +class InputInfo(private val context: Context) { + private val inputManager = context.getSystemService(InputManager::class.java) + + fun getInputDevices(): List { + return inputManager.inputDeviceIds.toList().mapNotNull { id -> + inputManager.getInputDevice(id)?.let { device -> InputDeviceInfo(device) } + } + } + + fun getInputDevice(deviceId: Int): InputDeviceInfo? { + return inputManager.getInputDevice(deviceId)?.let { device -> + InputDeviceInfo(device) + } + } + + @RequiresApi(Build.VERSION_CODES.S) + fun getMaximumObscuringOpacityForTouch(): Float { + return inputManager.maximumObscuringOpacityForTouch + } + + @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + fun isStylusPointerIconEnabled(): Boolean { + return inputManager.isStylusPointerIconEnabled + } + + data class InputDeviceInfo(val inputDevice: InputDevice) { + val id: Int get() = inputDevice.id + val controllerNumber: Int get() = inputDevice.controllerNumber + val vendorId: Int get() = inputDevice.vendorId + val productId: Int get() = inputDevice.productId + val descriptor: String? get() = inputDevice.descriptor + val isVirtual: Boolean get() = inputDevice.isVirtual + val isExternal: Boolean + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + inputDevice.isExternal + } else { + false + } + val name: String get() = inputDevice.name + val sources: Int get() = inputDevice.sources + val keyboardType: Int get() = inputDevice.keyboardType + val keyCharacterMapKeyboardType: Int get() = inputDevice.keyCharacterMap.keyboardType + val motionRangesCount: Int get() = inputDevice.motionRanges.size + val hasVibrator: Boolean + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + inputDevice.vibratorManager.vibratorIds.isNotEmpty() + } else { + @Suppress("DEPRECATION") + inputDevice.vibrator.hasVibrator() + } + val isEnabled: Boolean + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { + inputDevice.isEnabled + } else { + true + } + val hasMicrophone: Boolean get() = inputDevice.hasMicrophone() + + companion object { + val keyboardTypeToString = mapOf( + InputDevice.KEYBOARD_TYPE_NONE to "None", + InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC to "Non-alphabetic", + InputDevice.KEYBOARD_TYPE_ALPHABETIC to "Alphabetic", + ) + + val keyCharacterMapKeyboardTypeToString = mapOf( + KeyCharacterMap.NUMERIC to "Numeric", + KeyCharacterMap.PREDICTIVE to "Predictive", + KeyCharacterMap.ALPHA to "Alpha", + KeyCharacterMap.FULL to "Full", + KeyCharacterMap.SPECIAL_FUNCTION to "Special Function", + ) + + val sourceClassToString = mapOf( + InputDevice.SOURCE_CLASS_BUTTON to "Button", + InputDevice.SOURCE_CLASS_POINTER to "Pointer", + InputDevice.SOURCE_CLASS_TRACKBALL to "Trackball", + InputDevice.SOURCE_CLASS_POSITION to "Position", + InputDevice.SOURCE_CLASS_JOYSTICK to "Joystick", + ) + + val sourceToString = mapOf( + InputDevice.SOURCE_KEYBOARD to "Keyboard", + InputDevice.SOURCE_DPAD to "D-Pad", + InputDevice.SOURCE_GAMEPAD to "Gamepad", + InputDevice.SOURCE_TOUCHSCREEN to "Touchscreen", + InputDevice.SOURCE_MOUSE to "Mouse", + InputDevice.SOURCE_STYLUS to "Stylus", + InputDevice.SOURCE_TRACKBALL to "Trackball", + InputDevice.SOURCE_TOUCHPAD to "Touchpad", + InputDevice.SOURCE_TOUCH_NAVIGATION to "Touch Navigation", + InputDevice.SOURCE_ROTARY_ENCODER to "Rotary Encoder", + InputDevice.SOURCE_JOYSTICK to "Joystick", + InputDevice.SOURCE_HDMI to "HDMI", + ) + } + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/SensorInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/SensorInfo.kt new file mode 100644 index 0000000..f79a836 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/SensorInfo.kt @@ -0,0 +1,86 @@ +package com.xyzshell.andinfo.libs + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorDirectChannel +import android.hardware.SensorManager +import android.os.Build +import androidx.annotation.RequiresApi + +class SensorInfo(private val context: Context) { + + private val sensorManager = context.getSystemService(SensorManager::class.java) + + fun getAllSensors(): List { + return sensorManager.getSensorList(Sensor.TYPE_ALL) + } + + fun getSensorDetail(sensor: Sensor): SensorDetail { + return SensorDetail( + name = sensor.name, + id = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) sensor.id.takeIf { it > 0 } else null, + stringType = sensor.stringType, + type = sensor.type, + vendor = sensor.vendor, + version = sensor.version, + isDynamicSensor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) sensor.isDynamicSensor else false, + isWakeUpSensor = sensor.isWakeUpSensor, + fifoMaxEventCount = sensor.fifoMaxEventCount, + fifoReservedEventCount = sensor.fifoReservedEventCount, + minDelay = sensor.minDelay, + maxDelay = sensor.maxDelay, + maximumRange = sensor.maximumRange, + power = sensor.power, + reportingMode = sensor.reportingMode, + resolution = sensor.resolution, + isAdditionalInfoSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) sensor.isAdditionalInfoSupported else false, + highestDirectReportRateLevel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) sensor.highestDirectReportRateLevel else SensorDirectChannel.RATE_STOP + ) + } + + fun isDynamicSensorDiscoverySupported(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + sensorManager.isDynamicSensorDiscoverySupported + } else { + false + } + } + + data class SensorDetail( + val name: String, + val id: Int?, + val stringType: String, + val type: Int, + val vendor: String, + val version: Int, + val isDynamicSensor: Boolean, + val isWakeUpSensor: Boolean, + val fifoMaxEventCount: Int, + val fifoReservedEventCount: Int, + val minDelay: Int, + val maxDelay: Int, + val maximumRange: Float, + val power: Float, + val reportingMode: Int, + val resolution: Float, + val isAdditionalInfoSupported: Boolean, + val highestDirectReportRateLevel: Int + ) + + companion object { + val sensorReportingModeToStringResId = mapOf( + Sensor.REPORTING_MODE_CONTINUOUS to "连续", + Sensor.REPORTING_MODE_ON_CHANGE to "变化时", + Sensor.REPORTING_MODE_ONE_SHOT to "单次", + Sensor.REPORTING_MODE_SPECIAL_TRIGGER to "特殊触发", + ) + + @RequiresApi(Build.VERSION_CODES.O) + val sensorDirectReportModeRatesToStringResId = mapOf( + SensorDirectChannel.RATE_STOP to "停止", + SensorDirectChannel.RATE_NORMAL to "正常", + SensorDirectChannel.RATE_FAST to "快速", + SensorDirectChannel.RATE_VERY_FAST to "非常快速", + ) + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/EglInformation.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/EglInformation.kt new file mode 100644 index 0000000..70d60fb --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/EglInformation.kt @@ -0,0 +1,9 @@ +package com.xyzshell.andinfo.libs.gpu.models + +data class EglInformation( + val eglVendor: String?, + val eglVersion: String?, + val eglExtensions: List?, + val eglClientApi: List?, + val glInformation: GlInformation?, +) diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/GlInformation.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/GlInformation.kt new file mode 100644 index 0000000..80418cc --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/GlInformation.kt @@ -0,0 +1,8 @@ +package com.xyzshell.andinfo.libs.gpu.models + +data class GlInformation( + val glVendor: String?, + val glRenderer: String?, + val glVersion: String?, + val glExtensions: String?, +) diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkApiVersion.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkApiVersion.kt new file mode 100644 index 0000000..5ce39c9 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkApiVersion.kt @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.xyzshell.andinfo.libs.gpu.models + +data class VkApiVersion( + /** + * Variant number. + */ + val variant: UInt, + /** + * Major version number. + */ + val major: UInt, + /** + * Minor version number. + */ + val minor: UInt, + + /** + * Patch version number. + */ + val patch: UInt, +) { + val version = 0UL + .or(variant.shl(29).toULong()) + .or(major.shl(22).toULong()) + .or(minor.shl(12).toULong()) + .or(patch.toULong()) + + companion object { + /** + * The variant is a 3-bit integer packed into bits 31-29. + * The major version is a 7-bit integer packed into bits 28-22. + * The minor version number is a 10-bit integer packed into bits 21-12. + * The patch version number is a 12-bit integer packed into bits 11-0. + */ + fun fromVersion(version: ULong): VkApiVersion { + val variant = version.shr(29).toUInt() + val major = version.shr(22).and(0x7FU).toUInt() + val minor = version.shr(12).and(0x3FFU).toUInt() + val patch = version.and(0xFFFU).toUInt() + + return VkApiVersion(variant, major, minor, patch) + } + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDevice.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDevice.kt new file mode 100644 index 0000000..fcaf8d7 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDevice.kt @@ -0,0 +1,20 @@ +package com.xyzshell.andinfo.libs.gpu.models + +data class VkPhysicalDevice( + val apiVersion: VkVersion, + val driverVersion: Int, + val vendorId: Int, + val registeredVendorId: VkVendorId?, + val deviceId: Int, + val deviceType: VkPhysicalDeviceType, + val deviceName: String, +) + +data class VkVersion( + val version: Int, +) { + val major: Int = (version shr 22) and 0x7F + val minor: Int = (version shr 12) and 0x3FF + val patch: Int = version and 0xFFF + val variant: Int = (version shr 29) and 0x7 +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDeviceType.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDeviceType.kt new file mode 100644 index 0000000..73b9b0a --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkPhysicalDeviceType.kt @@ -0,0 +1,14 @@ +package com.xyzshell.andinfo.libs.gpu.models + +enum class VkPhysicalDeviceType(val value: Int) { + OTHER(0), + INTEGRATED_GPU(1), + DISCRETE_GPU(2), + VIRTUAL_GPU(3), + CPU(4), + ; + + companion object { + fun fromValue(value: Int) = values().firstOrNull { it.value == value } + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkVendorId.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkVendorId.kt new file mode 100644 index 0000000..1ca96d6 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/models/VkVendorId.kt @@ -0,0 +1,17 @@ +package com.xyzshell.andinfo.libs.gpu.models + +enum class VkVendorId(val id: Int) { + KHRONOS(0x10001), + VIV(0x10002), + VSI(0x10003), + KAZAN(0x10004), + CODEPLAY(0x10005), + MESA(0x10006), + POCL(0x10007), + MOBILEYE(0x10008), + ; + + companion object { + fun fromId(id: Int) = values().firstOrNull { it.id == id } + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/EglUtils.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/EglUtils.kt new file mode 100644 index 0000000..33a5189 --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/EglUtils.kt @@ -0,0 +1,62 @@ +package com.xyzshell.andinfo.libs.gpu.utils + +import android.opengl.EGL14 +import android.opengl.GLES10 +import android.opengl.GLES20 +import android.opengl.GLES30 +import android.opengl.GLES31 +import android.opengl.GLES32 +import android.os.Build +import com.xyzshell.andinfo.libs.gpu.models.EglInformation +import com.xyzshell.andinfo.libs.gpu.models.GlInformation +import java.lang.reflect.Field + +object EglUtils { + fun getEglInformation(): EglInformation? { + val eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY) + + if (eglDisplay == EGL14.EGL_NO_DISPLAY) { + return null + } + + val version = IntArray(2) + if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { + return null + } + + val eglVendor = EGL14.eglQueryString(eglDisplay, EGL14.EGL_VENDOR) + val eglVersion = EGL14.eglQueryString(eglDisplay, EGL14.EGL_VERSION) + val eglExtensions = EGL14.eglQueryString(eglDisplay, EGL14.EGL_EXTENSIONS) + ?.split(" ") + ?.filter { it.isNotBlank() } + val eglClientApi = EGL14.eglQueryString(eglDisplay, EGL14.EGL_CLIENT_APIS) + ?.split(" ") + ?.filter { it.isNotBlank() } + + val glInformation = getGlInformation() + + EGL14.eglTerminate(eglDisplay) + + return EglInformation( + eglVendor, + eglVersion, + eglExtensions, + eglClientApi, + glInformation, + ) + } + + private fun getGlInformation(): GlInformation? { + val glVendor = GLES10.glGetString(GLES10.GL_VENDOR) + val glRenderer = GLES10.glGetString(GLES10.GL_RENDERER) + val glVersion = GLES10.glGetString(GLES10.GL_VERSION) + val glExtensions = GLES10.glGetString(GLES10.GL_EXTENSIONS) + + return GlInformation( + glVendor, + glRenderer, + glVersion, + glExtensions, + ) + } +} diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/VkUtils.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/VkUtils.kt new file mode 100644 index 0000000..d73115f --- /dev/null +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/gpu/utils/VkUtils.kt @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: Sebastiano Barezzi + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.xyzshell.andinfo.libs.gpu.utils + +import com.xyzshell.andinfo.libs.gpu.models.VkApiVersion +import com.xyzshell.andinfo.libs.gpu.models.VkPhysicalDevice +import com.xyzshell.andinfo.libs.gpu.models.VkVersion + +object VkUtils { + class VkPhysicalDevices : ArrayList() { + fun addDevice( + apiVersion: Long, + driverVersion: Long, + vendorId: Int, + deviceId: Int, + deviceType: Int, + deviceName: String, + ) = add( + VkPhysicalDevice( + apiVersion = VkVersion(apiVersion.toInt()), + driverVersion = driverVersion.toInt(), + vendorId = vendorId, + registeredVendorId = com.xyzshell.andinfo.libs.gpu.models.VkVendorId.fromId(vendorId), + deviceId = deviceId, + deviceType = com.xyzshell.andinfo.libs.gpu.models.VkPhysicalDeviceType.fromValue(deviceType) ?: com.xyzshell.andinfo.libs.gpu.models.VkPhysicalDeviceType.OTHER, + deviceName = deviceName, + ) + ) + } + + external fun getVkInfo(): VkPhysicalDevices? +} diff --git a/myphoneinfo/src/main/AndroidManifest.xml b/myphoneinfo/src/main/AndroidManifest.xml index 1145c8b..5473158 100644 --- a/myphoneinfo/src/main/AndroidManifest.xml +++ b/myphoneinfo/src/main/AndroidManifest.xml @@ -1,13 +1,18 @@ - + + + + android:theme="@style/Theme.MyAndriodInfo" + tools:replace="android:name"> - \ No newline at end of file + diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt index 62ebf11..69b87d6 100644 --- a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MainActivity.kt @@ -33,6 +33,37 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.xyzshell.myphoneinfo.ui.theme.MyAndriodInfoTheme import com.xyzshell.andinfo.AndInfo +import android.text.format.Formatter +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import android.hardware.Sensor +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ListItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.SheetState +import androidx.compose.material3.rememberStandardBottomSheetState +import androidx.compose.material3.BottomSheetScaffold +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberBottomSheetScaffoldState +import androidx.compose.material3.BottomSheetDefaults +import androidx.compose.material3.BottomSheetScaffoldState +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.rememberBottomSheetScaffoldState +import kotlinx.coroutines.launch +import androidx.compose.runtime.rememberCoroutineScope +import com.xyzshell.andinfo.libs.SensorInfo +import com.xyzshell.andinfo.libs.GpuInfo +import com.xyzshell.andinfo.libs.gpu.models.VkPhysicalDevice +import com.xyzshell.andinfo.libs.gpu.models.EglInformation +import androidx.compose.foundation.lazy.itemsIndexed +import android.os.Build +import com.xyzshell.andinfo.libs.InputInfo +import com.xyzshell.andinfo.libs.InputInfo.InputDeviceInfo +import androidx.compose.foundation.clickable class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -55,7 +86,16 @@ class MainActivity : ComponentActivity() { @Composable fun MainView(name: String, modifier: Modifier = Modifier) { - val showDialog = remember { mutableStateOf(false) } + var showCpuDialog by remember { mutableStateOf(false) } + var showDeviceDialog by remember { mutableStateOf(false) } + var showDisplayDialog by remember { mutableStateOf(false) } + var showSensorsDialog by remember { mutableStateOf(false) } + var selectedSensor by remember { mutableStateOf(null) } + var showBuildDialog by remember { mutableStateOf(false) } + var showGpuDialog by remember { mutableStateOf(false) } + var showInputDevicesDialog by remember { mutableStateOf(false) } + var selectedInputDevice by remember { mutableStateOf(null) } + Column (modifier){ Box(modifier = Modifier.fillMaxWidth()){ Text(text = name, Modifier.align(Alignment.Center)) @@ -63,28 +103,414 @@ fun MainView(name: String, modifier: Modifier = Modifier) { Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ Text("硬件:${AndInfo.instance.cpu.hardware()}") Text("核心数:${AndInfo.instance.cpu.cores.size}") - Button(onClick = {showDialog.value = true}) { Text("cpu") } + Button(onClick = { showCpuDialog = true }) { Text("CPU 详情") } + } + Spacer(modifier = Modifier.height(16.dp)) + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + val memoryInfo = AndInfo.instance.device.getMemoryInfo() + Text("设备型号:${AndInfo.instance.device.model}") + Text("制造商:${AndInfo.instance.device.manufacturer}") + Text("总内存:${Formatter.formatFileSize(AndInfo.instance.context, memoryInfo.totalMem)}") + Text("可用内存:${Formatter.formatFileSize(AndInfo.instance.context, memoryInfo.availMem)}") + Button(onClick = { showDeviceDialog = true }) { Text("设备详情") } + } + Spacer(modifier = Modifier.height(16.dp)) + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + val defaultDisplayInfo = AndInfo.instance.display.getDefaultDisplayInfo() + if (defaultDisplayInfo != null) { + Text("显示器名称:${defaultDisplayInfo.name}") + Text("分辨率:${defaultDisplayInfo.widthPixels}x${defaultDisplayInfo.heightPixels}") + Text("刷新率:${defaultDisplayInfo.refreshRate} Hz") + Button(onClick = { showDisplayDialog = true }) { Text("显示器详情") } + } else { + Text("无法获取显示器信息") + } + } + Spacer(modifier = Modifier.height(16.dp)) + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + val allSensors = AndInfo.instance.sensor.getAllSensors() + Text("传感器数量:${allSensors.size}") + Text("支持动态传感器发现:${AndInfo.instance.sensor.isDynamicSensorDiscoverySupported()}") + Button(onClick = { showSensorsDialog = true }) { Text("传感器列表") } + } + Spacer(modifier = Modifier.height(16.dp)) + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + Text("构建指纹:${AndInfo.instance.build.fingerprint}") + Text("构建类型:${AndInfo.instance.build.type}") + Text("Android 版本:${AndInfo.instance.build.versionRelease} (SDK ${AndInfo.instance.build.versionSdkInt})") + Button(onClick = { showBuildDialog = true }) { Text("构建详情") } + } + Spacer(modifier = Modifier.height(16.dp)) + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + val gpuInfo = AndInfo.instance.gpu.getGpuInformation() + Text("Vulkan 设备数量:${gpuInfo.vkPhysicalDevices?.size ?: 0}") + Text("EGL 信息可用:${gpuInfo.eglInformation != null}") + Button(onClick = { showGpuDialog = true }) { Text("GPU 详情") } + } + Spacer(modifier = Modifier.height(16.dp)) + Card(modifier= Modifier.fillMaxWidth().padding(10.dp)){ + val inputDevices = AndInfo.instance.input.getInputDevices() + Text("输入设备数量:${inputDevices.size}") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + Text("触摸最大遮蔽不透明度:${AndInfo.instance.input.getMaximumObscuringOpacityForTouch()}") + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + Text("手写笔指针图标启用:${AndInfo.instance.input.isStylusPointerIconEnabled()}") + } + Button(onClick = { showInputDevicesDialog = true }) { Text("输入设备列表") } } } - if (showDialog.value) { + + if (showCpuDialog) { AlertDialog( - onDismissRequest = { showDialog.value = false }, - title = { Text(text = "标题") }, + onDismissRequest = { showCpuDialog = false }, + title = { Text(text = "CPU 详情") }, text = { Text(text = AndInfo.instance.cpu.text()) }, confirmButton = { - TextButton(onClick = { showDialog.value = false }) { + TextButton(onClick = { showCpuDialog = false }) { Text("确认") } }, dismissButton = { - TextButton(onClick = { showDialog.value = false }) { + TextButton(onClick = { showCpuDialog = false }) { Text("取消") } } ) } -} + if (showDeviceDialog) { + val memoryInfo = AndInfo.instance.device.getMemoryInfo() + AlertDialog( + onDismissRequest = { showDeviceDialog = false }, + title = { Text(text = "设备详情") }, + text = { + Column { + Text("设备:${AndInfo.instance.device.device}") + Text("品牌:${AndInfo.instance.device.brand}") + Text("型号:${AndInfo.instance.device.model}") + Text("制造商:${AndInfo.instance.device.manufacturer}") + Text("产品名称:${AndInfo.instance.device.productName}") + Text("硬件名称:${AndInfo.instance.device.hardwareName}") + Text("主板名称:${AndInfo.instance.device.boardName}") + AndInfo.instance.device.hardwareSku?.let { Text("硬件 SKU:$it") } + AndInfo.instance.device.odmSku?.let { Text("ODM SKU:$it") } + AndInfo.instance.device.socManufacturer?.let { Text("SoC 制造商:$it") } + AndInfo.instance.device.socModel?.let { Text("SoC 型号:$it") } + Text("总内存:${Formatter.formatFileSize(AndInfo.instance.context, memoryInfo.totalMem)}") + Text("可用内存:${Formatter.formatFileSize(AndInfo.instance.context, memoryInfo.availMem)}") + Text("低内存阈值:${Formatter.formatFileSize(AndInfo.instance.context, memoryInfo.threshold)}") + Text("当前是否低内存:${memoryInfo.lowMemory}") + } + }, + confirmButton = { + TextButton(onClick = { showDeviceDialog = false }) { + Text("确认") + } + }, + dismissButton = { + TextButton(onClick = { showDeviceDialog = false }) { + Text("取消") + } + } + ) + } + + if (showDisplayDialog) { + val defaultDisplayInfo = AndInfo.instance.display.getDefaultDisplayInfo() + if (defaultDisplayInfo != null) { + AlertDialog( + onDismissRequest = { showDisplayDialog = false }, + title = { Text(text = "显示器详情") }, + text = { + Column { + Text("ID:${defaultDisplayInfo.id}") + Text("名称:${defaultDisplayInfo.name}") + Text("宽度 (像素):${defaultDisplayInfo.widthPixels}") + Text("高度 (像素):${defaultDisplayInfo.heightPixels}") + Text("密度 (DPI):${defaultDisplayInfo.densityDpi}") + Text("X DPI:${defaultDisplayInfo.xdpi}") + Text("Y DPI:${defaultDisplayInfo.ydpi}") + Text("刷新率:${defaultDisplayInfo.refreshRate} Hz") + Text("是否支持 HDR:${defaultDisplayInfo.isHdr}") + Text("是否支持广色域:${defaultDisplayInfo.isWideColorGamut}") + } + }, + confirmButton = { + TextButton(onClick = { showDisplayDialog = false }) { + Text("确认") + } + }, + dismissButton = { + TextButton(onClick = { showDisplayDialog = false }) { + Text("取消") + } + } + ) + } else { + AlertDialog( + onDismissRequest = { showDisplayDialog = false }, + title = { Text(text = "显示器详情") }, + text = { Text(text = "无法获取显示器信息") }, + confirmButton = { + TextButton(onClick = { showDisplayDialog = false }) { + Text("确认") + } + } + ) + } + } + + if (showSensorsDialog) { + val allSensors = AndInfo.instance.sensor.getAllSensors() + AlertDialog( + onDismissRequest = { showSensorsDialog = false }, + title = { Text(text = "传感器列表") }, + text = { + LazyColumn { + items(allSensors) { sensor -> + ListItem( + headlineContent = { Text(sensor.name) }, + supportingContent = { Text(sensor.stringType) }, + trailingContent = { Text(sensor.vendor) }, + modifier = Modifier.fillMaxWidth() + .clickable { + selectedSensor = sensor + showSensorsDialog = false + } + ) + } + } + }, + confirmButton = { + TextButton(onClick = { showSensorsDialog = false }) { + Text("确认") + } + } + ) + } + + selectedSensor?.let { sensor -> + val sensorDetail = AndInfo.instance.sensor.getSensorDetail(sensor) + AlertDialog( + onDismissRequest = { selectedSensor = null }, + title = { Text(text = sensorDetail.name) }, + text = { + Column { + Text("名称:${sensorDetail.name}") + sensorDetail.id?.let { Text("ID:$it") } + Text("字符串类型:${sensorDetail.stringType}") + Text("类型:${sensorDetail.type}") + Text("供应商:${sensorDetail.vendor}") + Text("版本:${sensorDetail.version}") + Text("是否动态传感器:${sensorDetail.isDynamicSensor}") + Text("是否唤醒传感器:${sensorDetail.isWakeUpSensor}") + Text("FIFO 最大事件数:${sensorDetail.fifoMaxEventCount}") + Text("FIFO 预留事件数:${sensorDetail.fifoReservedEventCount}") + Text("最小延迟:${sensorDetail.minDelay}") + Text("最大延迟:${sensorDetail.maxDelay}") + Text("最大量程:${sensorDetail.maximumRange}") + Text("功耗:${sensorDetail.power}") + Text("报告模式:${SensorInfo.sensorReportingModeToStringResId[sensorDetail.reportingMode] ?: sensorDetail.reportingMode.toString()}") + Text("分辨率:${sensorDetail.resolution}") + Text("是否支持附加信息:${sensorDetail.isAdditionalInfoSupported}") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Text("最高直接报告速率级别:${SensorInfo.sensorDirectReportModeRatesToStringResId[sensorDetail.highestDirectReportRateLevel] ?: sensorDetail.highestDirectReportRateLevel.toString()}") + } + } + }, + confirmButton = { + TextButton(onClick = { selectedSensor = null }) { + Text("确认") + } + } + ) + } + + if (showBuildDialog) { + val buildInfo = AndInfo.instance.build + AlertDialog( + onDismissRequest = { showBuildDialog = false }, + title = { Text(text = "构建详情") }, + text = { + LazyColumn { + item { Text("指纹:${buildInfo.fingerprint}") } + item { Text("标签:${buildInfo.tags}") } + item { Text("类型:${buildInfo.type}") } + item { Text("构建日期:${buildInfo.buildDate}") } + item { Text("主机:${buildInfo.host}") } + item { Text("用户:${buildInfo.user}") } + item { Text("ID:${buildInfo.id}") } + item { Text("显示:${buildInfo.display}") } + item { Text("版本发布:${buildInfo.versionRelease}") } + item { Text("版本代号:${buildInfo.versionCodename}") } + item { Text("SDK 版本:${buildInfo.versionSdkInt}") } + item { Text("预览 SDK 版本:${buildInfo.versionPreviewSdkInt}") } + item { Text("安全补丁:${buildInfo.securityPatch}") } + item { Text("基础操作系统:${buildInfo.baseOs}") } + item { Text("增量:${buildInfo.incremental}") } + buildInfo.releaseOrCodename?.let { item { Text("发布或代号:$it") } } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + item { Text("媒体性能类:${buildInfo.mediaPerformanceClass}") } + } + buildInfo.releaseOrPreviewDisplay?.let { item { Text("发布或预览显示:$it") } } + item { Spacer(modifier = Modifier.height(8.dp)) } + item { Text("JVM 名称:${buildInfo.jvmName}") } + item { Text("JVM 供应商:${buildInfo.jvmVendor}") } + item { Text("JVM 版本:${buildInfo.jvmVersion}") } + item { Text("JVM 类版本:${buildInfo.jvmClassVersion}") } + item { Text("JVM 规范名称:${buildInfo.jvmSpecificationName}") } + item { Text("JVM 规范供应商:${buildInfo.jvmSpecificationVendor}") } + item { Text("JVM 规范版本:${buildInfo.jvmSpecificationVersion}") } + item { Spacer(modifier = Modifier.height(8.dp)) } + buildInfo.vendorSecurityPatchLevel?.let { item { Text("供应商安全补丁级别:$it") } } + buildInfo.kernelVersion?.let { item { Text("内核版本:$it") } } + buildInfo.kernelCompleteVersion?.let { item { Text("内核完整版本:$it") } } + item { Spacer(modifier = Modifier.height(8.dp)) } + item { Text("引导加载程序版本:${buildInfo.bootloaderVersion}") } + buildInfo.radioVersion?.let { item { Text("无线电版本:$it") } } + if (buildInfo.fingerprintedPartitions.isNotEmpty()) { + item { Spacer(modifier = Modifier.height(8.dp)) } + item { Text("指纹分区:") } + items(buildInfo.fingerprintedPartitions) { partition -> + Text(" ${partition.name}: ${partition.fingerprint}") + } + } + } + }, + confirmButton = { + TextButton(onClick = { showBuildDialog = false }) { + Text("确认") + } + } + ) + } + + if (showGpuDialog) { + val gpuInfo = AndInfo.instance.gpu.getGpuInformation() + AlertDialog( + onDismissRequest = { showGpuDialog = false }, + title = { Text(text = "GPU 详情") }, + text = { + LazyColumn { + gpuInfo.vkPhysicalDevices?.let { devices -> + if (devices.isNotEmpty()) { + item { Text("Vulkan 物理设备:") } + itemsIndexed(devices) { index, vkPhysicalDevice -> + Column(modifier = Modifier.padding(start = 16.dp)) { + Text("设备 ${index + 1}:") + Text(" 名称: ${vkPhysicalDevice.deviceName}") + Text(" API 版本: ${vkPhysicalDevice.apiVersion.major}.${vkPhysicalDevice.apiVersion.minor}.${vkPhysicalDevice.apiVersion.patch}") + Text(" 驱动版本: ${vkPhysicalDevice.driverVersion}") + Text(" 供应商 ID: ${vkPhysicalDevice.vendorId}") + vkPhysicalDevice.registeredVendorId?.let { + Text(" 注册供应商 ID: ${GpuInfo.vkVendorIdToString[it] ?: it.toString()}") + } + Text(" 设备 ID: ${vkPhysicalDevice.deviceId}") + Text(" 设备类型: ${GpuInfo.vkPhysicalDeviceTypeToString[vkPhysicalDevice.deviceType.value] ?: vkPhysicalDevice.deviceType.toString()}") + } + } + } else { + item { Text("无 Vulkan 物理设备信息") } + } + } ?: run { + item { Text("无 Vulkan 物理设备信息") } + } + + gpuInfo.eglInformation?.let { eglInfo -> + item { Spacer(modifier = Modifier.height(8.dp)) } + item { Text("EGL 信息:") } + eglInfo.eglVendor?.let { item { Text(" 供应商: $it") } } + eglInfo.eglVersion?.let { item { Text(" 版本: $it") } } + eglInfo.eglExtensions?.let { + item { Text(" 扩展: ${it.joinToString()}") } + } + eglInfo.eglClientApi?.let { + item { Text(" 客户端 API: ${it.joinToString()}") } + } + + eglInfo.glInformation?.let { glInfo -> + item { Spacer(modifier = Modifier.height(8.dp)) } + item { Text("OpenGL ES 信息:") } + glInfo.glVendor?.let { item { Text(" 供应商: $it") } } + glInfo.glRenderer?.let { item { Text(" 渲染器: $it") } } + glInfo.glVersion?.let { item { Text(" 版本: $it") } } + glInfo.glExtensions?.let { item { Text(" 扩展: $it") } } + } + } ?: run { + item { Spacer(modifier = Modifier.height(8.dp)) } + item { Text("无 EGL 信息") } + } + } + }, + confirmButton = { + TextButton(onClick = { showGpuDialog = false }) { + Text("确认") + } + } + ) + } + + if (showInputDevicesDialog) { + val inputDevices = AndInfo.instance.input.getInputDevices() + AlertDialog( + onDismissRequest = { showInputDevicesDialog = false }, + title = { Text(text = "输入设备列表") }, + text = { + LazyColumn { + items(inputDevices) { inputDevice -> + ListItem( + headlineContent = { Text(inputDevice.name) }, + supportingContent = { Text("ID: ${inputDevice.id}, 供应商: ${inputDevice.vendorId}, 产品: ${inputDevice.productId}") }, + modifier = Modifier.fillMaxWidth() + .clickable { + selectedInputDevice = inputDevice + showInputDevicesDialog = false + } + ) + } + } + }, + confirmButton = { + TextButton(onClick = { showInputDevicesDialog = false }) { + Text("确认") + } + } + ) + } + + selectedInputDevice?.let { inputDevice -> + AlertDialog( + onDismissRequest = { selectedInputDevice = null }, + title = { Text(text = inputDevice.name) }, + text = { + LazyColumn { + item { Text("ID: ${inputDevice.id}") } + item { Text("控制器编号: ${inputDevice.controllerNumber}") } + item { Text("供应商 ID: ${inputDevice.vendorId}") } + item { Text("产品 ID: ${inputDevice.productId}") } + inputDevice.descriptor?.let { item { Text("描述符: $it") } } + item { Text("是否虚拟: ${inputDevice.isVirtual}") } + item { Text("是否外部: ${inputDevice.isExternal}") } + item { Text("名称: ${inputDevice.name}") } + item { Text("源类: ${InputInfo.InputDeviceInfo.sourceClassToString.filter { (key, _) -> (inputDevice.sources and key) == key }.values.joinToString()}") } + item { Text("源: ${InputInfo.InputDeviceInfo.sourceToString.filter { (key, _) -> (inputDevice.sources and key) == key }.values.joinToString()}") } + item { Text("键盘类型: ${InputInfo.InputDeviceInfo.keyboardTypeToString[inputDevice.keyboardType] ?: inputDevice.keyboardType.toString()}") } + item { Text("KeyCharacterMap 键盘类型: ${InputInfo.InputDeviceInfo.keyCharacterMapKeyboardTypeToString[inputDevice.keyCharacterMapKeyboardType] ?: inputDevice.keyCharacterMapKeyboardType.toString()}") } + item { Text("运动范围数量: ${inputDevice.motionRangesCount}") } + item { Text("有振动器: ${inputDevice.hasVibrator}") } + item { Text("已启用: ${inputDevice.isEnabled}") } + item { Text("有麦克风: ${inputDevice.hasMicrophone}") } + } + }, + confirmButton = { + TextButton(onClick = { selectedInputDevice = null }) { + Text("确认") + } + } + ) + } +} @Preview(showBackground = true) diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MyApplication.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MyApplication.kt new file mode 100644 index 0000000..b90c6df --- /dev/null +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/MyApplication.kt @@ -0,0 +1,11 @@ +package com.xyzshell.myphoneinfo + +import android.app.Application +import com.xyzshell.andinfo.AndInfo + +class MyApplication : Application() { + override fun onCreate() { + super.onCreate() + AndInfo.init(this) + } +}