diff --git a/bin/templates/project/Activity.java b/bin/templates/project/Activity.java index a515ab0b..1bd9e1cb 100644 --- a/bin/templates/project/Activity.java +++ b/bin/templates/project/Activity.java @@ -22,16 +22,13 @@ package __ID__; import android.os.Bundle; import org.apache.cordova.*; -public class __ACTIVITY__ extends CordovaActivity +public class __ACTIVITY__ extends CordovaActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - super.init(); // Set by in config.xml - super.loadUrl(Config.getStartUrl()); - //super.loadUrl("file:///android_asset/www/index.html"); + loadUrl(launchUrl); } } - diff --git a/bin/templates/project/AndroidManifest.xml b/bin/templates/project/AndroidManifest.xml index 8f7d9593..01840463 100644 --- a/bin/templates/project/AndroidManifest.xml +++ b/bin/templates/project/AndroidManifest.xml @@ -38,7 +38,7 @@ android:label="@string/activity_name" android:launchMode="singleTop" android:theme="@android:style/Theme.Black.NoTitleBar" - android:windowSoftInputMode="adjustPan" + android:windowSoftInputMode="adjustResize" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"> diff --git a/framework/src/org/apache/cordova/AndroidChromeClient.java b/framework/src/org/apache/cordova/AndroidChromeClient.java index 55ce0f5f..73e97240 100755 --- a/framework/src/org/apache/cordova/AndroidChromeClient.java +++ b/framework/src/org/apache/cordova/AndroidChromeClient.java @@ -46,8 +46,6 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.util.Log; - - /** * This class is the WebChromeClient that implements callbacks for our web view. * The kind of callbacks that happen here are on the chrome outside the document, @@ -62,10 +60,10 @@ import android.util.Log; public class AndroidChromeClient extends WebChromeClient implements CordovaChromeClient { public static final int FILECHOOSER_RESULTCODE = 5173; - private static final String LOG_TAG = "CordovaChromeClient"; + private static final String LOG_TAG = "AndroidChromeClient"; private long MAX_QUOTA = 100 * 1024 * 1024; - protected CordovaInterface cordova; - protected AndroidWebView appView; + protected final CordovaInterface cordova; + protected final AndroidWebView appView; // the video progress view private View mVideoProgressView; @@ -73,12 +71,6 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom // File Chooser public ValueCallback mUploadMessage; - /** - * Constructor. - * - * @param ctx - * @param app - */ public AndroidChromeClient(CordovaInterface ctx, AndroidWebView app) { this.cordova = ctx; this.appView = app; diff --git a/framework/src/org/apache/cordova/AndroidWebView.java b/framework/src/org/apache/cordova/AndroidWebView.java index df4f1f91..36040821 100755 --- a/framework/src/org/apache/cordova/AndroidWebView.java +++ b/framework/src/org/apache/cordova/AndroidWebView.java @@ -23,6 +23,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import org.apache.cordova.Config; @@ -30,7 +31,6 @@ import org.apache.cordova.CordovaInterface; import org.apache.cordova.LOG; import org.apache.cordova.PluginManager; import org.apache.cordova.PluginResult; -import org.json.JSONException; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -39,8 +39,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -50,7 +48,6 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.webkit.WebBackForwardList; import android.webkit.WebHistoryItem; @@ -61,6 +58,7 @@ import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebViewClient; import android.widget.FrameLayout; + /* * This class is our web view. * @@ -124,133 +122,51 @@ public class AndroidWebView extends WebView implements CordovaWebView { ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); - - /** - * Constructor. - * - * @param context - */ + /** Used when created via reflection. */ public AndroidWebView(Context context) { - super(context); - if (CordovaInterface.class.isInstance(context)) - { - this.cordova = (CordovaInterface) context; - } - else - { - Log.d(TAG, "Your activity must implement CordovaInterface to work"); - } - this.loadConfiguration(); - this.setup(); + this(context, null); } - /** - * Constructor. - * - * @param context - * @param attrs - */ + /** Required to allow view to be used within XML layouts. */ public AndroidWebView(Context context, AttributeSet attrs) { super(context, attrs); - if (CordovaInterface.class.isInstance(context)) - { - this.cordova = (CordovaInterface) context; - } - else - { - Log.d(TAG, "Your activity must implement CordovaInterface to work"); - } - this.loadConfiguration(); - this.setup(); } - /** - * Constructor. - * - * @param context - * @param attrs - * @param defStyle - * - */ - public AndroidWebView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - if (CordovaInterface.class.isInstance(context)) - { - this.cordova = (CordovaInterface) context; - } - else - { - Log.d(TAG, "Your activity must implement CordovaInterface to work"); - } - this.loadConfiguration(); - this.setup(); - } - - /** - * Constructor. - * - * @param context - * @param attrs - * @param defStyle - * @param privateBrowsing - */ - @TargetApi(11) - public AndroidWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) { - super(context, attrs, defStyle, privateBrowsing); - if (CordovaInterface.class.isInstance(context)) - { - this.cordova = (CordovaInterface) context; - } - else - { - Log.d(TAG, "Your activity must implement CordovaInterface to work"); - } - this.loadConfiguration(); - this.setup(); - } - - /** - * Create a default WebViewClient object for this webview. This can be overridden by the - * main application's CordovaActivity subclass. - * - * There are two possible client objects that can be returned: - * AndroidWebViewClient for android < 3.0 - * IceCreamCordovaWebViewClient for Android >= 3.0 (Supports shouldInterceptRequest) - */ + // Use two-phase init so that the control will work with XML layouts. @Override - public CordovaWebViewClient makeWebViewClient() { - if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) - { - return (CordovaWebViewClient) new AndroidWebViewClient(this.cordova, this); - } - else - { - return (CordovaWebViewClient) new IceCreamCordovaWebViewClient(this.cordova, this); + public void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient, List pluginEntries) { + if (this.cordova != null) { + throw new IllegalStateException(); } + this.cordova = cordova; + setWebChromeClient(webChromeClient); + setWebViewClient(webViewClient); + + pluginManager = new PluginManager(this, this.cordova, pluginEntries); + jsMessageQueue = new NativeToJsMessageQueue(this, cordova); + exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue); + resourceApi = new CordovaResourceApi(this.getContext(), pluginManager); + + initWebViewSettings(); + exposeJsInterface(); } - /** - * Create a default WebViewClient object for this webview. This can be overridden by the - * main application's CordovaActivity subclass. - */ - @Override - public CordovaChromeClient makeWebChromeClient() { - return (CordovaChromeClient) new AndroidChromeClient(this.cordova, this); - } - - /** - * Initialize webview. - */ + @SuppressLint("SetJavaScriptEnabled") @SuppressWarnings("deprecation") - @SuppressLint("NewApi") - private void setup() { + private void initWebViewSettings() { + this.setInitialScale(0); + this.setVerticalScrollBarEnabled(false); + // TODO: The Activity is the one that should call requestFocus(). + if (shouldRequestFocusOnInit()) { + this.requestFocusFromTouch(); + } this.setInitialScale(0); this.setVerticalScrollBarEnabled(false); if (shouldRequestFocusOnInit()) { - this.requestFocusFromTouch(); - } - // Enable JavaScript - WebSettings settings = this.getSettings(); + this.requestFocusFromTouch(); + } + // Enable JavaScript + final WebSettings settings = this.getSettings(); settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL); @@ -286,31 +202,17 @@ public class AndroidWebView extends WebView implements CordovaWebView { Level16Apis.enableUniversalAccess(settings); // Enable database // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16 - String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); + String databasePath = getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); settings.setDatabaseEnabled(true); settings.setDatabasePath(databasePath); //Determine whether we're in debug or release mode, and turn on Debugging! - try { - final String packageName = this.cordova.getActivity().getPackageName(); - final PackageManager pm = this.cordova.getActivity().getPackageManager(); - ApplicationInfo appInfo; - - appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); - - if((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 && - android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) - { - setWebContentsDebuggingEnabled(true); - } - } catch (IllegalArgumentException e) { - Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! "); - e.printStackTrace(); - } catch (NameNotFoundException e) { - Log.d(TAG, "This should never happen: Your application's package can't be found."); - e.printStackTrace(); - } + ApplicationInfo appInfo = getContext().getApplicationContext().getApplicationInfo(); + if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 && + android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + enableRemoteDebugging(); + } settings.setGeolocationDatabasePath(databasePath); @@ -323,13 +225,12 @@ public class AndroidWebView extends WebView implements CordovaWebView { // Enable AppCache // Fix for CB-2282 settings.setAppCacheMaxSize(5 * 1048576); - String pathToCache = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); - settings.setAppCachePath(pathToCache); + settings.setAppCachePath(databasePath); settings.setAppCacheEnabled(true); // Fix for CB-1405 // Google issue 4641 - this.updateUserAgentString(); + settings.getUserAgentString(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); @@ -337,18 +238,35 @@ public class AndroidWebView extends WebView implements CordovaWebView { this.receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - updateUserAgentString(); + settings.getUserAgentString(); } }; - this.cordova.getActivity().registerReceiver(this.receiver, intentFilter); + getContext().registerReceiver(this.receiver, intentFilter); } // end CB-1405 + } - pluginManager = new PluginManager(this, this.cordova); - jsMessageQueue = new NativeToJsMessageQueue(this, cordova); - exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue); - resourceApi = new CordovaResourceApi(this.getContext(), pluginManager); - exposeJsInterface(); + @TargetApi(Build.VERSION_CODES.KITKAT) + private void enableRemoteDebugging() { + try { + WebView.setWebContentsDebuggingEnabled(true); + } catch (IllegalArgumentException e) { + Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! "); + e.printStackTrace(); + } + } + + @Override + public CordovaChromeClient makeWebChromeClient(CordovaInterface cordova) { + return new AndroidChromeClient(cordova, this); + } + + @Override + public CordovaWebViewClient makeWebViewClient(CordovaInterface cordova) { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return new AndroidWebViewClient(cordova, this); + } + return new IceCreamCordovaWebViewClient(cordova, this); } /** @@ -361,13 +279,8 @@ public class AndroidWebView extends WebView implements CordovaWebView { return true; } - private void updateUserAgentString() { - this.getSettings().getUserAgentString(); - } - private void exposeJsInterface() { - int SDK_INT = Build.VERSION.SDK_INT; - if ((SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) { + if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) { Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); // Bug being that Java Strings do not get converted to JS strings automatically. // This isn't hard to work-around on the JS side, but it's easier to just @@ -377,21 +290,13 @@ public class AndroidWebView extends WebView implements CordovaWebView { this.addJavascriptInterface(exposedJsApi, "_cordovaNative"); } - /** - * Set the WebViewClient. - * - * @param client - */ + @Override public void setWebViewClient(CordovaWebViewClient client) { this.viewClient = client; super.setWebViewClient((WebViewClient) client); } - /** - * Set the WebChromeClient. - * - * @param client - */ + @Override public void setWebChromeClient(CordovaChromeClient client) { this.chromeClient = client; super.setWebChromeClient((WebChromeClient) client); @@ -650,21 +555,6 @@ public class AndroidWebView extends WebView implements CordovaWebView { } } - /** - * Check configuration parameters from Config. - * Approved list of URLs that can be loaded into Cordova - * - * Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR) - * - */ - private void loadConfiguration() { - - if ("true".equals(this.getProperty("Fullscreen", "false"))) { - this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); - this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - } - /** * Get string property for activity. * @@ -843,7 +733,7 @@ public class AndroidWebView extends WebView implements CordovaWebView { // unregister the receiver if (this.receiver != null) { try { - this.cordova.getActivity().unregisterReceiver(this.receiver); + getContext().unregisterReceiver(this.receiver); } catch (Exception e) { Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e); } diff --git a/framework/src/org/apache/cordova/AndroidWebViewClient.java b/framework/src/org/apache/cordova/AndroidWebViewClient.java index f3b295bf..047e1af2 100755 --- a/framework/src/org/apache/cordova/AndroidWebViewClient.java +++ b/framework/src/org/apache/cordova/AndroidWebViewClient.java @@ -18,20 +18,17 @@ */ package org.apache.cordova; -import java.io.ByteArrayInputStream; import java.util.Hashtable; import org.json.JSONException; import org.json.JSONObject; import android.annotation.TargetApi; -import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.net.http.SslError; -import android.util.Log; import android.view.View; import android.webkit.HttpAuthHandler; import android.webkit.SslErrorHandler; @@ -54,25 +51,15 @@ import android.webkit.WebViewClient; public class AndroidWebViewClient extends WebViewClient implements CordovaWebViewClient{ private static final String TAG = "AndroidWebViewClient"; - private static final String CORDOVA_EXEC_URL_PREFIX = "http://cdv_exec/"; - CordovaInterface cordova; - AndroidWebView appView; - CordovaUriHelper helper; + protected final CordovaInterface cordova; + protected final AndroidWebView appView; + protected final CordovaUriHelper helper; private boolean doClearHistory = false; boolean isCurrentlyLoading; /** The authorization tokens. */ private Hashtable authenticationTokens = new Hashtable(); - /** - * Constructor. - * - * @param cordova - */ - public AndroidWebViewClient(CordovaInterface cordova) { - this.cordova = cordova; - } - /** * Constructor. * @@ -85,16 +72,6 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie helper = new CordovaUriHelper(cordova, view); } - /** - * Constructor. - * - * @param view - */ - public void setWebView(AndroidWebView view) { - this.appView = view; - helper = new CordovaUriHelper(cordova, view); - } - /** * Give the host application a chance to take over the control when a new url * is about to be loaded in the current WebView. diff --git a/framework/src/org/apache/cordova/Config.java b/framework/src/org/apache/cordova/Config.java index 7865e004..dfb039d8 100644 --- a/framework/src/org/apache/cordova/Config.java +++ b/framework/src/org/apache/cordova/Config.java @@ -25,7 +25,7 @@ import android.util.Log; public class Config { private static final String TAG = "Config"; - private static ConfigXmlParser parser; + static ConfigXmlParser parser; private Config() { } diff --git a/framework/src/org/apache/cordova/ConfigXmlParser.java b/framework/src/org/apache/cordova/ConfigXmlParser.java index 8062168a..a5958efa 100644 --- a/framework/src/org/apache/cordova/ConfigXmlParser.java +++ b/framework/src/org/apache/cordova/ConfigXmlParser.java @@ -21,8 +21,6 @@ package org.apache.cordova; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -41,7 +39,6 @@ public class ConfigXmlParser { private CordovaPreferences prefs = new CordovaPreferences(); private Whitelist whitelist = new Whitelist(); private ArrayList pluginEntries = new ArrayList(20); - private HashMap> urlMap = new HashMap>(); public Whitelist getWhitelist() { return whitelist; @@ -59,10 +56,6 @@ public class ConfigXmlParser { return launchUrl; } - public HashMap> getPluginUrlMap() { - return urlMap; - } - public void parse(Activity action) { // First checking the class namespace for config.xml int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName()); @@ -82,16 +75,17 @@ public class ConfigXmlParser { String service = "", pluginClass = "", paramType = ""; boolean onload = false; boolean insideFeature = false; + ArrayList urlMap = null; + while (eventType != XmlResourceParser.END_DOCUMENT) { if (eventType == XmlResourceParser.START_TAG) { String strNode = xml.getName(); if (strNode.equals("url-filter")) { Log.w(TAG, "Plugin " + service + " is using deprecated tag "); - if (urlMap.get(service) == null) { - urlMap.put(service, new ArrayList(2)); + if (urlMap == null) { + urlMap = new ArrayList(2); } - List filters = urlMap.get(service); - filters.add(xml.getAttributeValue(null, "value")); + urlMap.add(xml.getAttributeValue(null, "value")); } else if (strNode.equals("feature")) { //Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc) //Set the bit for reading params @@ -130,12 +124,13 @@ public class ConfigXmlParser { { String strNode = xml.getName(); if (strNode.equals("feature")) { - pluginEntries.add(new PluginEntry(service, pluginClass, onload)); + pluginEntries.add(new PluginEntry(service, pluginClass, onload, urlMap)); service = ""; pluginClass = ""; insideFeature = false; onload = false; + urlMap = null; } } try { diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java index d8e218a3..e55a653f 100755 --- a/framework/src/org/apache/cordova/CordovaActivity.java +++ b/framework/src/org/apache/cordova/CordovaActivity.java @@ -20,8 +20,8 @@ package org.apache.cordova; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.HashMap; -import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -46,7 +46,6 @@ import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.Display; -import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -59,7 +58,7 @@ import android.widget.LinearLayout; /** * This class is the main Android activity that represents the Cordova - * application. It should be extended by the user to load the specific + * application. It should be extended by the user to load the specific * html file that contains the application. * * As an example: @@ -74,9 +73,8 @@ import android.widget.LinearLayout; * @Override * public void onCreate(Bundle savedInstanceState) { * super.onCreate(savedInstanceState); - * super.init(); * // Load your application - * super.loadUrl(Config.getStartUrl()); + * loadUrl(launchUrl); * } * } * @@ -93,9 +91,13 @@ public class CordovaActivity extends Activity implements CordovaInterface { // The webview for our app protected CordovaWebView appView; + + @Deprecated // unused. protected CordovaWebViewClient webViewClient; + @Deprecated // Will be removed. Use findViewById() to retrieve views. protected LinearLayout root; + protected ProgressDialog spinnerDialog = null; private final ExecutorService threadPool = Executors.newCachedThreadPool(); @@ -108,10 +110,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { protected CordovaPlugin activityResultCallback = null; protected boolean activityResultKeepRunning; - // Default background color for activity - // (this is not the color for the webview, which is set in HTML) - private int backgroundColor = Color.BLACK; - /* * The variables below are used to cache some of the activity properties. */ @@ -131,13 +129,17 @@ public class CordovaActivity extends Activity implements CordovaInterface { private String initCallbackClass; + // Read from config.xml: + protected CordovaPreferences preferences; + protected Whitelist whitelist; + protected String launchUrl; + protected ArrayList pluginEntries; + /** * Called when the activity is first created. */ - @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { - Config.init(this); LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting"); LOG.d(TAG, "CordovaActivity.onCreate()"); super.onCreate(savedInstanceState); @@ -147,22 +149,55 @@ public class CordovaActivity extends Activity implements CordovaInterface { initCallbackClass = savedInstanceState.getString("callbackClass"); } - if(!this.getBooleanProperty("ShowTitle", false)) + loadConfig(); + + if(!preferences.getBoolean("ShowTitle", false)) { getWindow().requestFeature(Window.FEATURE_NO_TITLE); } - if(this.getBooleanProperty("SetFullscreen", false)) + if(preferences.getBoolean("SetFullscreen", false)) { Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version."); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - else - { + } else if (preferences.getBoolean("Fullscreen", false)) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); } + + appView = makeWebView(); + appView.init(this, makeWebViewClient(appView), makeChromeClient(appView), pluginEntries); + + // TODO: Have the views set this themselves. + if (preferences.getBoolean("DisallowOverscroll", false)) { + appView.setOverScrollMode(View.OVER_SCROLL_NEVER); + } + createViews(); + + // TODO: Make this a preference (CB-6153) + // Setup the hardware volume controls to handle volume control + setVolumeControlStream(AudioManager.STREAM_MUSIC); + } + + protected void loadConfig() { + ConfigXmlParser parser = new ConfigXmlParser(); + parser.parse(this); + preferences = parser.getPreferences(); + preferences.setPreferencesBundle(getIntent().getExtras()); + preferences.copyIntoIntentExtras(this); + whitelist = parser.getWhitelist(); + launchUrl = parser.getLaunchUrl(); + pluginEntries = parser.getPluginEntries(); + Config.parser = parser; + } + + @SuppressWarnings("deprecation") + protected void createViews() { + // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); @@ -170,20 +205,29 @@ public class CordovaActivity extends Activity implements CordovaInterface { root = new LinearLayoutSoftKeyboardDetect(this, width, height); root.setOrientation(LinearLayout.VERTICAL); - root.setBackgroundColor(this.backgroundColor); root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); - // Setup the hardware volume controls to handle volume control - setVolumeControlStream(AudioManager.STREAM_MUSIC); + appView.setId(100); + appView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + 1.0F)); + + // Add web view but make it invisible while loading URL + appView.setVisibility(View.INVISIBLE); + root.addView((View) appView); + setContentView(root); + + // TODO: Setting this on the appView causes it to show when . + int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK); + root.setBackgroundColor(backgroundColor); } /** * Get the Android activity. - * - * @return the Activity */ - public Activity getActivity() { + @Override public Activity getActivity() { return this; } @@ -194,16 +238,16 @@ public class CordovaActivity extends Activity implements CordovaInterface { * require a more specialized web view. */ protected CordovaWebView makeWebView() { - String r = this.getStringProperty("webView", "org.apache.cordova.AndroidWebView"); + String r = preferences.getString("webView", "org.apache.cordova.AndroidWebView"); try { - Class webViewClass = Class.forName(r); - Constructor [] webViewConstructors = webViewClass.getConstructors(); + Class webViewClass = Class.forName(r); + Constructor[] webViewConstructors = webViewClass.getConstructors(); if(CordovaWebView.class.isAssignableFrom(webViewClass)) { - for (Constructor constructor : webViewConstructors) { + for (Constructor constructor : webViewConstructors) { try { - CordovaWebView webView = (CordovaWebView) constructor.newInstance(this); + CordovaWebView webView = (CordovaWebView) constructor.newInstance((Context)this); return webView; } catch (IllegalArgumentException e) { LOG.d(TAG, "Illegal arguments; trying next constructor."); @@ -224,7 +268,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { } // If all else fails, return a default WebView - return (CordovaWebView) new AndroidWebView(CordovaActivity.this); + return (CordovaWebView) new AndroidWebView(this); } /** @@ -237,7 +281,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { * @param webView the default constructed web view object */ protected CordovaWebViewClient makeWebViewClient(CordovaWebView webView) { - return webView.makeWebViewClient(); + return webView.makeWebViewClient(this); } /** @@ -250,77 +294,44 @@ public class CordovaActivity extends Activity implements CordovaInterface { * @param webView the default constructed web view object */ protected CordovaChromeClient makeChromeClient(CordovaWebView webView) { - return webView.makeWebChromeClient(); + return webView.makeWebChromeClient(this); } - /** - * Create and initialize web container with default web view objects. - */ + @Deprecated // No need to call init() anymore. public void init() { - CordovaWebView webView = makeWebView(); - this.init(webView, makeWebViewClient(webView), makeChromeClient(webView)); + this.init(appView, null, null); } - /** - * Initialize web container with web view objects. - * - * @param webView - * @param webViewClient - * @param webChromeClient - */ @SuppressLint("NewApi") + @Deprecated // No need to call init() anymore. public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) { LOG.d(TAG, "CordovaActivity.init()"); - // Set up web container - this.appView = webView; - this.appView.setId(100); + appView = webView; - this.appView.setWebViewClient(webViewClient); - this.appView.setWebChromeClient(webChromeClient); - - this.appView.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - 1.0F)); - - if (this.getBooleanProperty("DisallowOverscroll", false)) { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) { - //Note: We're using the parent class, because all we know is that this will be a view - this.appView.setOverScrollMode(View.OVER_SCROLL_NEVER); - } + if (webViewClient != null) { + this.appView.setWebViewClient(webViewClient); + } + if (webChromeClient != null) { + this.appView.setWebChromeClient(webChromeClient); } - - // Add web view but make it invisible while loading URL - this.appView.setVisibility(View.INVISIBLE); - this.root.addView((View) this.appView.getView()); - setContentView(this.root); } /** * Load the url into the webview. */ public void loadUrl(String url) { - - // Init web view if not already done - if (this.appView == null) { - this.init(); - } - - this.splashscreenTime = this.getIntegerProperty("SplashScreenDelay", this.splashscreenTime); - if(this.splashscreenTime > 0) + this.splashscreenTime = preferences.getInteger("SplashScreenDelay", this.splashscreenTime); + String splash = preferences.getString("SplashScreen", null); + if(this.splashscreenTime > 0 && splash != null) { - this.splashscreen = this.getIntegerProperty("SplashScreen", 0); + this.splashscreen = getResources().getIdentifier(splash, "drawable", getClass().getPackage().getName());; if(this.splashscreen != 0) { this.showSplashScreen(this.splashscreenTime); } } - // Set backgroundColor - this.backgroundColor = this.getIntegerProperty("BackgroundColor", Color.BLACK); - this.root.setBackgroundColor(this.backgroundColor); - // If keepRunning this.keepRunning = this.getBooleanProperty("KeepRunning", true); @@ -391,16 +402,15 @@ public class CordovaActivity extends Activity implements CordovaInterface { /** * Clear the resource cache. */ + @Deprecated // Call method on appView directly. public void clearCache() { - if (this.appView == null) { - this.init(); - } this.appView.clearCache(true); } /** * Clear web history in this web view. */ + @Deprecated // Call method on appView directly. public void clearHistory() { this.appView.clearHistory(); } @@ -410,6 +420,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { * * @return true if we went back, false if we are already at top */ + @Deprecated // Call method on appView directly. public boolean backHistory() { if (this.appView != null) { return appView.backHistory(); @@ -419,103 +430,34 @@ public class CordovaActivity extends Activity implements CordovaInterface { /** * Get boolean property for activity. - * - * @param name - * @param defaultValue - * @return the boolean value of the named property */ + @Deprecated // Call method on preferences directly. public boolean getBooleanProperty(String name, boolean defaultValue) { - Bundle bundle = this.getIntent().getExtras(); - if (bundle == null) { - return defaultValue; - } - name = name.toLowerCase(Locale.getDefault()); - Boolean p; - try { - p = (Boolean) bundle.get(name); - } catch (ClassCastException e) { - String s = bundle.get(name).toString(); - if ("true".equals(s)) { - p = true; - } - else { - p = false; - } - } - if (p == null) { - return defaultValue; - } - return p.booleanValue(); + return preferences.getBoolean(name, defaultValue); } /** * Get int property for activity. - * - * @param name - * @param defaultValue - * @return the int value for the named property */ + @Deprecated // Call method on preferences directly. public int getIntegerProperty(String name, int defaultValue) { - Bundle bundle = this.getIntent().getExtras(); - if (bundle == null) { - return defaultValue; - } - name = name.toLowerCase(Locale.getDefault()); - Integer p; - try { - p = (Integer) bundle.get(name); - } catch (ClassCastException e) { - p = Integer.parseInt(bundle.get(name).toString()); - } - if (p == null) { - return defaultValue; - } - return p.intValue(); + return preferences.getInteger(name, defaultValue); } /** * Get string property for activity. - * - * @param name - * @param defaultValue - * @return the String value for the named property */ + @Deprecated // Call method on preferences directly. public String getStringProperty(String name, String defaultValue) { - Bundle bundle = this.getIntent().getExtras(); - if (bundle == null) { - return defaultValue; - } - name = name.toLowerCase(Locale.getDefault()); - String p = bundle.getString(name); - if (p == null) { - return defaultValue; - } - return p; + return preferences.getString(name, defaultValue); } /** * Get double property for activity. - * - * @param name - * @param defaultValue - * @return the double value for the named property */ + @Deprecated // Call method on preferences directly. public double getDoubleProperty(String name, double defaultValue) { - Bundle bundle = this.getIntent().getExtras(); - if (bundle == null) { - return defaultValue; - } - name = name.toLowerCase(Locale.getDefault()); - Double p; - try { - p = (Double) bundle.get(name); - } catch (ClassCastException e) { - p = Double.parseDouble(bundle.get(name).toString()); - } - if (p == null) { - return defaultValue; - } - return p.doubleValue(); + return preferences.getDouble(name, defaultValue); } /** @@ -562,8 +504,6 @@ public class CordovaActivity extends Activity implements CordovaInterface { protected void onResume() { super.onResume(); LOG.d(TAG, "Resuming the App"); - //Reload the configuration - Config.init(this); if (this.activityState == ACTIVITY_STARTING) { this.activityState = ACTIVITY_RUNNING; @@ -622,6 +562,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { * @param statement * */ + @Deprecated // Call method on appView directly. public void sendJavascript(String statement) { if (this.appView != null) { this.appView.addJavascript(statement); @@ -846,6 +787,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { * @param clearHistory Clear the history stack, so new page becomes top of history * @param params Parameters for new app */ + @Deprecated // Call method on appView directly. public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap params) { if (this.appView != null) { appView.showWebPage(url, openExternal, clearHistory, params); diff --git a/framework/src/org/apache/cordova/CordovaPreferences.java b/framework/src/org/apache/cordova/CordovaPreferences.java index 9fa1898f..4b9eb373 100644 --- a/framework/src/org/apache/cordova/CordovaPreferences.java +++ b/framework/src/org/apache/cordova/CordovaPreferences.java @@ -48,7 +48,7 @@ public class CordovaPreferences { name = name.toLowerCase(Locale.ENGLISH); String value = prefs.get(name); if (value != null) { - return "true".equals(value); + return Boolean.parseBoolean(value); } else if (preferencesBundleExtras != null) { Object bundleValue = preferencesBundleExtras.get(name); if (bundleValue instanceof String) { @@ -64,7 +64,8 @@ public class CordovaPreferences { name = name.toLowerCase(Locale.ENGLISH); String value = prefs.get(name); if (value != null) { - return Integer.valueOf(value); + // Use Integer.decode() can't handle it if the highest bit is set. + return (int)(long)Long.decode(value); } else if (preferencesBundleExtras != null) { Object bundleValue = preferencesBundleExtras.get(name); if (bundleValue instanceof String) { @@ -123,30 +124,30 @@ public class CordovaPreferences { action.getIntent().putExtra(name, resource); } else if(name.equals("backgroundcolor")) { - int asInt = Integer.valueOf(value); + int asInt = (int)(long)Long.decode(value); action.getIntent().putExtra(name, asInt); } else if(name.equals("loadurltimeoutvalue")) { - int asInt = Integer.valueOf(value); + int asInt = Integer.decode(value); action.getIntent().putExtra(name, asInt); } else if(name.equals("splashscreendelay")) { - int asInt = Integer.valueOf(value); + int asInt = Integer.decode(value); action.getIntent().putExtra(name, asInt); } else if(name.equals("keeprunning")) { - boolean asBool = "true".equals(value); + boolean asBool = Boolean.parseBoolean(value); action.getIntent().putExtra(name, asBool); } else if(name.equals("inappbrowserstorageenabled")) { - boolean asBool = "true".equals(value); + boolean asBool = Boolean.parseBoolean(value); action.getIntent().putExtra(name, asBool); } else if(name.equals("disallowoverscroll")) { - boolean asBool = "true".equals(value); + boolean asBool = Boolean.parseBoolean(value); action.getIntent().putExtra(name, asBool); } else @@ -154,5 +155,9 @@ public class CordovaPreferences { action.getIntent().putExtra(name, value); } } + // In the normal case, the intent extras are null until the first call to putExtra(). + if (preferencesBundleExtras == null) { + preferencesBundleExtras = action.getIntent().getExtras(); + } } } diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java index ac73ecbd..dc871ac8 100644 --- a/framework/src/org/apache/cordova/CordovaWebView.java +++ b/framework/src/org/apache/cordova/CordovaWebView.java @@ -1,12 +1,10 @@ package org.apache.cordova; import java.util.HashMap; - -import org.json.JSONException; +import java.util.List; import android.content.Context; import android.content.Intent; -import android.view.KeyEvent; import android.view.View; import android.webkit.WebChromeClient.CustomViewCallback; import android.widget.LinearLayout.LayoutParams; @@ -14,12 +12,14 @@ import android.widget.LinearLayout.LayoutParams; public interface CordovaWebView { public static final String CORDOVA_VERSION = "4.0.0-dev"; + void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient, List pluginEntries); + View getView(); - CordovaWebViewClient makeWebViewClient(); - - CordovaChromeClient makeWebChromeClient(); + CordovaWebViewClient makeWebViewClient(CordovaInterface cordova); + CordovaChromeClient makeWebChromeClient(CordovaInterface cordova); + void setWebViewClient(CordovaWebViewClient webViewClient); void setWebChromeClient(CordovaChromeClient webChromeClient); @@ -132,4 +132,5 @@ public interface CordovaWebView { // Required for test String getUrl(); boolean isPaused(); + } diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java index 3c6ad215..1a29510d 100644 --- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java +++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java @@ -35,12 +35,7 @@ import android.webkit.WebView; public class IceCreamCordovaWebViewClient extends AndroidWebViewClient implements CordovaWebViewClient{ private static final String TAG = "IceCreamCordovaWebViewClient"; - private CordovaUriHelper helper; - public IceCreamCordovaWebViewClient(CordovaInterface cordova) { - super(cordova); - } - public IceCreamCordovaWebViewClient(CordovaInterface cordova, AndroidWebView view) { super(cordova, view); } diff --git a/framework/src/org/apache/cordova/PluginEntry.java b/framework/src/org/apache/cordova/PluginEntry.java index dcc19743..c54f6cb2 100755 --- a/framework/src/org/apache/cordova/PluginEntry.java +++ b/framework/src/org/apache/cordova/PluginEntry.java @@ -18,12 +18,12 @@ */ package org.apache.cordova; +import java.util.List; + import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; -//import android.content.Context; -//import android.webkit.WebView; /** * This class represents a service entry object. @@ -52,30 +52,36 @@ public class PluginEntry { */ public boolean onload = false; + private List urlFilters; + + /** + * @param service The name of the service + * @param plugin The plugin associated with this entry + */ + public PluginEntry(String service, CordovaPlugin plugin) { + this(service, plugin.getClass().getName(), true, null); + this.plugin = plugin; + } + /** - * Constructor - * * @param service The name of the service * @param pluginClass The plugin class name * @param onload Create plugin object when HTML page is loaded */ public PluginEntry(String service, String pluginClass, boolean onload) { + this(service, pluginClass, onload, null); + } + + + public PluginEntry(String service, String pluginClass, boolean onload, List urlFilters) { this.service = service; this.pluginClass = pluginClass; this.onload = onload; + this.urlFilters = urlFilters; } - /** - * Alternate constructor - * - * @param service The name of the service - * @param plugin The plugin associated with this entry - */ - public PluginEntry(String service, CordovaPlugin plugin) { - this.service = service; - this.plugin = plugin; - this.pluginClass = plugin.getClass().getName(); - this.onload = false; + public List getUrlFilters() { + return urlFilters; } /** @@ -89,8 +95,7 @@ public class PluginEntry { return this.plugin; } try { - @SuppressWarnings("rawtypes") - Class c = getClassByName(this.pluginClass); + Class c = getClassByName(this.pluginClass); if (isCordovaPlugin(c)) { this.plugin = (CordovaPlugin) c.newInstance(); this.plugin.initialize(ctx, webView); @@ -110,9 +115,8 @@ public class PluginEntry { * @return a reference to the named class * @throws ClassNotFoundException */ - @SuppressWarnings("rawtypes") - private Class getClassByName(final String clazz) throws ClassNotFoundException { - Class c = null; + private Class getClassByName(final String clazz) throws ClassNotFoundException { + Class c = null; if ((clazz != null) && !("".equals(clazz))) { c = Class.forName(clazz); } @@ -122,10 +126,9 @@ public class PluginEntry { /** * Returns whether the given class extends CordovaPlugin. */ - @SuppressWarnings("rawtypes") - private boolean isCordovaPlugin(Class c) { + private boolean isCordovaPlugin(Class c) { if (c != null) { - return org.apache.cordova.CordovaPlugin.class.isAssignableFrom(c); + return CordovaPlugin.class.isAssignableFrom(c); } return false; } diff --git a/framework/src/org/apache/cordova/PluginManager.java b/framework/src/org/apache/cordova/PluginManager.java index 13c55c89..7ba9450e 100755 --- a/framework/src/org/apache/cordova/PluginManager.java +++ b/framework/src/org/apache/cordova/PluginManager.java @@ -19,7 +19,6 @@ package org.apache.cordova; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -54,13 +53,28 @@ public class PluginManager { // Stores mapping of Plugin Name -> values. // Using is deprecated. - protected HashMap> urlMap; + protected HashMap> urlMap = new HashMap>(); private Set pluginIdWhitelist; - public PluginManager(CordovaWebView app, CordovaInterface ctx) { - this.ctx = ctx; - this.app = app; + PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, List pluginEntries) { + this.ctx = cordova; + this.app = cordovaWebView; + if (pluginEntries == null) { + ConfigXmlParser parser = new ConfigXmlParser(); + parser.parse(ctx.getActivity()); + pluginEntries = parser.getPluginEntries(); + } + setPluginEntries(pluginEntries); + } + + public void setPluginEntries(List pluginEntries) { + this.onPause(false); + this.onDestroy(); + this.clearPluginObjects(); + for (PluginEntry entry : pluginEntries) { + addService(entry); + } } public void setPluginIdWhitelist(Set pluginIdWhitelist) { @@ -72,33 +86,14 @@ public class PluginManager { */ public void init() { LOG.d(TAG, "init()"); - - // If first time, then load plugins from config.xml file - if (urlMap == null) { - this.loadPlugins(); - } - - // Stop plugins on current HTML page and discard plugin objects - else { - this.onPause(false); - this.onDestroy(); - this.clearPluginObjects(); - } - - // Start up all plugins that have onload specified + this.onPause(false); + this.onDestroy(); + this.clearPluginObjects(); this.startupPlugins(); } - /** - * Load plugins from res/xml/config.xml - */ + @Deprecated public void loadPlugins() { - ConfigXmlParser parser = new ConfigXmlParser(); - parser.parse(ctx.getActivity()); - for (PluginEntry entry : parser.getPluginEntries()) { - addService(entry); - } - urlMap = parser.getPluginUrlMap(); } /** @@ -219,6 +214,10 @@ public class PluginManager { */ public void addService(PluginEntry entry) { this.entries.put(entry.service, entry); + List urlFilters = entry.getUrlFilters(); + if (urlFilters != null) { + urlMap.put(entry.service, urlFilters); + } } /** @@ -324,11 +323,9 @@ public class PluginManager { * Called when the app navigates or refreshes. */ public void onReset() { - Iterator it = this.entries.values().iterator(); - while (it.hasNext()) { - CordovaPlugin plugin = it.next().plugin; - if (plugin != null) { - plugin.onReset(); + for (PluginEntry entry : this.entries.values()) { + if (entry.plugin != null) { + entry.plugin.onReset(); } } }