| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Tester Core |
| * ---------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Android utilities. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuAndroidUtil.hpp" |
| |
| #include "deSTLUtil.hpp" |
| #include "deMath.h" |
| |
| #include <vector> |
| |
| namespace tcu |
| { |
| namespace Android |
| { |
| |
| using std::string; |
| using std::vector; |
| |
| namespace |
| { |
| |
| class ScopedJNIEnv |
| { |
| public: |
| ScopedJNIEnv(JavaVM *vm); |
| ~ScopedJNIEnv(void); |
| |
| JavaVM *getVM(void) const |
| { |
| return m_vm; |
| } |
| JNIEnv *getEnv(void) const |
| { |
| return m_env; |
| } |
| |
| private: |
| JavaVM *const m_vm; |
| JNIEnv *m_env; |
| bool m_detach; |
| }; |
| |
| ScopedJNIEnv::ScopedJNIEnv(JavaVM *vm) : m_vm(vm), m_env(DE_NULL), m_detach(false) |
| { |
| const int getEnvRes = m_vm->GetEnv((void **)&m_env, JNI_VERSION_1_6); |
| |
| if (getEnvRes == JNI_EDETACHED) |
| { |
| if (m_vm->AttachCurrentThread(&m_env, DE_NULL) != JNI_OK) |
| throw std::runtime_error("JNI AttachCurrentThread() failed"); |
| |
| m_detach = true; |
| } |
| else if (getEnvRes != JNI_OK) |
| throw std::runtime_error("JNI GetEnv() failed"); |
| |
| DE_ASSERT(m_env); |
| } |
| |
| ScopedJNIEnv::~ScopedJNIEnv(void) |
| { |
| if (m_detach) |
| m_vm->DetachCurrentThread(); |
| } |
| |
| class LocalRef |
| { |
| public: |
| LocalRef(JNIEnv *env, jobject ref); |
| ~LocalRef(void); |
| |
| jobject operator*(void) const |
| { |
| return m_ref; |
| } |
| operator bool(void) const |
| { |
| return !!m_ref; |
| } |
| |
| private: |
| LocalRef(const LocalRef &); |
| LocalRef &operator=(const LocalRef &); |
| |
| JNIEnv *const m_env; |
| const jobject m_ref; |
| }; |
| |
| LocalRef::LocalRef(JNIEnv *env, jobject ref) : m_env(env), m_ref(ref) |
| { |
| } |
| |
| LocalRef::~LocalRef(void) |
| { |
| if (m_ref) |
| m_env->DeleteLocalRef(m_ref); |
| } |
| |
| void checkException(JNIEnv *env) |
| { |
| if (env->ExceptionCheck()) |
| { |
| env->ExceptionDescribe(); |
| env->ExceptionClear(); |
| throw std::runtime_error("Got JNI exception"); |
| } |
| } |
| |
| jclass findClass(JNIEnv *env, const char *className) |
| { |
| const jclass cls = env->FindClass(className); |
| |
| checkException(env); |
| TCU_CHECK_INTERNAL(cls); |
| |
| return cls; |
| } |
| |
| jclass getObjectClass(JNIEnv *env, jobject object) |
| { |
| const jclass cls = env->GetObjectClass(object); |
| |
| checkException(env); |
| TCU_CHECK_INTERNAL(cls); |
| |
| return cls; |
| } |
| |
| jmethodID getMethodID(JNIEnv *env, jclass cls, const char *methodName, const char *signature) |
| { |
| const jmethodID id = env->GetMethodID(cls, methodName, signature); |
| |
| checkException(env); |
| TCU_CHECK_INTERNAL(id); |
| |
| return id; |
| } |
| |
| string getStringValue(JNIEnv *env, jstring jniStr) |
| { |
| const char *ptr = env->GetStringUTFChars(jniStr, DE_NULL); |
| const string str = string(ptr); |
| |
| env->ReleaseStringUTFChars(jniStr, ptr); |
| |
| return str; |
| } |
| |
| string getIntentStringExtra(JNIEnv *env, jobject activity, const char *name) |
| { |
| // \todo [2013-05-12 pyry] Clean up references on error. |
| |
| const jclass activityCls = getObjectClass(env, activity); |
| const LocalRef intent( |
| env, env->CallObjectMethod(activity, getMethodID(env, activityCls, "getIntent", "()Landroid/content/Intent;"))); |
| TCU_CHECK_INTERNAL(intent); |
| |
| const LocalRef extraName(env, env->NewStringUTF(name)); |
| const jclass intentCls = getObjectClass(env, *intent); |
| TCU_CHECK_INTERNAL(extraName && intentCls); |
| |
| jvalue getExtraArgs[1]; |
| getExtraArgs[0].l = *extraName; |
| |
| const LocalRef extraStr(env, env->CallObjectMethodA(*intent, |
| getMethodID(env, intentCls, "getStringExtra", |
| "(Ljava/lang/String;)Ljava/lang/String;"), |
| getExtraArgs)); |
| |
| if (extraStr) |
| return getStringValue(env, (jstring)*extraStr); |
| else |
| return string(); |
| } |
| |
| void setRequestedOrientation(JNIEnv *env, jobject activity, ScreenOrientation orientation) |
| { |
| const jclass activityCls = getObjectClass(env, activity); |
| const jmethodID setOrientationId = getMethodID(env, activityCls, "setRequestedOrientation", "(I)V"); |
| |
| env->CallVoidMethod(activity, setOrientationId, (int)orientation); |
| } |
| |
| template <typename Type> |
| const char *getJNITypeStr(void); |
| |
| template <> |
| const char *getJNITypeStr<int>(void) |
| { |
| return "I"; |
| } |
| |
| template <> |
| const char *getJNITypeStr<int64_t>(void) |
| { |
| return "J"; |
| } |
| |
| template <> |
| const char *getJNITypeStr<string>(void) |
| { |
| return "Ljava/lang/String;"; |
| } |
| |
| template <> |
| const char *getJNITypeStr<vector<string>>(void) |
| { |
| return "[Ljava/lang/String;"; |
| } |
| |
| template <typename FieldType> |
| FieldType getStaticFieldValue(JNIEnv *env, jclass cls, jfieldID fieldId); |
| |
| template <> |
| int getStaticFieldValue<int>(JNIEnv *env, jclass cls, jfieldID fieldId) |
| { |
| DE_ASSERT(cls && fieldId); |
| return env->GetStaticIntField(cls, fieldId); |
| } |
| |
| template <> |
| string getStaticFieldValue<string>(JNIEnv *env, jclass cls, jfieldID fieldId) |
| { |
| const jstring jniStr = (jstring)env->GetStaticObjectField(cls, fieldId); |
| |
| if (jniStr) |
| return getStringValue(env, jniStr); |
| else |
| return string(); |
| } |
| |
| template <> |
| vector<string> getStaticFieldValue<vector<string>>(JNIEnv *env, jclass cls, jfieldID fieldId) |
| { |
| const jobjectArray array = (jobjectArray)env->GetStaticObjectField(cls, fieldId); |
| vector<string> result; |
| |
| checkException(env); |
| |
| if (array) |
| { |
| const int numElements = env->GetArrayLength(array); |
| |
| for (int ndx = 0; ndx < numElements; ndx++) |
| { |
| const jstring jniStr = (jstring)env->GetObjectArrayElement(array, ndx); |
| |
| checkException(env); |
| |
| if (jniStr) |
| result.push_back(getStringValue(env, jniStr)); |
| } |
| } |
| |
| return result; |
| } |
| |
| template <typename FieldType> |
| FieldType getStaticField(JNIEnv *env, const char *className, const char *fieldName) |
| { |
| const jclass cls = findClass(env, className); |
| const jfieldID fieldId = env->GetStaticFieldID(cls, fieldName, getJNITypeStr<FieldType>()); |
| |
| checkException(env); |
| |
| if (fieldId) |
| return getStaticFieldValue<FieldType>(env, cls, fieldId); |
| else |
| throw std::runtime_error(string(fieldName) + " not found in " + className); |
| } |
| |
| template <typename FieldType> |
| FieldType getFieldValue(JNIEnv *env, jobject obj, jfieldID fieldId); |
| |
| template <> |
| int64_t getFieldValue<int64_t>(JNIEnv *env, jobject obj, jfieldID fieldId) |
| { |
| DE_ASSERT(obj && fieldId); |
| return env->GetLongField(obj, fieldId); |
| } |
| |
| template <typename FieldType> |
| FieldType getField(JNIEnv *env, jobject obj, const char *fieldName) |
| { |
| const jclass cls = getObjectClass(env, obj); |
| const jfieldID fieldId = env->GetFieldID(cls, fieldName, getJNITypeStr<FieldType>()); |
| |
| checkException(env); |
| |
| if (fieldId) |
| return getFieldValue<FieldType>(env, obj, fieldId); |
| else |
| throw std::runtime_error(string(fieldName) + " not found in object"); |
| } |
| |
| void describePlatform(JNIEnv *env, std::ostream &dst) |
| { |
| const char *const buildClass = "android/os/Build"; |
| const char *const versionClass = "android/os/Build$VERSION"; |
| |
| static const struct |
| { |
| const char *classPath; |
| const char *className; |
| const char *fieldName; |
| } s_stringFields[] = { |
| {buildClass, "Build", "BOARD"}, {buildClass, "Build", "BRAND"}, |
| {buildClass, "Build", "DEVICE"}, {buildClass, "Build", "DISPLAY"}, |
| {buildClass, "Build", "FINGERPRINT"}, {buildClass, "Build", "HARDWARE"}, |
| {buildClass, "Build", "MANUFACTURER"}, {buildClass, "Build", "MODEL"}, |
| {buildClass, "Build", "PRODUCT"}, {buildClass, "Build", "TAGS"}, |
| {buildClass, "Build", "TYPE"}, {versionClass, "Build.VERSION", "RELEASE"}, |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_stringFields); ndx++) |
| dst << s_stringFields[ndx].className << "." << s_stringFields[ndx].fieldName << ": " |
| << getStaticField<string>(env, s_stringFields[ndx].classPath, s_stringFields[ndx].fieldName) << "\n"; |
| |
| dst << "Build.VERSION.SDK_INT: " << getStaticField<int>(env, versionClass, "SDK_INT") << "\n"; |
| |
| { |
| const vector<string> supportedAbis = getStaticField<vector<string>>(env, buildClass, "SUPPORTED_ABIS"); |
| |
| dst << "Build.SUPPORTED_ABIS: "; |
| |
| for (size_t ndx = 0; ndx < supportedAbis.size(); ndx++) |
| dst << (ndx != 0 ? ", " : "") << supportedAbis[ndx]; |
| |
| dst << "\n"; |
| } |
| } |
| |
| } // namespace |
| |
| ScreenOrientation mapScreenRotation(ScreenRotation rotation) |
| { |
| switch (rotation) |
| { |
| case SCREENROTATION_UNSPECIFIED: |
| return SCREEN_ORIENTATION_UNSPECIFIED; |
| case SCREENROTATION_0: |
| return SCREEN_ORIENTATION_PORTRAIT; |
| case SCREENROTATION_90: |
| return SCREEN_ORIENTATION_LANDSCAPE; |
| case SCREENROTATION_180: |
| return SCREEN_ORIENTATION_REVERSE_PORTRAIT; |
| case SCREENROTATION_270: |
| return SCREEN_ORIENTATION_REVERSE_LANDSCAPE; |
| default: |
| print("Warning: Unsupported rotation"); |
| return SCREEN_ORIENTATION_PORTRAIT; |
| } |
| } |
| |
| string getIntentStringExtra(ANativeActivity *activity, const char *name) |
| { |
| const ScopedJNIEnv env(activity->vm); |
| |
| return getIntentStringExtra(env.getEnv(), activity->clazz, name); |
| } |
| |
| void setRequestedOrientation(ANativeActivity *activity, ScreenOrientation orientation) |
| { |
| const ScopedJNIEnv env(activity->vm); |
| |
| setRequestedOrientation(env.getEnv(), activity->clazz, orientation); |
| } |
| |
| void describePlatform(ANativeActivity *activity, std::ostream &dst) |
| { |
| const ScopedJNIEnv env(activity->vm); |
| |
| describePlatform(env.getEnv(), dst); |
| } |
| |
| size_t getTotalAndroidSystemMemory(ANativeActivity *activity) |
| { |
| const ScopedJNIEnv scopedJniEnv(activity->vm); |
| JNIEnv *env = scopedJniEnv.getEnv(); |
| |
| // Get activity manager instance: |
| // ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
| const jclass activityManagerClass = findClass(env, "android/app/ActivityManager"); |
| const LocalRef activityString(env, env->NewStringUTF("activity")); // Context.ACTIVITY_SERVICE == "activity" |
| const jclass activityClass = getObjectClass(env, activity->clazz); |
| const jmethodID getServiceID = |
| getMethodID(env, activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); |
| LocalRef activityManager(env, env->CallObjectMethod(activity->clazz, getServiceID, *activityString)); |
| checkException(env); |
| TCU_CHECK_INTERNAL(activityManager); |
| |
| // Crete memory info instance: |
| // ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); |
| const jclass memoryInfoClass = findClass(env, "android/app/ActivityManager$MemoryInfo"); |
| const jmethodID memoryInfoCtor = getMethodID(env, memoryInfoClass, "<init>", "()V"); |
| LocalRef memoryInfo(env, env->NewObject(memoryInfoClass, memoryInfoCtor)); |
| checkException(env); |
| TCU_CHECK_INTERNAL(memoryInfo); |
| |
| // Get memory info from activity manager: |
| // activityManager.getMemoryInfo(memoryInfo); |
| const jmethodID getMemoryInfoID = |
| getMethodID(env, activityManagerClass, "getMemoryInfo", "(Landroid/app/ActivityManager$MemoryInfo;)V"); |
| checkException(env); |
| env->CallVoidMethod(*activityManager, getMemoryInfoID, *memoryInfo); |
| |
| // Return 'totalMem' field from the memory info instance. |
| return static_cast<size_t>(getField<int64_t>(env, *memoryInfo, "totalMem")); |
| } |
| |
| } // namespace Android |
| } // namespace tcu |