#include "tcuAndroidUtil.hpp"
+#include "deSTLUtil.hpp"
+#include "deMath.h"
+
#include <vector>
namespace tcu
using std::string;
using std::vector;
-void checkJNIException (JNIEnv* env)
+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())
{
}
}
-string getJNIStringValue (JNIEnv* env, jstring jniStr)
+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);
return str;
}
-static string getIntentStringExtra (JNIEnv* env, jobject activity, const char* name)
+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);
+ const jclass activityCls = getObjectClass(env, activity);
+ const LocalRef intent (env, env->CallObjectMethod(activity, getMethodID(env, activityCls, "getIntent", "()Landroid/content/Intent;")));
+ TCU_CHECK_INTERNAL(intent);
- jstring extraName = env->NewStringUTF(name);
- jclass intentCls = env->GetObjectClass(intent);
- TCU_CHECK(extraName && intentCls);
+ 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;
- jstring extraStr = (jstring)env->CallObjectMethodA(intent, env->GetMethodID(intentCls, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"), getExtraArgs);
+ getExtraArgs[0].l = *extraName;
- env->DeleteLocalRef(extraName);
+ const LocalRef extraStr (env, env->CallObjectMethodA(*intent, getMethodID(env, intentCls, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"), getExtraArgs));
if (extraStr)
- return getJNIStringValue(env, extraStr);
+ return getStringValue(env, (jstring)*extraStr);
else
return string();
}
-string getIntentStringExtra (ANativeActivity* activity, const char* name)
+void setRequestedOrientation (JNIEnv* env, jobject activity, ScreenOrientation orientation)
{
- 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");
+ const jclass activityCls = getObjectClass(env, activity);
+ const jmethodID setOrientationId = getMethodID(env, 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<float> (void)
+{
+ return "F";
+}
+
+template<>
const char* getJNITypeStr<string> (void)
{
return "Ljava/lang/String;";
const jstring jniStr = (jstring)env->GetStaticObjectField(cls, fieldId);
if (jniStr)
- return getJNIStringValue(env, jniStr);
+ return getStringValue(env, jniStr);
else
return string();
}
const jobjectArray array = (jobjectArray)env->GetStaticObjectField(cls, fieldId);
vector<string> result;
- checkJNIException(env);
+ checkException(env);
if (array)
{
{
const jstring jniStr = (jstring)env->GetObjectArrayElement(array, ndx);
- checkJNIException(env);
+ checkException(env);
if (jniStr)
- result.push_back(getJNIStringValue(env, jniStr));
+ result.push_back(getStringValue(env, jniStr));
}
}
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;
+ const jclass cls = findClass(env, className);
+ const jfieldID fieldId = env->GetStaticFieldID(cls, fieldName, getJNITypeStr<FieldType>());
- checkJNIException(env);
+ checkException(env);
- if (cls && fieldId)
+ if (fieldId)
return getStaticFieldValue<FieldType>(env, cls, fieldId);
else
- return FieldType();
+ throw std::runtime_error(string(fieldName) + " not found in " + className);
}
-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;
-};
+template<typename FieldType>
+FieldType getFieldValue (JNIEnv* env, jobject obj, jfieldID fieldId);
-ScopedJNIEnv::ScopedJNIEnv (JavaVM* vm)
- : m_vm (vm)
- , m_env (DE_NULL)
- , m_detach (false)
+template<>
+int getFieldValue<int> (JNIEnv* env, jobject obj, jfieldID fieldId)
{
- 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(obj && fieldId);
+ return env->GetIntField(obj, fieldId);
+}
- DE_ASSERT(m_env);
+template<>
+float getFieldValue<float> (JNIEnv* env, jobject obj, jfieldID fieldId)
+{
+ DE_ASSERT(obj && fieldId);
+ return env->GetFloatField(obj, fieldId);
}
-ScopedJNIEnv::~ScopedJNIEnv (void)
+template<typename FieldType>
+FieldType getField (JNIEnv* env, jobject obj, const char* fieldName)
{
- if (m_detach)
- m_vm->DetachCurrentThread();
+ 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 (ANativeActivity* activity, std::ostream& dst)
+void describePlatform (JNIEnv* env, std::ostream& dst)
{
- const ScopedJNIEnv env (activity->vm);
const char* const buildClass = "android/os/Build";
const char* const versionClass = "android/os/Build$VERSION";
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)
+ << ": " << getStaticField<string>(env, s_stringFields[ndx].classPath, s_stringFields[ndx].fieldName)
<< "\n";
- dst << "Build.VERSION.SDK_INT: " << getStaticField<int>(env.getEnv(), versionClass, "SDK_INT") << "\n";
+ dst << "Build.VERSION.SDK_INT: " << getStaticField<int>(env, versionClass, "SDK_INT") << "\n";
{
- const vector<string> supportedAbis = getStaticField<vector<string> >(env.getEnv(), buildClass, "SUPPORTED_ABIS");
+ const vector<string> supportedAbis = getStaticField<vector<string> >(env, buildClass, "SUPPORTED_ABIS");
dst << "Build.SUPPORTED_ABIS: ";
}
}
+vector<string> getSupportedABIs (JNIEnv* env)
+{
+ return getStaticField<vector<string> >(env, "android/os/Build", "SUPPORTED_ABIS");
+}
+
+bool supportsAny64BitABI (JNIEnv* env)
+{
+ const vector<string> supportedAbis = getSupportedABIs(env);
+ const char* known64BitAbis[] = { "arm64-v8a", "x86_64", "mips64" };
+
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(known64BitAbis); ++ndx)
+ {
+ if (de::contains(supportedAbis.begin(), supportedAbis.end(), string(known64BitAbis[ndx])))
+ return true;
+ }
+
+ return false;
+}
+
+bool supportsAny64BitABI (ANativeActivity* activity)
+{
+ const ScopedJNIEnv env(activity->vm);
+
+ return supportsAny64BitABI(env.getEnv());
+}
+
+jobject getPackageManager (JNIEnv* env, jobject activity)
+{
+ const jclass activityCls = getObjectClass(env, activity);
+ const jmethodID getPMID = getMethodID(env, activityCls, "getPackageManager", "()Landroid/content/pm/PackageManager;");
+ const jobject packageManager = env->CallObjectMethod(activity, getPMID);
+
+ return packageManager;
+}
+
+bool hasSystemFeature (JNIEnv* env, jobject activity, const char* name)
+{
+ const LocalRef packageManager (env, getPackageManager(env, activity));
+ const jclass pmCls = getObjectClass(env, *packageManager);
+ const jmethodID hasFeatureID = getMethodID(env, pmCls, "hasSystemFeature", "(Ljava/lang/String;)Z");
+ const LocalRef nameStr (env, env->NewStringUTF(name));
+ jvalue callArgs[1];
+
+ callArgs[0].l = *nameStr;
+
+ return env->CallBooleanMethodA(*packageManager, hasFeatureID, callArgs) == JNI_TRUE;
+}
+
+jobject getWindowManager (JNIEnv* env, jobject activity)
+{
+ const jclass activityCls = getObjectClass(env, activity);
+ const jmethodID getWMID = getMethodID(env, activityCls, "getWindowManager", "()Landroid/view/WindowManager;");
+ const jobject windowManager = env->CallObjectMethod(activity, getWMID);
+
+ return windowManager;
+}
+
+jobject getDefaultDisplay (JNIEnv* env, jobject windowManager)
+{
+ const jclass wmClass = getObjectClass(env, windowManager);
+ const jmethodID getDisplayID = getMethodID(env, wmClass, "getDefaultDisplay", "()Landroid/view/Display;");
+ const jobject display = env->CallObjectMethod(windowManager, getDisplayID);
+
+ return display;
+}
+
+jobject createDisplayMetrics (JNIEnv* env)
+{
+ const jclass displayMetricsCls = findClass(env, "android/util/DisplayMetrics");
+ const jmethodID ctorId = getMethodID(env, displayMetricsCls, "<init>", "()V");
+
+ return env->NewObject(displayMetricsCls, ctorId);
+}
+
+DisplayMetrics getDisplayMetrics (JNIEnv* env, jobject activity)
+{
+ const LocalRef windowManager (env, getWindowManager(env, activity));
+ const LocalRef defaultDisplay (env, getDefaultDisplay(env, *windowManager));
+ const LocalRef nativeMetrics (env, createDisplayMetrics(env));
+ const jclass displayCls = getObjectClass(env, *defaultDisplay);
+ const jmethodID getMetricsID = getMethodID(env, displayCls, "getMetrics", "(Landroid/util/DisplayMetrics;)V");
+ DisplayMetrics metrics;
+
+ {
+ jvalue callArgs[1];
+ callArgs[0].l = *nativeMetrics;
+
+ env->CallVoidMethodA(*defaultDisplay, getMetricsID, callArgs);
+ }
+
+ metrics.density = getField<float> (env, *nativeMetrics, "density");
+ metrics.densityDpi = getField<int> (env, *nativeMetrics, "densityDpi");
+ metrics.scaledDensity = getField<float> (env, *nativeMetrics, "scaledDensity");
+ metrics.widthPixels = getField<int> (env, *nativeMetrics, "widthPixels");
+ metrics.heightPixels = getField<int> (env, *nativeMetrics, "heightPixels");
+ metrics.xdpi = getField<float> (env, *nativeMetrics, "xdpi");
+ metrics.ydpi = getField<float> (env, *nativeMetrics, "ydpi");
+
+ return metrics;
+}
+
+enum ScreenClass
+{
+ SCREEN_CLASS_WEAR = 0,
+ SCREEN_CLASS_SMALL,
+ SCREEN_CLASS_NORMAL,
+ SCREEN_CLASS_LARGE,
+ SCREEN_CLASS_EXTRA_LARGE,
+
+ SCREEN_CLASS_LAST
+};
+
+enum DensityClass
+{
+ DENSITY_CLASS_LDPI = 120,
+ DENSITY_CLASS_MDPI = 160,
+ DENSITY_CLASS_TVDPI = 213,
+ DENSITY_CLASS_HDPI = 240,
+ DENSITY_CLASS_280DPI = 280,
+ DENSITY_CLASS_XHDPI = 320,
+ DENSITY_CLASS_360DPI = 360,
+ DENSITY_CLASS_400DPI = 400,
+ DENSITY_CLASS_420DPI = 420,
+ DENSITY_CLASS_XXHDPI = 480,
+ DENSITY_CLASS_560DPI = 560,
+ DENSITY_CLASS_XXXHDPI = 640,
+
+ DENSITY_CLASS_INVALID = -1,
+};
+
+ScreenClass getScreenClass (const DisplayMetrics& displayMetrics)
+{
+ static const struct
+ {
+ int minWidthDp;
+ int minHeightDp;
+ ScreenClass screenClass;
+ } s_screenClasses[] =
+ {
+ // Must be ordered from largest to smallest
+ { 960, 720, SCREEN_CLASS_EXTRA_LARGE },
+ { 640, 480, SCREEN_CLASS_LARGE },
+ { 480, 320, SCREEN_CLASS_NORMAL },
+ { 426, 320, SCREEN_CLASS_SMALL },
+ };
+
+ const float dpScale = float(displayMetrics.densityDpi) / 160.f;
+
+ // \note Assume landscape orientation for comparison
+ const int widthP = de::max(displayMetrics.widthPixels, displayMetrics.heightPixels);
+ const int heightP = de::min(displayMetrics.widthPixels, displayMetrics.heightPixels);
+
+ const int widthDp = deFloorFloatToInt32(float(widthP) / dpScale);
+ const int heightDp = deFloorFloatToInt32(float(heightP) / dpScale);
+
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_screenClasses); ++ndx)
+ {
+ if ((s_screenClasses[ndx].minWidthDp <= widthDp) &&
+ (s_screenClasses[ndx].minHeightDp <= heightDp))
+ return s_screenClasses[ndx].screenClass;
+ }
+
+ return SCREEN_CLASS_WEAR;
+}
+
+bool isValidDensityClass (int dpi)
+{
+ switch (dpi)
+ {
+ case DENSITY_CLASS_LDPI:
+ case DENSITY_CLASS_MDPI:
+ case DENSITY_CLASS_TVDPI:
+ case DENSITY_CLASS_HDPI:
+ case DENSITY_CLASS_280DPI:
+ case DENSITY_CLASS_XHDPI:
+ case DENSITY_CLASS_360DPI:
+ case DENSITY_CLASS_400DPI:
+ case DENSITY_CLASS_420DPI:
+ case DENSITY_CLASS_XXHDPI:
+ case DENSITY_CLASS_560DPI:
+ case DENSITY_CLASS_XXXHDPI:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+DensityClass getDensityClass (const DisplayMetrics& displayMetrics)
+{
+ if (isValidDensityClass(displayMetrics.densityDpi))
+ return (DensityClass)displayMetrics.densityDpi;
+ else
+ return DENSITY_CLASS_INVALID;
+}
+
+} // anonymous
+
+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);
+}
+
+bool hasSystemFeature (ANativeActivity* activity, const char* name)
+{
+ const ScopedJNIEnv env(activity->vm);
+
+ return hasSystemFeature(env.getEnv(), activity->clazz, name);
+}
+
+DisplayMetrics getDisplayMetrics (ANativeActivity* activity)
+{
+ const ScopedJNIEnv env(activity->vm);
+
+ return getDisplayMetrics(env.getEnv(), activity->clazz);
+}
+
+size_t getCDDRequiredSystemMemory (ANativeActivity* activity)
+{
+ const DisplayMetrics displayMetrics = getDisplayMetrics(activity);
+ const ScreenClass screenClass = getScreenClass(displayMetrics);
+ const bool isWearDevice = hasSystemFeature(activity, "android.hardware.type.watch");
+ const bool is64BitDevice = supportsAny64BitABI(activity);
+ const size_t MiB = (size_t)(1<<20);
+
+ if (!is64BitDevice)
+ TCU_CHECK_INTERNAL(sizeof(void*) != sizeof(deUint64));
+
+ if (isWearDevice)
+ {
+ TCU_CHECK_INTERNAL(!is64BitDevice);
+ return 416*MiB;
+ }
+ else
+ {
+ const DensityClass densityClass = getDensityClass(displayMetrics);
+
+ TCU_CHECK_INTERNAL(de::inRange(screenClass, SCREEN_CLASS_SMALL, SCREEN_CLASS_EXTRA_LARGE));
+ TCU_CHECK_INTERNAL(densityClass != DENSITY_CLASS_INVALID);
+
+ static const struct
+ {
+ DensityClass smallNormalScreenDensity;
+ DensityClass largeScreenDensity;
+ DensityClass extraLargeScreenDensity;
+ size_t requiredMem32bit;
+ size_t requiredMem64bit;
+ } s_classes[] =
+ {
+ // Must be ordered from largest to smallest
+ { DENSITY_CLASS_560DPI, DENSITY_CLASS_400DPI, DENSITY_CLASS_XHDPI, 1344*MiB, 1824*MiB },
+ { DENSITY_CLASS_400DPI, DENSITY_CLASS_XHDPI, DENSITY_CLASS_TVDPI, 896*MiB, 1280*MiB },
+ { DENSITY_CLASS_XHDPI, DENSITY_CLASS_HDPI, DENSITY_CLASS_MDPI, 512*MiB, 832*MiB },
+
+ // \note Last is default, and density values are maximum allowed
+ { DENSITY_CLASS_280DPI, DENSITY_CLASS_MDPI, DENSITY_CLASS_LDPI, 424*MiB, 704*MiB },
+ };
+
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_classes); ++ndx)
+ {
+ const DensityClass minClass = screenClass == SCREEN_CLASS_EXTRA_LARGE ? s_classes[ndx].extraLargeScreenDensity
+ : screenClass == SCREEN_CLASS_LARGE ? s_classes[ndx].largeScreenDensity
+ : /* small/normal */ s_classes[ndx].smallNormalScreenDensity;
+ const size_t reqMem = is64BitDevice ? s_classes[ndx].requiredMem64bit : s_classes[ndx].requiredMem32bit;
+ const bool isLast = ndx == DE_LENGTH_OF_ARRAY(s_classes)-1;
+
+ if ((isLast && minClass >= densityClass) || (!isLast && minClass <= densityClass))
+ return reqMem;
+ }
+
+ TCU_THROW(InternalError, "Invalid combination of density and screen size");
+ }
+}
+
} // Android
} // tcu