package de.jeisfeld.augendiagnoselib; import android.app.Activity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; import android.util.Log; import java.lang.Thread.UncaughtExceptionHandler; import java.util.Locale; import de.jeisfeld.augendiagnoselib.activities.SettingsActivity; import de.jeisfeld.augendiagnoselib.util.PreferenceUtil; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Utility class to retrieve base application resources. */ @SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_SUPERCLASS", justification = "Intentionally using same name as superclass") public class Application extends android.app.Application { /** * The private constants of this app. */ private static ApplicationSettings mApplicationSettings; /** * An instance of the application context. */ private static Context mContext; /** * The default tag for logging. */ public static final String TAG = "Augendiagnose.JE"; @Nullable private static ApplicationSettings getApplicationSettings() { return mApplicationSettings; } // OVERRIDABLE @Override @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "Make some context visible statically (no matter which one)") public void onCreate() { super.onCreate(); Application.mContext = this.getApplicationContext(); SettingsActivity.setDefaultSharedPreferences(getApplicationContext()); setLanguage(); setExceptionHandler(); // Initialize special classes try { Application.mApplicationSettings = (ApplicationSettings) Class.forName(getResourceString(R.string.class_application_settings)) .getDeclaredMethod("getInstance", new Class<?>[0]) .invoke(null); } catch (Exception e) { Log.e(TAG, "Error in getting PrivateConstants and ApplicationSettings", e); } // Set statistics int initialVersion = PreferenceUtil.getSharedPreferenceInt(R.string.key_statistics_initialversion, -1); if (initialVersion == -1) { PreferenceUtil.setSharedPreferenceInt(R.string.key_statistics_initialversion, getVersion()); } long firstStartTime = PreferenceUtil.getSharedPreferenceLong(R.string.key_statistics_firststarttime, -1); if (firstStartTime == -1) { PreferenceUtil.setSharedPreferenceLong(R.string.key_statistics_firststarttime, System.currentTimeMillis()); } PreferenceUtil.incrementCounter(R.string.key_statistics_countstarts); PreferenceUtil.sendStatistics(); } /** * Define custom ExceptionHandler which takes action on OutOfMemoryError. */ private void setExceptionHandler() { final UncaughtExceptionHandler defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); UncaughtExceptionHandler customExceptionHandler = new UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread thread, final Throwable ex) { if (ex instanceof OutOfMemoryError) { // Store info about OutOfMemoryError PreferenceUtil.setSharedPreferenceBoolean(R.string.key_internal_outofmemoryerror, true); } // re-throw critical exception further to the os defaultExceptionHandler.uncaughtException(thread, ex); } }; Thread.setDefaultUncaughtExceptionHandler(customExceptionHandler); } /** * Retrieve the application context. * * @return The (statically stored) application context */ public static Context getAppContext() { return Application.mContext; } /** * Check if the application has an authorized user key. * * @return true if the application has an authorized user key. */ public static AuthorizationLevel getAuthorizationLevel() { return getApplicationSettings().getAuthorizationLevel(); } /** * start the application. * * @param triggeringActivity the triggering activity. */ public static void startApplication(final Activity triggeringActivity) { getApplicationSettings().startApplication(triggeringActivity); } /** * Get a resource string. * * @param resourceId the id of the resource. * @return the value of the String resource. */ public static String getResourceString(final int resourceId) { return getAppContext().getResources().getString(resourceId); } /** * Retrieve the version number of the app. * * @return the app version. */ public static int getVersion() { PackageInfo pInfo; try { pInfo = getAppContext().getPackageManager().getPackageInfo(getAppContext().getPackageName(), 0); return pInfo.versionCode; } catch (NameNotFoundException e) { Log.e(TAG, "Did not find application version", e); return 0; } } /** * Retrieve the version String of the app. * * @return the app version String. */ public static String getVersionString() { PackageInfo pInfo; try { pInfo = getAppContext().getPackageManager().getPackageInfo(getAppContext().getPackageName(), 0); return pInfo.versionName; } catch (NameNotFoundException e) { Log.e(TAG, "Did not find application version", e); return null; } } /** * Set the language. */ public static void setLanguage() { String languageString = PreferenceUtil.getSharedPreferenceString(R.string.key_language); if (languageString == null || languageString.length() == 0) { PreferenceUtil.setSharedPreferenceString(R.string.key_language, "0"); return; } int languageSetting = Integer.parseInt(languageString); if (languageSetting != 0) { switch (languageSetting) { case 1: setLocale(Locale.ENGLISH); break; case 2: setLocale(Locale.GERMAN); break; case 3: // MAGIC_NUMBER setLocale(new Locale("es")); break; default: } } } /** * Set the locale. * * @param locale The locale to be set. */ private static void setLocale(final Locale locale) { if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) { setLocale17(locale); } else { setLocale16(locale); } } /** * Set the locale for Android version below Jelly Bean. * * @param locale The locale to be set. */ @RequiresApi(api = VERSION_CODES.JELLY_BEAN_MR1) private static void setLocale17(final Locale locale) { Configuration conf = getAppContext().getResources().getConfiguration(); conf.setLocale(locale); Application.mContext = getAppContext().createConfigurationContext(conf); } /** * Set the locale for Android version above Jelly Bean. * * @param locale The locale to be set. */ @SuppressWarnings("deprecation") private static void setLocale16(final Locale locale) { Resources res = getAppContext().getResources(); Configuration conf = res.getConfiguration(); conf.locale = locale; res.updateConfiguration(conf, res.getDisplayMetrics()); } /** * The level of authorization of the class. */ public enum AuthorizationLevel { /** * Only trial access. */ TRIAL_ACCESS, /** * Full usage, but with ads. */ FULL_ACCESS_WITH_ADS, /** * Full usage. */ FULL_ACCESS, /** * No access. */ NO_ACCESS } }