package com.samknows.measurement; import java.io.File; import com.samknows.libcore.R; import com.samknows.libcore.SKAndroidLogger; import com.samknows.libcore.SKConstants; import com.samknows.libcore.SKPorting; import com.samknows.libcore.SKOperators; import com.samknows.measurement.environment.CellTowersDataCollector; import com.samknows.measurement.storage.ExportFile; import com.samknows.measurement.storage.TestResultsManager; import com.samknows.ui2.activity.SKAAboutActivity; import com.samknows.ska.activity.SKATermsOfUseActivity; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Typeface; import android.preference.PreferenceManager; import android.support.multidex.MultiDexApplication; import android.util.Log; public class SKApplication extends MultiDexApplication { static private SKApplication sAppInstance = null; public SKApplication() { super(); sAppInstance = this; SKConstants.RStringQuit = R.string.quit; SKConstants.RStringReallyQuit = R.string.really_quit; SKConstants.RStringYes = R.string.yes; SKConstants.RStringNoDialog = R.string.no_dialog; SKConstants.PREF_KEY_USED_BYTES = "used_bytes"; SKConstants.PREF_DATA_CAP = "data_cap_pref"; SKConstants.PROP_TEST_START_WINDOW_RTC = "test_start_window_in_millis_rtc"; } @Override protected void attachBaseContext(Context base) { // https://github.com/robolectric/robolectric/issues/1328 // Multidex support doesn't play well with Robolectric yet! try { super.attachBaseContext(base); } catch (RuntimeException ignored) { Log.d("SKApplication", "Warning - Multidex support doesn't play well with Robolectric yet"); } } @Override public void onCreate() { super.onCreate(); // Initialize the SKOperators data! SKOperators.getInstance(getApplicationContext()); File theCacheDir = getExternalCacheDir(); if (theCacheDir == null) { theCacheDir = getCacheDir(); } // Clear the cache dir of old export files... as they might be quite big! { File[] files = theCacheDir.listFiles(); String baseExportName = getString(R.string.menu_export_default_file_name_no_extension); if (files != null) { for (File file : files) { if (file.getName().indexOf(baseExportName) == 0) { boolean bRes = file.delete(); SKPorting.sAssert(bRes); } } } } SKAndroidLogger.setStorageFolder(theCacheDir); TestResultsManager.setStorage(theCacheDir); // Do NOT use the storage area for ExportFiles... these should be retained for future export. ExportFile.setStorage(getFilesDir()); SK2AppSettings.create(this); CachingStorage.create(this); // Get the config! CachingStorage.getInstance().loadScheduleConfig(); // Start monitoring for cell tower signal strength etc.... // We need to do this, as Android does not allow us to query this information synchronously. CellTowersDataCollector.sStartToCaptureCellTowersData(this); } public static SKApplication getAppInstance() { return sAppInstance; } public void showAbout(Activity activity) { Intent intent = new Intent(activity, SKAAboutActivity.class); activity.startActivity(intent); } public void showTermsAndConditions(Activity activity) { Intent intent = new Intent(activity, SKATermsOfUseActivity.class); activity.startActivity(intent); } // Network type results querying... public enum eNetworkTypeResults { eNetworkTypeResults_Any, eNetworkTypeResults_Mobile, eNetworkTypeResults_WiFi } private static eNetworkTypeResults sNetworkTypeResults = eNetworkTypeResults.eNetworkTypeResults_Mobile; public static eNetworkTypeResults getNetworkTypeResults() { return sNetworkTypeResults; } public static void setNetworkTypeResults(eNetworkTypeResults networkTypeResults) { sNetworkTypeResults = networkTypeResults; } public boolean getShouldTestResultsBeUploadedToTestSpecificServer() { return false; } // Override this, if you want your application to support a 1-day result view. public boolean supportOneDayResultView() { return false; } // Override this, if you want your application to support continuous testing. public boolean supportContinuousTesting() { return false; } // Get the class of the main activity! public Class getTheMainActivityClass() { return null; } // Return the About screen title. public String getAboutScreenTitle() { return getApplicationContext().getString(R.string.about) + " " + getAppName(); } public boolean getRevealMetricsOnMainScreen() { return true; } public boolean getRevealPassiveMetricsOnArchiveResultsPanel() { return true; } public boolean getRevealGraphFromSummary() { return true; } public boolean hideJitter() { return false; } public boolean hideLatency() { return false; } public boolean hideLoss() { return false; } public boolean hideJitterLatencyAndPacketLoss() { return hideJitter() & hideLatency() & hideLoss(); } // Return null, but can be overridden. // Otherwise, SKTypeface will use Typeface.DEFAULT public Typeface getDefaultTypeface() { return null; } public boolean allowUserToSelectTestToRun() { // Run all tests! return false; } public boolean isExportMenuItemSupported() { return false; } // Datacap enabling/disabling public boolean canViewDataCapInSettings() { return true; } public boolean canDisableDataCap() { return false; } // Datacap - enable/disable (managed via the SKAPreferenceActivity) public boolean getIsDataCapEnabled() { if (canDisableDataCap() == false) { // Can't disable the datacap in this version of the app - so in this // case, the data cap is always enabled. return true; } // The value is saved/restored automatically through PreferenceManager. SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); return p.getBoolean(SKConstants.PREF_DATA_CAP_ENABLED, true); } public boolean canViewLocationInSettings() { return true; } public boolean isSocialMediaExportSupported() { return false; } public boolean isSocialMediaImageExportSupported() { return false; } // Support throttle query supported? public boolean isThrottleQuerySupported() { return false; } public boolean getDoesAppDisplayClosestTargetInfo() { return true; } // Some versions of the app can enable background menu forcing via the menu... public boolean isForceBackgroundMenuItemSupported() { return false; } public String getExportFileProviderAuthority() { // e.g. return "com.samknows.myapppackage.ExportFileProvider.provider"; SKPorting.sAssert(getClass(), false); return null; } public String getAppName() { SKPorting.sAssert(getClass(), false); // Must be overridden! return "Unknown"; } // For now, we don't generally support server-based upload speed measurement testing. public boolean getDoesAppSupportServerBasedUploadSpeedTesting() { return false; } public boolean getShouldDisplayWlanCarrierNameInRunTestScreen() { return false; } public boolean getDoesAppDisplayCountryNameInMetrics() { return true; } // Must be overridden! public String getDCSInitUrl() { SKPorting.sAssert(getClass(), false); return "DCSInitUrl_UNKNOWN"; } public String getBaseUrlForUpload() { //return @"http://dcs-mobile-fcc.samknows.com"; SKPorting.sAssert(getClass(), false); return "BaseUrlForUpload_UNKNOWN"; } // Must be overridden! public String getEnterpriseId() { SKPorting.sAssert(getClass(), false); return "EnterpriseId_UNKNOWN"; } // This must be overridden to return the HockeyApp id ... public String getCrashManagerId() { SKPorting.sAssert(getClass(), false); return "CrashManagerId_UNKNOWN"; } // Must be overridden! public boolean getAnonymous() { SKPorting.sAssert(getClass(), false); return true; } private static boolean sbUpdateAllDataOnScreen = false; public static void sSetUpdateAllDataOnScreen(boolean value) { sbUpdateAllDataOnScreen = value; } public static boolean sGetUpdateAllDataOnScreen() { return sbUpdateAllDataOnScreen; } public Boolean getIsBackgroundProcessingEnabledInTheSchedule() { Boolean backgroundTest = SK2AppSettings.getSK2AppSettingsInstance().getIsBackgroundProcessingEnabledInTheSchedule(); return backgroundTest; } public Boolean getIsBackgroundTestingEnabledInUserPreferences() { if (getIsBackgroundProcessingEnabledInTheSchedule() == false) { return false; } Boolean backgroundTest = SK2AppSettings.getSK2AppSettingsInstance().getIsBackgroundTestingEnabledInUserPreferences(); return backgroundTest; } public Boolean getPassiveMetricsJustDisplayPublicIpAndSubmissionId() { return false; } public boolean getForceUploadDownloadSpeedToReportInMbps() { return false; } // Used by the new app... public String mLastSubmissionId = ""; public String mLastPublicIp = ""; public double[] getDownloadSixSegmentMaxValues() { double arrSegmentMinValues_Download[] = {1.0, 2.0, 5.0, 10.0, 30.0, 100.0}; return arrSegmentMinValues_Download; } public double[] getUploadSixSegmentMaxValues() { double arrSegmentMaxValues_Upload[] = {0.5, 1.0, 1.5, 2.0, 10.0, 50.0}; return arrSegmentMaxValues_Upload; } public static double[] sGetDownloadSixSegmentMaxValues() { if (getAppInstance() != null) { // The normal case! return getAppInstance().getDownloadSixSegmentMaxValues(); } // Special fallback case to cater for GaugeView.java in the layout designer double arrSegmentMinValues_Download[] = {1.0, 2.0, 5.0, 10.0, 30.0, 100.0}; return arrSegmentMinValues_Download; } public static double[] sGetUploadSixSegmentMaxValues() { if (getAppInstance() != null) { // The normal case! return getAppInstance().getUploadSixSegmentMaxValues(); } // Special fallback case to cater for GaugeView.java in the layout designer double arrSegmentMaxValues_Upload[] = {0.5, 1.0, 1.5, 2.0, 10.0, 50.0}; return arrSegmentMaxValues_Upload; } // T&C checking! final static private String kPreferencesFileName = "termsAndConditions"; final static private String kAgreementKey = "agreementVersion"; public static boolean sGetTermsAcceptedAtThisVersionOrGreater(Activity activity, String termsVersion) { SharedPreferences prefs = activity.getSharedPreferences(kPreferencesFileName, MODE_PRIVATE); String agreement = prefs.getString(kAgreementKey, null); if (agreement != null) { try { if (Double.valueOf(agreement) >= Double.valueOf(termsVersion)) { return true; } } catch (Exception e) { SKPorting.sAssert(SKApplication.class, false); } } return false; } public static void sSetTermsAcceptedAtThisVersion(Activity activity, String termsVersion) { SharedPreferences prefs = activity.getSharedPreferences(kPreferencesFileName, MODE_PRIVATE); Editor editor = prefs.edit(); editor.putString(kAgreementKey, termsVersion); editor.commit(); } public String getTAndCVersionToCheckFor() { return "1.0"; } // Some apps can override this, to show terms when app starts. public boolean getShouldAppShowTermsAtStart() { return false; } public java.io.InputStream getScheduleXml() { // Must be overridden! SKPorting.sAssert(getClass(), false); return null; } // If the app needs to override the detailed fonts specified by the base app, this method can be overridden; // this can look at the path, and attempt to override. // If there is no need to override, or in event of failure, call the super class implementation! public Typeface createTypefaceFromAsset(String typefacePathInAssets) { Context context = getApplicationContext(); switch (typefacePathInAssets) { case "fonts/roboto_condensed_regular.ttf": break; case "fonts/roboto_light.ttf": break; case "fonts/roboto_thin.ttf": break; case "fonts/roboto_bold.ttf": break; case "fonts/roboto_regular.ttf": break; case "fonts/Lato_Semibold.ttf": break; case "fonts/Lato_Bold.ttf": break; case "fonts/Lato_Medium.ttf": break; case "fonts/Lato_MediumItalic.ttf": break; case "fonts/Lato_Thin.ttf": break; case "fonts/Lato_ThinItalic.ttf": break; case "fonts/Lato_Light.ttf": break; case "fonts/Lato_LightItalic.ttf": break; case "typewriter.ttf": // Log.d("SKTypefaceUtil", "typewriter.ttf!"); // SKLogger.sAssert(false); break; default: Log.d("SKTypefaceUtil", "Unexpected font path " + typefacePathInAssets); SKPorting.sAssert(false); break; } Typeface result = null; try { result = Typeface.createFromAsset(context.getAssets(), typefacePathInAssets); } catch (Exception e) { SKPorting.sAssert(false); } SKPorting.sAssert(result != null); return result; } }