blob: 3c09ce97b29d0745a5698b7c617d08af384885be [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 <vector>
namespace tcu
{
namespace Android
{
using std::string;
using std::vector;
void checkJNIException (JNIEnv* env)
{
if (env->ExceptionCheck())
{
env->ExceptionDescribe();
env->ExceptionClear();
throw std::runtime_error("Got JNI exception");
}
}
string getJNIStringValue (JNIEnv* env, jstring jniStr)
{
const char* ptr = env->GetStringUTFChars(jniStr, DE_NULL);
const string str = string(ptr);
env->ReleaseStringUTFChars(jniStr, ptr);
return str;
}
static string getIntentStringExtra (JNIEnv* env, jobject activity, const char* name)
{
// \todo [2013-05-12 pyry] Clean up references on error.
jclass activityCls = env->GetObjectClass(activity);
jobject intent = env->CallObjectMethod(activity, env->GetMethodID(activityCls, "getIntent", "()Landroid/content/Intent;"));
TCU_CHECK(intent);
jstring extraName = env->NewStringUTF(name);
jclass intentCls = env->GetObjectClass(intent);
TCU_CHECK(extraName && intentCls);
jvalue getExtraArgs[1];
getExtraArgs[0].l = extraName;
jstring extraStr = (jstring)env->CallObjectMethodA(intent, env->GetMethodID(intentCls, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"), getExtraArgs);
env->DeleteLocalRef(extraName);
if (extraStr)
return getJNIStringValue(env, extraStr);
else
return string();
}
string getIntentStringExtra (ANativeActivity* activity, const char* name)
{
return getIntentStringExtra(activity->env, activity->clazz, name);
}
static void setRequestedOrientation (JNIEnv* env, jobject activity, ScreenOrientation orientation)
{
jclass activityCls = env->GetObjectClass(activity);
jmethodID setOrientationId = env->GetMethodID(activityCls, "setRequestedOrientation", "(I)V");
env->CallVoidMethod(activity, setOrientationId, (int)orientation);
}
void setRequestedOrientation (ANativeActivity* activity, ScreenOrientation orientation)
{
setRequestedOrientation(activity->env, activity->clazz, orientation);
}
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;
}
}
template<typename Type>
const char* getJNITypeStr (void);
template<>
const char* getJNITypeStr<int> (void)
{
return "I";
}
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 getJNIStringValue(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;
checkJNIException(env);
if (array)
{
const int numElements = env->GetArrayLength(array);
for (int ndx = 0; ndx < numElements; ndx++)
{
const jstring jniStr = (jstring)env->GetObjectArrayElement(array, ndx);
checkJNIException(env);
if (jniStr)
result.push_back(getJNIStringValue(env, jniStr));
}
}
return result;
}
template<typename FieldType>
FieldType getStaticField (JNIEnv* env, const char* className, const char* fieldName)
{
const jclass cls = env->FindClass(className);
const jfieldID fieldId = cls ? env->GetStaticFieldID(cls, fieldName, getJNITypeStr<FieldType>()) : (jfieldID)0;
checkJNIException(env);
if (cls && fieldId)
return getStaticFieldValue<FieldType>(env, cls, fieldId);
else
return FieldType();
}
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();
}
void describePlatform (ANativeActivity* activity, std::ostream& dst)
{
const ScopedJNIEnv env (activity->vm);
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.getEnv(), s_stringFields[ndx].classPath, s_stringFields[ndx].fieldName)
<< "\n";
dst << "Build.VERSION.SDK_INT: " << getStaticField<int>(env.getEnv(), versionClass, "SDK_INT") << "\n";
{
const vector<string> supportedAbis = getStaticField<vector<string> >(env.getEnv(), buildClass, "SUPPORTED_ABIS");
dst << "Build.SUPPORTED_ABIS: ";
for (size_t ndx = 0; ndx < supportedAbis.size(); ndx++)
dst << (ndx != 0 ? ", " : "") << supportedAbis[ndx];
dst << "\n";
}
}
} // Android
} // tcu