protected void RegisterService(Object service, String key) { try { LOG.LogDebug(Module.GUI, "************* REGISTERING SERVICE: " + key); ((AndroidServiceLocator) AndroidServiceLocator.GetInstance()).RegisterService(service, key); } catch (Exception ex) { LOG.LogDebug( Module.GUI, "************* Exception registering service [" + key + "], exception message: " + ex.getMessage()); } }
/** PRIVATE METHODS * */ private boolean checkUnityProperty(String propertyName) { int resourceIdentifier = getResources().getIdentifier(propertyName, "string", getPackageName()); try { boolean propertyValue = Boolean.parseBoolean(getResources().getString(resourceIdentifier)); LOG.LogDebug(Module.GUI, propertyName + "? " + propertyValue); return propertyValue; } catch (Exception ex) { LOG.LogDebug( Module.GUI, "Exception getting value for " + propertyName + ": " + ex.getMessage()); return false; } }
protected void RegisterResultReceiver(int[] resultCodes, ResultReceiver resultReceiver) { try { ((AndroidServiceLocator) AndroidServiceLocator.GetInstance()) .RegisterResultReceiver(resultCodes, resultReceiver); } catch (Exception ex) { LOG.LogDebug( Module.GUI, "************* Exception registering result receiver, exception message: " + ex.getMessage()); } }
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // this method is invoked with an CANCELED result code if the activity is a "singleInstance" // (launchMode) // that is the reason that we removed that launch mode for the AndroidManifest (see SVN logs) LOG.LogDebug( Module.GUI, "******** onActivityResult # requestCode " + requestCode + ", resultCode: " + resultCode); AndroidActivityManager aam = (AndroidActivityManager) AndroidServiceLocator.GetInstance() .GetService(AndroidServiceLocator.SERVICE_ANDROID_ACTIVITY_MANAGER); boolean handleResult = false; if (aam != null) { handleResult = aam.publishActivityResult(requestCode, resultCode, data); } if (!handleResult) { ResultReceiver resultReceiver = ((AndroidServiceLocator) AndroidServiceLocator.GetInstance()) .getResultReceiver(requestCode); if (resultReceiver != null) { LOG.LogDebug( Module.GUI, "******** Calling ResultReceiver send (probably from a module)..."); Bundle bundle = (data == null ? new Bundle() : data.getExtras()); bundle.putInt(IAppDelegate.ACTIVITY_RESULT_CODE_BUNDLE_KEY, resultCode); resultReceiver.send(requestCode, bundle); } else { LOG.LogDebug(Module.GUI, "******** Calling super.onActivityResult()"); super.onActivityResult(requestCode, resultCode, data); } } }
@Override public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults) { // this method is invoked with an CANCELED result code if the activity is a "singleInstance" // (launchMode) // that is the reason that we removed that launch mode for the AndroidManifest (see SVN logs) LOG.LogDebug( Module.GUI, "******** onActivityResult # requestCode " + requestCode + ", grantResults: " + grantResults); AndroidActivityManager aam = (AndroidActivityManager) AndroidServiceLocator.GetInstance() .GetService(AndroidServiceLocator.SERVICE_ANDROID_ACTIVITY_MANAGER); boolean handleResult = false; if (aam != null) { handleResult = aam.publishPermissionResult(requestCode, permissions, grantResults); } }
/** Initializes the appverse context exposing data to the WebView Javascript DOM. */ private void InitializeAppverseContext(int networkType) { long startTime = System.currentTimeMillis(); try { LOG.Log( Module.GUI, "Before loading the main HTML, platform will expose some information directly to javascript..."); AndroidSystem systemService = (AndroidSystem) AndroidServiceLocator.GetInstance() .GetService(AndroidServiceLocator.SERVICE_TYPE_SYSTEM); AndroidI18N i18nService = (AndroidI18N) AndroidServiceLocator.GetInstance() .GetService(AndroidServiceLocator.SERVICE_TYPE_I18N); AndroidIO ioService = (AndroidIO) AndroidServiceLocator.GetInstance().GetService(AndroidServiceLocator.SERVICE_TYPE_IO); IActivityManager am = (IActivityManager) AndroidServiceLocator.GetInstance() .GetService(AndroidServiceLocator.SERVICE_ANDROID_ACTIVITY_MANAGER); // 1. Appverse Context (Appverse.is) UnityContext unityContext = systemService.GetUnityContext(); String unityContextJsonString = JSONSerializer.serialize(unityContext); unityContextJsonString = "_AppverseContext = " + unityContextJsonString; LOG.LogDebug(Module.GUI, "InitializeAppverseContext: " + unityContextJsonString); am.executeJS(unityContextJsonString); // 2. OS Info (Appverse.OSInfo) OSInfo osInfo = systemService.GetOSInfo(); String osInfoJsonString = JSONSerializer.serialize(osInfo); osInfoJsonString = "_OSInfo = " + osInfoJsonString; LOG.LogDebug(Module.GUI, "InitializeAppverseContext: " + osInfoJsonString); am.executeJS(osInfoJsonString); // 3. Hardware Info (Appverse.HardwareInfo) HardwareInfo hwInfo = systemService.GetOSHardwareInfo(); String hwInfoJsonString = JSONSerializer.serialize(hwInfo); hwInfoJsonString = "_HwInfo = " + hwInfoJsonString; LOG.LogDebug(Module.GUI, "InitializeAppverseContext: " + hwInfoJsonString); am.executeJS(hwInfoJsonString); try { // 4. Get all configured localized keys (Appverse.i18n) Locale[] supportedLocales = i18nService.GetLocaleSupported(); String localizedStrings = "_i18n = {}; _i18n['default'] = '" + i18nService.getDefaultLocale() + "'; "; String localeLiterals = ""; for (Locale supportedLocale : supportedLocales) { ResourceLiteralDictionary literals = i18nService.GetResourceLiterals(supportedLocale); String literalsJsonString = JSONSerializer.serialize(literals); localeLiterals = localeLiterals + " _i18n['" + supportedLocale.toString() + "'] = " + literalsJsonString + "; "; } localizedStrings = localizedStrings + localeLiterals; LOG.LogDebug(Module.GUI, "InitializeAppverseContext: " + localizedStrings); am.executeJS(localizedStrings); } catch (Exception ex) { LOG.LogDebug( Module.GUI, "Unable to load all languages. Exception message: " + ex.getMessage()); } // 5. Current device locale com.gft.unity.core.system.Locale currentLocale = systemService.GetLocaleCurrent(); String currentLocaleJsonString = JSONSerializer.serialize(currentLocale); currentLocaleJsonString = "_CurrentDeviceLocale = " + currentLocaleJsonString; LOG.LogDebug(Module.GUI, "InitializeAppverseContext: " + currentLocaleJsonString); am.executeJS(currentLocaleJsonString); try { // 6. Configured IO services endpoints IOService[] services = ioService.GetServices(); String servicesJsonString = "_IOServices = {}; "; for (IOService service : services) { String serviceJson = JSONSerializer.serialize(service); servicesJsonString = servicesJsonString + " _IOServices['" + service.getName() + "-" + JSONSerializer.serialize(service.getType()) + "'] = " + serviceJson + "; "; } LOG.LogDebug(Module.GUI, "InitializeAppverseContext: " + servicesJsonString); am.executeJS(servicesJsonString); } catch (Exception ex) { LOG.LogDebug( Module.GUI, "Unable to load all services. Exception message: " + ex.getMessage()); } String networkStatusString = "_NetworkStatus = " + networkType + ";"; LOG.LogDebug(Module.GUI, "InitializeAppverseContext: networkType: " + networkType); am.executeJS(networkStatusString); } catch (Exception ex) { LOG.LogDebug( Module.GUI, "Unable to load Appverse Context. Exception message: " + ex.getMessage()); } long timetaken = System.currentTimeMillis() - startTime; LOG.Log(Module.GUI, "# Time elapsed initializing Appverse Context: " + timetaken); }
/** * Check if this activity was launched from a local notification, and send details to application */ private void checkLaunchedFromNotificationOrExternaly() { List<LaunchData> launchDataList = null; LOG.Log(Module.GUI, "checkLaunchedFromNotificationOrExternaly "); if (this.lastIntentExtras != null) { LOG.Log(Module.GUI, "checkLaunchedFromNotificationOrExternaly has intent extras"); final String notificationId = lastIntentExtras.getString(NotificationUtils.EXTRA_NOTIFICATION_ID); if (notificationId != null && notificationId.length() > 0) { LOG.Log(Module.GUI, "Activity was launched from Notification Manager... "); final String message = lastIntentExtras.getString(NotificationUtils.EXTRA_MESSAGE); final String notificationSound = this.lastIntentExtras.getString(NotificationUtils.EXTRA_SOUND); final String customJSONString = this.lastIntentExtras.getString(NotificationUtils.EXTRA_CUSTOM_JSON); final String notificationType = lastIntentExtras.getString(NotificationUtils.EXTRA_TYPE); LOG.LogDebug(Module.GUI, notificationType + " Notification ID = " + notificationId); NotificationData notif = new NotificationData(); notif.setAlertMessage(message); notif.setSound(notificationSound); notif.setCustomDataJsonString(customJSONString); if (notificationType != null && notificationType.equals(NotificationUtils.NOTIFICATION_TYPE_LOCAL)) { this.activityManager.loadUrlIntoWebView( "javascript:try{Appverse.OnLocalNotificationReceived(" + JSONSerializer.serialize(notif) + ")}catch(e){}"); } else if (notificationType != null && notificationType.equals(NotificationUtils.NOTIFICATION_TYPE_REMOTE)) { this.activityManager.loadUrlIntoWebView( "javascript:try{Appverse.PushNotifications.OnRemoteNotificationReceived(" + JSONSerializer.serialize(notif) + ")}catch(e){}"); } } else { LOG.Log(Module.GUI, "Activity was launched from an external app with extras... "); for (String key : this.lastIntentExtras.keySet()) { Object value = this.lastIntentExtras.get(key); /* * debugging LOG.Log(Module.GUI, String.format("%s %s (%s)", * key, value.toString(), value.getClass().getName())); */ if (launchDataList == null) launchDataList = new ArrayList<LaunchData>(); LaunchData launchData = new LaunchData(); launchData.setName(key); launchData.setValue(value.toString()); launchDataList.add(launchData); } LOG.Log(Module.GUI, "#num extras: " + launchDataList.size()); } this.lastIntentExtras = null; } if (this.lastIntentData != null) { LOG.Log(Module.GUI, "Activity was launched from an external app with uri scheme... "); Set<String> lastIntentDataSet = this.getQueryParameterNames(this.lastIntentData); for (String key : lastIntentDataSet) { // for (String key : this.lastIntentData.getQueryParameterNames()) { String value = this.lastIntentData.getQueryParameter(key); /* * debugging LOG.Log(Module.GUI, String.format("%s %s (%s)", * key, value.toString(), value.getClass().getName())); */ if (launchDataList == null) launchDataList = new ArrayList<LaunchData>(); LaunchData launchData = new LaunchData(); launchData.setName(key); launchData.setValue(value); launchDataList.add(launchData); } LOG.LogDebug( Module.GUI, "#num Data: " + (lastIntentDataSet == null ? 0 : lastIntentDataSet.size())); this.lastIntentData = null; } if (launchDataList != null) { String executeExternallyLaunchedListener = "javascript:try{Appverse.OnExternallyLaunched (" + JSONSerializer.serialize( launchDataList.toArray(new LaunchData[launchDataList.size()])) + ")}catch(e){console.log('TESTING OnExternallyLaunched: ' + e);}"; if (this.isWebviewReady()) { LOG.Log(Module.GUI, "Calling OnExternallyLaunched JS listener..."); this.activityManager.loadUrlIntoWebView(executeExternallyLaunchedListener); } else { this.queueJSStatementsForWebviewClient(executeExternallyLaunchedListener); } } }
/** ACTIVITY OVERRIDEN METHODS * */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LOG.Log(Module.GUI, "onCreate"); if (getIntent() != null && getIntent().getExtras() != null) { extras = getIntent().getExtras(); LOG.LogDebug(Module.GUI, "[K] notification Extra:" + extras.getString("item_id")); } // GUI initialization code getWindow().requestFeature(Window.FEATURE_NO_TITLE); getWindow() .setFlags( WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); /*disableThumbnails = checkUnityProperty("Unity_DisableThumbnails"); blockRooted = checkUnityProperty("Appverse_BlockRooted"); blockROMModified = checkUnityProperty("Appverse_BlockROMModified");*/ // security reasons; don't allow screen shots while this window is displayed /* not valid for builds under level 14 */ // TODO DISABLETHUMBNAILS_1 // @@DISABLETHUMBNAILS_1@@ // Initialize Webview component and provide specific settings this.initialiazeWebViewSettings(); // create the application logger LogManager.setDelegate(new AndroidLoggerDelegate()); // initialize the service locator activityManager = initialiazeActivityManager(); // save the context for further access AndroidServiceLocator.setContext(this, activityManager); // killing previous background processes from the same package activityManager.killBackgroundProcesses(); AndroidServiceLocator serviceLocator = (AndroidServiceLocator) AndroidServiceLocator.GetInstance(); serviceLocator.RegisterService( this.getAssets(), AndroidServiceLocator.SERVICE_ANDROID_ASSET_MANAGER); serviceLocator.RegisterService( activityManager, AndroidServiceLocator.SERVICE_ANDROID_ACTIVITY_MANAGER); // registering Appverse modules (if any) this.registerModulesServices(); // initialize config data files for app delegates serviceLocator.initConfigDataForServices(); if (Build.VERSION.SDK_INT >= 17) { // Only used for JELLY_BEAN_MR1 or higher /** * INJECT SCRIPT MESSAGE HANDLER (new in Appverse 5) ** */ /** * From Android documentation: * * <p>This method can be used to allow JavaScript to control the host application. This is a * powerful feature, but also presents a security risk for apps targeting JELLY_BEAN or * earlier. Apps that target a version later than JELLY_BEAN are still vulnerable if the app * runs on a device running Android earlier than 4.2. The most secure way to use this method * is to target JELLY_BEAN_MR1 and to ensure the method is called only when running on Android * 4.2 or later. With these older versions, JavaScript could use reflection to access an * injected object's public fields. Use of this method in a WebView containing untrusted * content could allow an attacker to manipulate the host application in unintended ways, * executing Java code with the permissions of the host application. Use extreme care when * using this method in a WebView which could contain untrusted content. * * <p>JavaScript interacts with Java object on a private, background thread of this WebView. * Care is therefore required to maintain thread safety. The Java object's fields are not * accessible. For applications targeted to API level LOLLIPOP and above, methods of injected * Java objects are enumerable from JavaScript. */ this.addJavascriptIntefaceToWebView(serviceLocator, "appverseJSBridge"); } if (performSecurityChecks(serviceLocator)) { LOG.Log(Module.GUI, "Security checks passed... initializing Appverse..."); startServer(); /* THIS COULD NOT BE CHECKED ON API LEVEL < 11; NO suchmethodexception * boolean hwAccelerated = appView.isHardwareAccelerated(); * if(hwAccelerated) * LOG.Log(Module.GUI,"Application View is HARDWARE ACCELERATED"); else * LOG.Log(Module.GUI,"Application View is NOT hardware accelerated"); */ final IntentFilter actionFilter = new IntentFilter(); actionFilter.addAction(android.net.ConnectivityManager.CONNECTIVITY_ACTION); // actionFilter.addAction("android.intent.action.SERVICE_STATE"); registerReceiver(this.initialiazeNetworkReceiver(), actionFilter); ConnectivityManager conMan = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = conMan.getActiveNetworkInfo(); com.gft.unity.core.net.NetworkType type = NetworkType.Unknown; if (networkInfo != null) { boolean isWiFi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI; boolean isMobile = networkInfo.getType() == ConnectivityManager.TYPE_MOBILE; boolean isConnected = networkInfo.isConnected(); if (isWiFi) { if (isConnected) { LOG.Log(Module.GUI, "Wi-Fi - CONNECTED (" + networkInfo.getType() + ")"); type = NetworkType.Wifi; } else { LOG.Log(Module.GUI, "Wi-Fi - DISCONNECTED (" + networkInfo.getType() + ")"); } } else if (isMobile) { if (isConnected) { LOG.Log(Module.GUI, "Mobile - CONNECTED (" + networkInfo.getType() + ")"); type = NetworkType.Carrier_3G; } else { LOG.Log(Module.GUI, "Mobile - DISCONNECTED (" + networkInfo.getType() + ")"); } } else { if (isConnected) { LOG.Log( Module.GUI, networkInfo.getTypeName() + " - CONNECTED (" + networkInfo.getType() + ")"); } else { LOG.Log( Module.GUI, networkInfo.getTypeName() + " - DISCONNECTED (" + networkInfo.getType() + ")"); } } } else { LOG.Log(Module.GUI, "DISCONNECTED"); } final int typeOrdinal = type.ordinal(); final Activity currentContext = this; new Thread( new Runnable() { public void run() { currentContext.runOnUiThread( new Runnable() { public void run() { InitializeAppverseContext(typeOrdinal); String networkStatusListener = "javascript:try{if(Appverse&&Appverse.Net){Appverse.Net.NetworkStatus = " + typeOrdinal + ";Appverse.Net.onConnectivityChange(Appverse.Net.NetworkStatus);}else{console.log('Appverse is not defined');}}catch(e){console.log('Error setting network status (please check onConnectivityChange method): '+e);}"; queueJSStatementsForWebviewClient(networkStatusListener); loadMainURLIntoWebview(); } }); } }) .start(); } holdSplashScreenOnStartup = checkUnityProperty("Unity_HoldSplashScreenOnStartup"); this.showSplashScreen(); LocalNotificationReceiver.initialize(this.activityManager, this); // notify app delegates about the onCreate event ((AndroidServiceLocator) AndroidServiceLocator.GetInstance()) .sendApplicationEvent(AndroidApplicationEvent.onCreate); }