You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/01/22 02:57:58 UTC

[37/52] [partial] support for 2.4.0rc1. "vendored" the platform libs in. added Gord and Braden as contributors. removed dependency on unzip and axed the old download-cordova code.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
new file mode 100755
index 0000000..83e1778
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -0,0 +1,484 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+
+import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.PluginResult;
+
+import android.os.Message;
+import android.util.Log;
+import android.webkit.WebView;
+
+/**
+ * Holds the list of messages to be sent to the WebView.
+ */
+public class NativeToJsMessageQueue {
+    private static final String LOG_TAG = "JsMessageQueue";
+
+    // This must match the default value in incubator-cordova-js/lib/android/exec.js
+    private static final int DEFAULT_BRIDGE_MODE = 2;
+    
+    // Set this to true to force plugin results to be encoding as
+    // JS instead of the custom format (useful for benchmarking).
+    private static final boolean FORCE_ENCODE_USING_EVAL = false;
+
+    // Disable URL-based exec() bridge by default since it's a bit of a
+    // security concern.
+    static final boolean ENABLE_LOCATION_CHANGE_EXEC_MODE = false;
+        
+    // Disable sending back native->JS messages during an exec() when the active
+    // exec() is asynchronous. Set this to true when running bridge benchmarks.
+    static final boolean DISABLE_EXEC_CHAINING = false;
+    
+    // Upper limit for how much data to send to JS in one shot.
+    // TODO(agrieve): This is currently disable. It should be re-enabled once we
+    // remove support for returning values from exec() calls. This was
+    // deprecated in 2.2.0.
+    // Also, this currently only chops up on message boundaries. It may be useful
+    // to allow it to break up messages.
+    private static int MAX_PAYLOAD_SIZE = -1; //50 * 1024 * 10240;
+    
+    /**
+     * The index into registeredListeners to treat as active. 
+     */
+    private int activeListenerIndex;
+    
+    /**
+     * When true, the active listener is not fired upon enqueue. When set to false,
+     * the active listener will be fired if the queue is non-empty. 
+     */
+    private boolean paused;
+    
+    /**
+     * The list of JavaScript statements to be sent to JavaScript.
+     */
+    private final LinkedList<JsMessage> queue = new LinkedList<JsMessage>();
+
+    /**
+     * The array of listeners that can be used to send messages to JS.
+     */
+    private final BridgeMode[] registeredListeners;    
+    
+    private final CordovaInterface cordova;
+    private final CordovaWebView webView;
+
+    public NativeToJsMessageQueue(CordovaWebView webView, CordovaInterface cordova) {
+        this.cordova = cordova;
+        this.webView = webView;
+        registeredListeners = new BridgeMode[4];
+        registeredListeners[0] = null;  // Polling. Requires no logic.
+        registeredListeners[1] = new LoadUrlBridgeMode();
+        registeredListeners[2] = new OnlineEventsBridgeMode();
+        registeredListeners[3] = new PrivateApiBridgeMode();
+        reset();
+    }
+    
+    /**
+     * Changes the bridge mode.
+     */
+    public void setBridgeMode(int value) {
+        if (value < 0 || value >= registeredListeners.length) {
+            Log.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value);
+        } else {
+            if (value != activeListenerIndex) {
+                Log.d(LOG_TAG, "Set native->JS mode to " + value);
+                synchronized (this) {
+                    activeListenerIndex = value;
+                    BridgeMode activeListener = registeredListeners[value];
+                    if (!paused && !queue.isEmpty() && activeListener != null) {
+                        activeListener.onNativeToJsMessageAvailable();
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Clears all messages and resets to the default bridge mode.
+     */
+    public void reset() {
+        synchronized (this) {
+            queue.clear();
+            setBridgeMode(DEFAULT_BRIDGE_MODE);
+        }
+    }
+
+    private int calculatePackedMessageLength(JsMessage message) {
+        int messageLen = message.calculateEncodedLength();
+        String messageLenStr = String.valueOf(messageLen);
+        return messageLenStr.length() + messageLen + 1;        
+    }
+    
+    private void packMessage(JsMessage message, StringBuilder sb) {
+        int len = message.calculateEncodedLength();
+        sb.append(len)
+          .append(' ');
+        message.encodeAsMessage(sb);
+    }
+    
+    /**
+     * Combines and returns queued messages combined into a single string.
+     * Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE.
+     * Returns null if the queue is empty.
+     */
+    public String popAndEncode() {
+        synchronized (this) {
+            if (queue.isEmpty()) {
+                return null;
+            }
+            int totalPayloadLen = 0;
+            int numMessagesToSend = 0;
+            for (JsMessage message : queue) {
+                int messageSize = calculatePackedMessageLength(message);
+                if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
+                    break;
+                }
+                totalPayloadLen += messageSize;
+                numMessagesToSend += 1;
+            }
+
+            StringBuilder sb = new StringBuilder(totalPayloadLen);
+            for (int i = 0; i < numMessagesToSend; ++i) {
+                JsMessage message = queue.removeFirst();
+                packMessage(message, sb);
+            }
+            
+            if (!queue.isEmpty()) {
+                // Attach a char to indicate that there are more messages pending.
+                sb.append('*');
+            }
+            String ret = sb.toString();
+            return ret;
+        }
+    }
+    
+    /**
+     * Same as popAndEncode(), except encodes in a form that can be executed as JS.
+     */
+    private String popAndEncodeAsJs() {
+        synchronized (this) {
+            int length = queue.size();
+            if (length == 0) {
+                return null;
+            }
+            int totalPayloadLen = 0;
+            int numMessagesToSend = 0;
+            for (JsMessage message : queue) {
+                int messageSize = message.calculateEncodedLength() + 50; // overestimate.
+                if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
+                    break;
+                }
+                totalPayloadLen += messageSize;
+                numMessagesToSend += 1;
+            }
+            boolean willSendAllMessages = numMessagesToSend == queue.size();
+            StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100));
+            // Wrap each statement in a try/finally so that if one throws it does 
+            // not affect the next.
+            for (int i = 0; i < numMessagesToSend; ++i) {
+                JsMessage message = queue.removeFirst();
+                if (willSendAllMessages && (i + 1 == numMessagesToSend)) {
+                    message.encodeAsJsMessage(sb);
+                } else {
+                    sb.append("try{");
+                    message.encodeAsJsMessage(sb);
+                    sb.append("}finally{");
+                }
+            }
+            if (!willSendAllMessages) {
+                sb.append("window.setTimeout(function(){cordova.require('cordova/plugin/android/polling').pollOnce();},0);");
+            }
+            for (int i = willSendAllMessages ? 1 : 0; i < numMessagesToSend; ++i) {
+                sb.append('}');
+            }
+            String ret = sb.toString();
+            return ret;
+        }
+    }   
+
+    /**
+     * Add a JavaScript statement to the list.
+     */
+    public void addJavaScript(String statement) {
+        enqueueMessage(new JsMessage(statement));
+    }
+
+    /**
+     * Add a JavaScript statement to the list.
+     */
+    public void addPluginResult(PluginResult result, String callbackId) {
+        if (callbackId == null) {
+            Log.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable());
+            return;
+        }
+        // Don't send anything if there is no result and there is no need to
+        // clear the callbacks.
+        boolean noResult = result.getStatus() == PluginResult.Status.NO_RESULT.ordinal();
+        boolean keepCallback = result.getKeepCallback();
+        if (noResult && keepCallback) {
+            return;
+        }
+        JsMessage message = new JsMessage(result, callbackId);
+        if (FORCE_ENCODE_USING_EVAL) {
+            StringBuilder sb = new StringBuilder(message.calculateEncodedLength() + 50);
+            message.encodeAsJsMessage(sb);
+            message = new JsMessage(sb.toString());
+        }
+
+        enqueueMessage(message);
+    }
+    
+    private void enqueueMessage(JsMessage message) {
+        synchronized (this) {
+            queue.add(message);
+            if (!paused && registeredListeners[activeListenerIndex] != null) {
+                registeredListeners[activeListenerIndex].onNativeToJsMessageAvailable();
+            }
+        }        
+    }
+    
+    public void setPaused(boolean value) {
+        if (paused && value) {
+            // This should never happen. If a use-case for it comes up, we should
+            // change pause to be a counter.
+            Log.e(LOG_TAG, "nested call to setPaused detected.", new Throwable());
+        }
+        paused = value;
+        if (!value) {
+            synchronized (this) {
+                if (!queue.isEmpty() && registeredListeners[activeListenerIndex] != null) {
+                    registeredListeners[activeListenerIndex].onNativeToJsMessageAvailable();
+                }
+            }   
+        }
+    }
+    
+    public boolean getPaused() {
+        return paused;
+    }
+
+    private interface BridgeMode {
+        void onNativeToJsMessageAvailable();
+    }
+    
+    /** Uses webView.loadUrl("javascript:") to execute messages. */
+    private class LoadUrlBridgeMode implements BridgeMode {
+        final Runnable runnable = new Runnable() {
+            public void run() {
+                String js = popAndEncodeAsJs();
+                if (js != null) {
+                    webView.loadUrlNow("javascript:" + js);
+                }
+            }
+        };
+        
+        public void onNativeToJsMessageAvailable() {
+            cordova.getActivity().runOnUiThread(runnable);
+        }
+    }
+
+    /** Uses online/offline events to tell the JS when to poll for messages. */
+    private class OnlineEventsBridgeMode implements BridgeMode {
+        boolean online = true;
+        final Runnable runnable = new Runnable() {
+            public void run() {
+                if (!queue.isEmpty()) {
+                    online = !online;
+                    webView.setNetworkAvailable(online);
+                }
+            }                
+        };
+        OnlineEventsBridgeMode() {
+            webView.setNetworkAvailable(true);
+        }
+        public void onNativeToJsMessageAvailable() {
+            cordova.getActivity().runOnUiThread(runnable);
+        }
+    }
+    
+    /**
+     * Uses Java reflection to access an API that lets us eval JS.
+     * Requires Android 3.2.4 or above. 
+     */
+    private class PrivateApiBridgeMode implements BridgeMode {
+    	// Message added in commit:
+    	// http://omapzoom.org/?p=platform/frameworks/base.git;a=commitdiff;h=9497c5f8c4bc7c47789e5ccde01179abc31ffeb2
+    	// Which first appeared in 3.2.4ish.
+    	private static final int EXECUTE_JS = 194;
+    	
+    	Method sendMessageMethod;
+    	Object webViewCore;
+    	boolean initFailed;
+
+    	@SuppressWarnings("rawtypes")
+    	private void initReflection() {
+        	Object webViewObject = webView;
+    		Class webViewClass = WebView.class;
+        	try {
+    			Field f = webViewClass.getDeclaredField("mProvider");
+    			f.setAccessible(true);
+    			webViewObject = f.get(webView);
+    			webViewClass = webViewObject.getClass();
+        	} catch (Throwable e) {
+        		// mProvider is only required on newer Android releases.
+    		}
+        	
+        	try {
+    			Field f = webViewClass.getDeclaredField("mWebViewCore");
+                f.setAccessible(true);
+    			webViewCore = f.get(webViewObject);
+    			
+    			if (webViewCore != null) {
+    				sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class);
+	    			sendMessageMethod.setAccessible(true);	    			
+    			}
+    		} catch (Throwable e) {
+    			initFailed = true;
+				Log.e(LOG_TAG, "PrivateApiBridgeMode failed to find the expected APIs.", e);
+    		}
+    	}
+    	
+        public void onNativeToJsMessageAvailable() {
+        	if (sendMessageMethod == null && !initFailed) {
+        		initReflection();
+        	}
+        	// webViewCore is lazily initialized, and so may not be available right away.
+        	if (sendMessageMethod != null) {
+	        	String js = popAndEncodeAsJs();
+	        	Message execJsMessage = Message.obtain(null, EXECUTE_JS, js);
+				try {
+				    sendMessageMethod.invoke(webViewCore, execJsMessage);
+				} catch (Throwable e) {
+					Log.e(LOG_TAG, "Reflection message bridge failed.", e);
+				}
+        	}
+        }
+    }    
+    private static class JsMessage {
+        final String jsPayloadOrCallbackId;
+        final PluginResult pluginResult;
+        JsMessage(String js) {
+            if (js == null) {
+                throw new NullPointerException();
+            }
+            jsPayloadOrCallbackId = js;
+            pluginResult = null;
+        }
+        JsMessage(PluginResult pluginResult, String callbackId) {
+            if (callbackId == null || pluginResult == null) {
+                throw new NullPointerException();
+            }
+            jsPayloadOrCallbackId = callbackId;
+            this.pluginResult = pluginResult;
+        }
+        
+        int calculateEncodedLength() {
+            if (pluginResult == null) {
+                return jsPayloadOrCallbackId.length() + 1;
+            }
+            int statusLen = String.valueOf(pluginResult.getStatus()).length();
+            int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;
+            switch (pluginResult.getMessageType()) {
+                case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
+                case PluginResult.MESSAGE_TYPE_NULL: // N
+                    ret += 1;
+                    break;
+                case PluginResult.MESSAGE_TYPE_NUMBER: // n
+                    ret += 1 + pluginResult.getMessage().length();
+                    break;
+                case PluginResult.MESSAGE_TYPE_STRING: // s
+                    ret += 1 + pluginResult.getStrMessage().length();
+                    break;
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                    ret += 1 + pluginResult.getMessage().length();
+                    break;
+                case PluginResult.MESSAGE_TYPE_JSON:
+                default:
+                    ret += pluginResult.getMessage().length();
+            }
+            return ret;
+        }
+        
+        void encodeAsMessage(StringBuilder sb) {
+            if (pluginResult == null) {
+                sb.append('J')
+                  .append(jsPayloadOrCallbackId);
+                return;
+            }
+            int status = pluginResult.getStatus();
+            boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
+            boolean resultOk = status == PluginResult.Status.OK.ordinal();
+            boolean keepCallback = pluginResult.getKeepCallback();
+
+            sb.append((noResult || resultOk) ? 'S' : 'F')
+              .append(keepCallback ? '1' : '0')
+              .append(status)
+              .append(' ')
+              .append(jsPayloadOrCallbackId)
+              .append(' ');
+            switch (pluginResult.getMessageType()) {
+                case PluginResult.MESSAGE_TYPE_BOOLEAN:
+                    sb.append(pluginResult.getMessage().charAt(0)); // t or f.
+                    break;
+                case PluginResult.MESSAGE_TYPE_NULL: // N
+                    sb.append('N');
+                    break;
+                case PluginResult.MESSAGE_TYPE_NUMBER: // n
+                    sb.append('n')
+                      .append(pluginResult.getMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_STRING: // s
+                    sb.append('s');
+                    sb.append(pluginResult.getStrMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                    sb.append('A');
+                    sb.append(pluginResult.getMessage());
+                    break;
+                case PluginResult.MESSAGE_TYPE_JSON:
+                default:
+                    sb.append(pluginResult.getMessage()); // [ or {
+            }
+        }
+        
+        void encodeAsJsMessage(StringBuilder sb) {
+            if (pluginResult == null) {
+                sb.append(jsPayloadOrCallbackId);
+            } else {
+                int status = pluginResult.getStatus();
+                boolean success = (status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal());
+                sb.append("cordova.callbackFromNative('")
+                  .append(jsPayloadOrCallbackId)
+                  .append("',")
+                  .append(success)
+                  .append(",")
+                  .append(status)
+                  .append(",")
+                  .append(pluginResult.getMessage())
+                  .append(",")
+                  .append(pluginResult.getKeepCallback())
+                  .append(");");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/NetworkListener.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NetworkListener.java b/lib/cordova-android/framework/src/org/apache/cordova/NetworkListener.java
new file mode 100755
index 0000000..7d19259
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NetworkListener.java
@@ -0,0 +1,32 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import android.location.LocationManager;
+
+/**
+ * This class handles requests for GPS location services.
+ *
+ */
+public class NetworkListener extends CordovaLocationListener {
+    public NetworkListener(LocationManager locationManager, GeoBroker m) {
+        super(locationManager, m, "[Cordova NetworkListener]");
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/NetworkManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NetworkManager.java b/lib/cordova-android/framework/src/org/apache/cordova/NetworkManager.java
new file mode 100755
index 0000000..bb4743f
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NetworkManager.java
@@ -0,0 +1,248 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import org.apache.cordova.api.CallbackContext;
+import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.PluginResult;
+import org.json.JSONArray;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.util.Log;
+
+public class NetworkManager extends CordovaPlugin {
+
+    public static int NOT_REACHABLE = 0;
+    public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
+    public static int REACHABLE_VIA_WIFI_NETWORK = 2;
+
+    public static final String WIFI = "wifi";
+    public static final String WIMAX = "wimax";
+    // mobile
+    public static final String MOBILE = "mobile";
+    // 2G network types
+    public static final String GSM = "gsm";
+    public static final String GPRS = "gprs";
+    public static final String EDGE = "edge";
+    // 3G network types
+    public static final String CDMA = "cdma";
+    public static final String UMTS = "umts";
+    public static final String HSPA = "hspa";
+    public static final String HSUPA = "hsupa";
+    public static final String HSDPA = "hsdpa";
+    public static final String ONEXRTT = "1xrtt";
+    public static final String EHRPD = "ehrpd";
+    // 4G network types
+    public static final String LTE = "lte";
+    public static final String UMB = "umb";
+    public static final String HSPA_PLUS = "hspa+";
+    // return type
+    public static final String TYPE_UNKNOWN = "unknown";
+    public static final String TYPE_ETHERNET = "ethernet";
+    public static final String TYPE_WIFI = "wifi";
+    public static final String TYPE_2G = "2g";
+    public static final String TYPE_3G = "3g";
+    public static final String TYPE_4G = "4g";
+    public static final String TYPE_NONE = "none";
+
+    private static final String LOG_TAG = "NetworkManager";
+
+    private CallbackContext connectionCallbackContext;
+    private boolean registered = false;
+
+    ConnectivityManager sockMan;
+    BroadcastReceiver receiver;
+    private String lastStatus = "";
+
+    /**
+     * Constructor.
+     */
+    public NetworkManager() {
+        this.receiver = null;
+    }
+
+    /**
+     * Sets the context of the Command. This can then be used to do things like
+     * get file paths associated with the Activity.
+     *
+     * @param cordova The context of the main Activity.
+     * @param webView The CordovaWebView Cordova is running in.
+     */
+    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+        super.initialize(cordova, webView);
+        this.sockMan = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
+        this.connectionCallbackContext = null;
+
+        // We need to listen to connectivity events to update navigator.connection
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        if (this.receiver == null) {
+            this.receiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    // (The null check is for the ARM Emulator, please use Intel Emulator for better results)
+                    if(NetworkManager.this.webView != null)                        
+                        updateConnectionInfo(sockMan.getActiveNetworkInfo());
+                }
+            };
+            cordova.getActivity().registerReceiver(this.receiver, intentFilter);
+            this.registered = true;
+        }
+
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArry of arguments for the plugin.
+     * @param callbackContext   The callback id used when calling back into JavaScript.
+     * @return                  True if the action was valid, false otherwise.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
+        if (action.equals("getConnectionInfo")) {
+            this.connectionCallbackContext = callbackContext;
+            NetworkInfo info = sockMan.getActiveNetworkInfo();
+            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
+            pluginResult.setKeepCallback(true);
+            callbackContext.sendPluginResult(pluginResult);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Stop network receiver.
+     */
+    public void onDestroy() {
+        if (this.receiver != null && this.registered) {
+            try {
+                this.cordova.getActivity().unregisterReceiver(this.receiver);
+                this.registered = false;
+            } catch (Exception e) {
+                Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+    /**
+     * Updates the JavaScript side whenever the connection changes
+     *
+     * @param info the current active network info
+     * @return
+     */
+    private void updateConnectionInfo(NetworkInfo info) {
+        // send update to javascript "navigator.network.connection"
+        // Jellybean sends its own info
+        String thisStatus = this.getConnectionInfo(info);
+        if(!thisStatus.equals(lastStatus))
+        {
+            sendUpdate(thisStatus);
+            lastStatus = thisStatus;
+        }
+            
+    }
+
+    /**
+     * Get the latest network connection information
+     *
+     * @param info the current active network info
+     * @return a JSONObject that represents the network info
+     */
+    private String getConnectionInfo(NetworkInfo info) {
+        String type = TYPE_NONE;
+        if (info != null) {
+            // If we are not connected to any network set type to none
+            if (!info.isConnected()) {
+                type = TYPE_NONE;
+            }
+            else {
+                type = getType(info);
+            }
+        }
+        Log.d("CordovaNetworkManager", "Connection Type: " + type);
+        return type;
+    }
+
+    /**
+     * Create a new plugin result and send it back to JavaScript
+     *
+     * @param connection the network info to set as navigator.connection
+     */
+    private void sendUpdate(String type) {
+        if (connectionCallbackContext != null) {
+            PluginResult result = new PluginResult(PluginResult.Status.OK, type);
+            result.setKeepCallback(true);
+            connectionCallbackContext.sendPluginResult(result);
+        }
+        webView.postMessage("networkconnection", type);
+    }
+
+    /**
+     * Determine the type of connection
+     *
+     * @param info the network info so we can determine connection type.
+     * @return the type of mobile network we are on
+     */
+    private String getType(NetworkInfo info) {
+        if (info != null) {
+            String type = info.getTypeName();
+
+            if (type.toLowerCase().equals(WIFI)) {
+                return TYPE_WIFI;
+            }
+            else if (type.toLowerCase().equals(MOBILE)) {
+                type = info.getSubtypeName();
+                if (type.toLowerCase().equals(GSM) ||
+                        type.toLowerCase().equals(GPRS) ||
+                        type.toLowerCase().equals(EDGE)) {
+                    return TYPE_2G;
+                }
+                else if (type.toLowerCase().startsWith(CDMA) ||
+                        type.toLowerCase().equals(UMTS) ||
+                        type.toLowerCase().equals(ONEXRTT) ||
+                        type.toLowerCase().equals(EHRPD) ||
+                        type.toLowerCase().equals(HSUPA) ||
+                        type.toLowerCase().equals(HSDPA) ||
+                        type.toLowerCase().equals(HSPA)) {
+                    return TYPE_3G;
+                }
+                else if (type.toLowerCase().equals(LTE) ||
+                        type.toLowerCase().equals(UMB) ||
+                        type.toLowerCase().equals(HSPA_PLUS)) {
+                    return TYPE_4G;
+                }
+            }
+        }
+        else {
+            return TYPE_NONE;
+        }
+        return TYPE_UNKNOWN;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Notification.java b/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
new file mode 100755
index 0000000..958ab26
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
@@ -0,0 +1,341 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import org.apache.cordova.api.CallbackContext;
+import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Vibrator;
+
+/**
+ * This class provides access to notifications on the device.
+ */
+public class Notification extends CordovaPlugin {
+
+    public int confirmResult = -1;
+    public ProgressDialog spinnerDialog = null;
+    public ProgressDialog progressDialog = null;
+
+    /**
+     * Constructor.
+     */
+    public Notification() {
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action            The action to execute.
+     * @param args              JSONArray of arguments for the plugin.
+     * @param callbackContext   The callback context used when calling back into JavaScript.
+     * @return                  True when the action was valid, false otherwise.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        if (action.equals("beep")) {
+            this.beep(args.getLong(0));
+        }
+        else if (action.equals("vibrate")) {
+            this.vibrate(args.getLong(0));
+        }
+        else if (action.equals("alert")) {
+            this.alert(args.getString(0), args.getString(1), args.getString(2), callbackContext);
+            return true;
+        }
+        else if (action.equals("confirm")) {
+            this.confirm(args.getString(0), args.getString(1), args.getString(2), callbackContext);
+            return true;
+        }
+        else if (action.equals("activityStart")) {
+            this.activityStart(args.getString(0), args.getString(1));
+        }
+        else if (action.equals("activityStop")) {
+            this.activityStop();
+        }
+        else if (action.equals("progressStart")) {
+            this.progressStart(args.getString(0), args.getString(1));
+        }
+        else if (action.equals("progressValue")) {
+            this.progressValue(args.getInt(0));
+        }
+        else if (action.equals("progressStop")) {
+            this.progressStop();
+        }
+        else {
+            return false;
+        }
+
+        // Only alert and confirm are async.
+        callbackContext.success();
+        return true;
+    }
+
+    //--------------------------------------------------------------------------
+    // LOCAL METHODS
+    //--------------------------------------------------------------------------
+
+    /**
+     * Beep plays the default notification ringtone.
+     *
+     * @param count     Number of times to play notification
+     */
+    public void beep(long count) {
+        Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+        Ringtone notification = RingtoneManager.getRingtone(this.cordova.getActivity().getBaseContext(), ringtone);
+
+        // If phone is not set to silent mode
+        if (notification != null) {
+            for (long i = 0; i < count; ++i) {
+                notification.play();
+                long timeout = 5000;
+                while (notification.isPlaying() && (timeout > 0)) {
+                    timeout = timeout - 100;
+                    try {
+                        Thread.sleep(100);
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Vibrates the device for the specified amount of time.
+     *
+     * @param time      Time to vibrate in ms.
+     */
+    public void vibrate(long time) {
+        // Start the vibration, 0 defaults to half a second.
+        if (time == 0) {
+            time = 500;
+        }
+        Vibrator vibrator = (Vibrator) this.cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
+        vibrator.vibrate(time);
+    }
+
+    /**
+     * Builds and shows a native Android alert with given Strings
+     * @param message           The message the alert should display
+     * @param title             The title of the alert
+     * @param buttonLabel       The label of the button
+     * @param callbackContext   The callback context
+     */
+    public synchronized void alert(final String message, final String title, final String buttonLabel, final CallbackContext callbackContext) {
+
+        final CordovaInterface cordova = this.cordova;
+
+        Runnable runnable = new Runnable() {
+            public void run() {
+
+                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
+                dlg.setMessage(message);
+                dlg.setTitle(title);
+                dlg.setCancelable(true);
+                dlg.setPositiveButton(buttonLabel,
+                        new AlertDialog.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int which) {
+                                dialog.dismiss();
+                                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
+                            }
+                        });
+                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog)
+                    {
+                        dialog.dismiss();
+                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
+                    }
+                });
+                
+                dlg.create();
+                dlg.show();
+            };
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+
+    /**
+     * Builds and shows a native Android confirm dialog with given title, message, buttons.
+     * This dialog only shows up to 3 buttons.  Any labels after that will be ignored.
+     * The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
+     *
+     * @param message           The message the dialog should display
+     * @param title             The title of the dialog
+     * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
+     * @param callbackContext   The callback context.
+     */
+    public synchronized void confirm(final String message, final String title, String buttonLabels, final CallbackContext callbackContext) {
+
+        final CordovaInterface cordova = this.cordova;
+        final String[] fButtons = buttonLabels.split(",");
+
+        Runnable runnable = new Runnable() {
+            public void run() {
+                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
+                dlg.setMessage(message);
+                dlg.setTitle(title);
+                dlg.setCancelable(true);
+
+                // First button
+                if (fButtons.length > 0) {
+                    dlg.setNegativeButton(fButtons[0],
+                            new AlertDialog.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int which) {
+                                    dialog.dismiss();
+                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
+                                }
+                            });
+                }
+
+                // Second button
+                if (fButtons.length > 1) {
+                    dlg.setNeutralButton(fButtons[1],
+                            new AlertDialog.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int which) {
+                                    dialog.dismiss();
+                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
+                                }
+                            });
+                }
+
+                // Third button
+                if (fButtons.length > 2) {
+                    dlg.setPositiveButton(fButtons[2],
+                            new AlertDialog.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int which) {
+                                    dialog.dismiss();
+                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
+                                }
+                            }
+                            );
+                }
+                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog)
+                    {
+                        dialog.dismiss();
+                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
+                    }
+                });
+
+                dlg.create();
+                dlg.show();
+            };
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+
+    /**
+     * Show the spinner.
+     *
+     * @param title     Title of the dialog
+     * @param message   The message of the dialog
+     */
+    public synchronized void activityStart(final String title, final String message) {
+        if (this.spinnerDialog != null) {
+            this.spinnerDialog.dismiss();
+            this.spinnerDialog = null;
+        }
+        final CordovaInterface cordova = this.cordova;
+        Runnable runnable = new Runnable() {
+            public void run() {
+                Notification.this.spinnerDialog = ProgressDialog.show(cordova.getActivity(), title, message, true, true,
+                        new DialogInterface.OnCancelListener() {
+                            public void onCancel(DialogInterface dialog) {
+                                Notification.this.spinnerDialog = null;
+                            }
+                        });
+            }
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+
+    /**
+     * Stop spinner.
+     */
+    public synchronized void activityStop() {
+        if (this.spinnerDialog != null) {
+            this.spinnerDialog.dismiss();
+            this.spinnerDialog = null;
+        }
+    }
+
+    /**
+     * Show the progress dialog.
+     *
+     * @param title     Title of the dialog
+     * @param message   The message of the dialog
+     */
+    public synchronized void progressStart(final String title, final String message) {
+        if (this.progressDialog != null) {
+            this.progressDialog.dismiss();
+            this.progressDialog = null;
+        }
+        final Notification notification = this;
+        final CordovaInterface cordova = this.cordova;
+        Runnable runnable = new Runnable() {
+            public void run() {
+                notification.progressDialog = new ProgressDialog(cordova.getActivity());
+                notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+                notification.progressDialog.setTitle(title);
+                notification.progressDialog.setMessage(message);
+                notification.progressDialog.setCancelable(true);
+                notification.progressDialog.setMax(100);
+                notification.progressDialog.setProgress(0);
+                notification.progressDialog.setOnCancelListener(
+                        new DialogInterface.OnCancelListener() {
+                            public void onCancel(DialogInterface dialog) {
+                                notification.progressDialog = null;
+                            }
+                        });
+                notification.progressDialog.show();
+            }
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+
+    /**
+     * Set value of progress bar.
+     *
+     * @param value     0-100
+     */
+    public synchronized void progressValue(int value) {
+        if (this.progressDialog != null) {
+            this.progressDialog.setProgress(value);
+        }
+    }
+
+    /**
+     * Stop progress dialog.
+     */
+    public synchronized void progressStop() {
+        if (this.progressDialog != null) {
+            this.progressDialog.dismiss();
+            this.progressDialog = null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/SplashScreen.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/SplashScreen.java b/lib/cordova-android/framework/src/org/apache/cordova/SplashScreen.java
new file mode 100644
index 0000000..66b5bae
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/SplashScreen.java
@@ -0,0 +1,43 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+package org.apache.cordova;
+
+import org.apache.cordova.api.CallbackContext;
+import org.apache.cordova.api.CordovaPlugin;
+import org.json.JSONArray;
+
+public class SplashScreen extends CordovaPlugin {
+
+    @Override
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
+        if (action.equals("hide")) {
+            this.webView.postMessage("splashscreen", "hide");
+        } else if (action.equals("show")){
+            this.webView.postMessage("splashscreen", "show");
+        }
+        else {
+            return false;
+        }
+
+        callbackContext.success();
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/StandAlone.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/StandAlone.java b/lib/cordova-android/framework/src/org/apache/cordova/StandAlone.java
new file mode 100644
index 0000000..a199dda
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/StandAlone.java
@@ -0,0 +1,32 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import android.os.Bundle;
+
+public class StandAlone extends DroidGap {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        super.loadUrl("file:///android_asset/www/index.html");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/Storage.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Storage.java b/lib/cordova-android/framework/src/org/apache/cordova/Storage.java
new file mode 100755
index 0000000..5ec3068
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Storage.java
@@ -0,0 +1,245 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova;
+
+import java.io.File;
+
+import org.apache.cordova.api.CallbackContext;
+import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.*;
+
+/**
+ * This class implements the HTML5 database support to work around a bug for
+ * Android 3.0 devices. It is not used for other versions of Android, since
+ * HTML5 database is built in to the browser.
+ */
+public class Storage extends CordovaPlugin {
+
+    // Data Definition Language
+    private static final String ALTER = "alter";
+    private static final String CREATE = "create";
+    private static final String DROP = "drop";
+    private static final String TRUNCATE = "truncate";
+
+    SQLiteDatabase myDb = null; // Database object
+    String path = null; // Database path
+    String dbName = null; // Database name
+
+    /**
+     * Constructor.
+     */
+    public Storage() {
+    }
+
+    /**
+     * Executes the request and returns PluginResult.
+     *
+     * @param action
+     *            The action to execute.
+     * @param args
+     *            JSONArry of arguments for the plugin.
+     * @param callbackContext
+     *            The callback context used when calling back into JavaScript.
+     * @return True if the action was valid, false otherwise.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        if (action.equals("openDatabase")) {
+            this.openDatabase(args.getString(0), args.getString(1),
+                    args.getString(2), args.getLong(3));
+        } else if (action.equals("executeSql")) {
+            String[] s = null;
+            if (args.isNull(1)) {
+                s = new String[0];
+            } else {
+                JSONArray a = args.getJSONArray(1);
+                int len = a.length();
+                s = new String[len];
+                for (int i = 0; i < len; i++) {
+                    s[i] = a.getString(i);
+                }
+            }
+            this.executeSql(args.getString(0), s, args.getString(2));
+        }
+        else {
+            return false;
+        }
+        callbackContext.success();
+        return true;
+    }
+
+    /**
+     * Clean up and close database.
+     */
+    @Override
+    public void onDestroy() {
+        if (this.myDb != null) {
+            this.myDb.close();
+            this.myDb = null;
+        }
+    }
+
+    /**
+     * Clean up on navigation/refresh.
+     */
+    public void onReset() {
+        this.onDestroy();
+    }
+
+    // --------------------------------------------------------------------------
+    // LOCAL METHODS
+    // --------------------------------------------------------------------------
+
+    /**
+     * Open database.
+     *
+     * @param db
+     *            The name of the database
+     * @param version
+     *            The version
+     * @param display_name
+     *            The display name
+     * @param size
+     *            The size in bytes
+     */
+    public void openDatabase(String db, String version, String display_name,
+            long size) {
+
+        // If database is open, then close it
+        if (this.myDb != null) {
+            this.myDb.close();
+        }
+
+        // If no database path, generate from application package
+        if (this.path == null) {
+            this.path = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
+        }
+
+        this.dbName = this.path + File.separator + db + ".db";
+
+        /*
+         * What is all this nonsense? Well the separator was incorrect so the db was showing up in the wrong 
+         * directory. This bit of code fixes that issue and moves the db to the correct directory.
+         */
+        File oldDbFile = new File(this.path + File.pathSeparator + db + ".db");
+        if (oldDbFile.exists()) {
+            File dbPath = new File(this.path);
+            File dbFile = new File(dbName);
+            dbPath.mkdirs();
+            oldDbFile.renameTo(dbFile);
+        }
+        
+        this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
+    }
+
+    /**
+     * Execute SQL statement.
+     *
+     * @param query
+     *            The SQL query
+     * @param params
+     *            Parameters for the query
+     * @param tx_id
+     *            Transaction id
+     */
+    public void executeSql(String query, String[] params, String tx_id) {
+        try {
+            if (isDDL(query)) {
+                this.myDb.execSQL(query);
+                this.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', '');");
+            }
+            else {
+                Cursor myCursor = this.myDb.rawQuery(query, params);
+                this.processResults(myCursor, tx_id);
+                myCursor.close();
+            }
+        }
+        catch (SQLiteException ex) {
+            ex.printStackTrace();
+            System.out.println("Storage.executeSql(): Error=" +  ex.getMessage());
+
+            // Send error message back to JavaScript
+            this.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').failQuery('" + ex.getMessage() + "','" + tx_id + "');");
+        }
+    }
+
+    /**
+     * Checks to see the the query is a Data Definition command
+     *
+     * @param query to be executed
+     * @return true if it is a DDL command, false otherwise
+     */
+    private boolean isDDL(String query) {
+        String cmd = query.toLowerCase();
+        if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Process query results.
+     *
+     * @param cur
+     *            Cursor into query results
+     * @param tx_id
+     *            Transaction id
+     */
+    public void processResults(Cursor cur, String tx_id) {
+
+        String result = "[]";
+        // If query result has rows
+
+        if (cur.moveToFirst()) {
+            JSONArray fullresult = new JSONArray();
+            String key = "";
+            String value = "";
+            int colCount = cur.getColumnCount();
+
+            // Build up JSON result object for each row
+            do {
+                JSONObject row = new JSONObject();
+                try {
+                    for (int i = 0; i < colCount; ++i) {
+                        key = cur.getColumnName(i);
+                        value = cur.getString(i);
+                        row.put(key, value);
+                    }
+                    fullresult.put(row);
+
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+
+            } while (cur.moveToNext());
+
+            result = fullresult.toString();
+        }
+
+        // Let JavaScript know that there are no more rows
+        this.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
new file mode 100644
index 0000000..2f7b15f
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
@@ -0,0 +1,120 @@
+package org.apache.cordova.api;
+
+import org.json.JSONArray;
+
+import android.util.Log;
+
+import org.apache.cordova.CordovaWebView;
+import org.json.JSONObject;
+
+public class CallbackContext {
+    private static final String LOG_TAG = "CordovaPlugin";
+
+    private String callbackId;
+    private CordovaWebView webView;
+    private boolean finished;
+    private int changingThreads;
+
+    public CallbackContext(String callbackId, CordovaWebView webView) {
+        this.callbackId = callbackId;
+        this.webView = webView;
+    }
+    
+    public boolean isFinished() {
+        return finished;
+    }
+    
+    public boolean isChangingThreads() {
+        return changingThreads > 0;
+    }
+    
+    public String getCallbackId() {
+        return callbackId;
+    }
+
+    public void sendPluginResult(PluginResult pluginResult) {
+        synchronized (this) {
+            if (finished) {
+                Log.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage());
+                return;
+            } else {
+                finished = !pluginResult.getKeepCallback();
+            }
+        }
+        webView.sendPluginResult(pluginResult, callbackId);
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(JSONObject message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(String message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(JSONArray message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(byte[] message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
+
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success() {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     *
+     * @param message           The message to add to the error result.
+     */
+    public void error(JSONObject message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     *
+     * @param message           The message to add to the error result.
+     * @param callbackId        The callback id used when calling back into JavaScript.
+     */
+    public void error(String message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
+    }
+
+    /**
+     * Helper for error callbacks that just returns the Status.ERROR by default
+     *
+     * @param message           The message to add to the error result.
+     * @param callbackId        The callback id used when calling back into JavaScript.
+     */
+    public void error(int message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java
new file mode 100755
index 0000000..22e36b6
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java
@@ -0,0 +1,71 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * The Cordova activity abstract class that is extended by DroidGap.
+ * It is used to isolate plugin development, and remove dependency on entire Cordova library.
+ */
+public interface CordovaInterface {
+
+    /**
+     * Launch an activity for which you would like a result when it finished. When this activity exits,
+     * your onActivityResult() method will be called.
+     *
+     * @param command     The command object
+     * @param intent      The intent to start
+     * @param requestCode   The request code that is passed to callback to identify the activity
+     */
+    abstract public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode);
+
+    /**
+     * Set the plugin to be called when a sub-activity exits.
+     *
+     * @param plugin      The plugin on which onActivityResult is to be called
+     */
+    abstract public void setActivityResultCallback(CordovaPlugin plugin);
+
+    /**
+     * Get the Android activity.
+     *
+     * @return
+     */
+    public abstract Activity getActivity();
+    
+
+    /**
+     * Called when a message is sent to plugin.
+     *
+     * @param id            The message id
+     * @param data          The message data
+     * @return              Object or null
+     */
+    public Object onMessage(String id, Object data);
+    
+    /**
+     * Returns a shared thread pool that can be used for background tasks.
+     */
+    public ExecutorService getThreadPool();
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
new file mode 100644
index 0000000..f4c785e
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
@@ -0,0 +1,171 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import org.apache.cordova.CordovaArgs;
+import org.apache.cordova.CordovaWebView;
+import org.json.JSONArray;
+import org.json.JSONException;
+import android.content.Intent;
+
+/**
+ * Plugins must extend this class and override one of the execute methods.
+ */
+public class CordovaPlugin {
+    public String id;
+    public CordovaWebView webView;					// WebView object
+    public CordovaInterface cordova;
+
+    /**
+     * @param cordova The context of the main Activity.
+     * @param webView The associated CordovaWebView.
+     */
+    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+        assert this.cordova == null;
+        this.cordova = cordova;
+        this.webView = webView;
+    }
+
+    /**
+     * Executes the request.
+     *
+     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
+     *     cordova.getThreadPool().execute(runnable);
+     *
+     * To run on the UI thread, use:
+     *     cordova.getActivity().runOnUiThread(runnable);
+     *
+     * @param action          The action to execute.
+     * @param rawArgs         The exec() arguments in JSON form.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return                Whether the action was valid.
+     */
+    public boolean execute(String action, String rawArgs, CallbackContext callbackContext) throws JSONException {
+        JSONArray args = new JSONArray(rawArgs);
+        return execute(action, args, callbackContext);
+    }
+
+    /**
+     * Executes the request.
+     *
+     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
+     *     cordova.getThreadPool().execute(runnable);
+     *
+     * To run on the UI thread, use:
+     *     cordova.getActivity().runOnUiThread(runnable);
+     *
+     * @param action          The action to execute.
+     * @param args            The exec() arguments.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return                Whether the action was valid.
+     */
+    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
+        CordovaArgs cordovaArgs = new CordovaArgs(args);
+        return execute(action, cordovaArgs, callbackContext);
+    }
+
+    /**
+     * Executes the request.
+     *
+     * This method is called from the WebView thread. To do a non-trivial amount of work, use:
+     *     cordova.getThreadPool().execute(runnable);
+     *
+     * To run on the UI thread, use:
+     *     cordova.getActivity().runOnUiThread(runnable);
+     *
+     * @param action          The action to execute.
+     * @param args            The exec() arguments, wrapped with some Cordova helpers.
+     * @param callbackContext The callback context used when calling back into JavaScript.
+     * @return                Whether the action was valid.
+     */
+    public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
+        return false;
+    }
+
+    /**
+     * Called when the system is about to start resuming a previous activity.
+     *
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onPause(boolean multitasking) {
+    }
+
+    /**
+     * Called when the activity will start interacting with the user.
+     *
+     * @param multitasking		Flag indicating if multitasking is turned on for app
+     */
+    public void onResume(boolean multitasking) {
+    }
+
+    /**
+     * Called when the activity receives a new intent.
+     */
+    public void onNewIntent(Intent intent) {
+    }
+
+    /**
+     * The final call you receive before your activity is destroyed.
+     */
+    public void onDestroy() {
+    }
+
+    /**
+     * Called when a message is sent to plugin.
+     *
+     * @param id            The message id
+     * @param data          The message data
+     * @return              Object to stop propagation or null
+     */
+    public Object onMessage(String id, Object data) {
+        return null;
+    }
+
+    /**
+     * Called when an activity you launched exits, giving you the requestCode you started it with,
+     * the resultCode it returned, and any additional data from it.
+     *
+     * @param requestCode		The request code originally supplied to startActivityForResult(),
+     * 							allowing you to identify who this result came from.
+     * @param resultCode		The integer result code returned by the child activity through its setResult().
+     * @param data				An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
+     */
+    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+    }
+
+    /**
+     * By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
+     *
+     * @param url				The URL that is trying to be loaded in the Cordova webview.
+     * @return					Return true to prevent the URL from loading. Default is false.
+     */
+    public boolean onOverrideUrlLoading(String url) {
+        return false;
+    }
+
+    /**
+     * Called when the WebView does a top-level navigation or refreshes.
+     *
+     * Plugins should stop any long-running processes and clean up internal state.
+     *
+     * Does nothing by default.
+     */
+    public void onReset() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/api/LOG.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/LOG.java b/lib/cordova-android/framework/src/org/apache/cordova/api/LOG.java
new file mode 100755
index 0000000..91f035b
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/LOG.java
@@ -0,0 +1,234 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+package org.apache.cordova.api;
+
+import android.util.Log;
+
+/**
+ * Log to Android logging system.
+ *
+ * Log message can be a string or a printf formatted string with arguments.
+ * See http://developer.android.com/reference/java/util/Formatter.html
+ */
+public class LOG {
+
+    public static final int VERBOSE = Log.VERBOSE;
+    public static final int DEBUG = Log.DEBUG;
+    public static final int INFO = Log.INFO;
+    public static final int WARN = Log.WARN;
+    public static final int ERROR = Log.ERROR;
+
+    // Current log level
+    public static int LOGLEVEL = Log.ERROR;
+
+    /**
+     * Set the current log level.
+     *
+     * @param logLevel
+     */
+    public static void setLogLevel(int logLevel) {
+        LOGLEVEL = logLevel;
+        Log.i("CordovaLog", "Changing log level to " + logLevel);
+    }
+
+    /**
+     * Set the current log level.
+     *
+     * @param logLevel
+     */
+    public static void setLogLevel(String logLevel) {
+        if ("VERBOSE".equals(logLevel)) LOGLEVEL = VERBOSE;
+        else if ("DEBUG".equals(logLevel)) LOGLEVEL = DEBUG;
+        else if ("INFO".equals(logLevel)) LOGLEVEL = INFO;
+        else if ("WARN".equals(logLevel)) LOGLEVEL = WARN;
+        else if ("ERROR".equals(logLevel)) LOGLEVEL = ERROR;
+        Log.i("CordovaLog", "Changing log level to " + logLevel + "(" + LOGLEVEL + ")");
+    }
+
+    /**
+     * Determine if log level will be logged
+     *
+     * @param logLevel
+     * @return
+     */
+    public static boolean isLoggable(int logLevel) {
+        return (logLevel >= LOGLEVEL);
+    }
+
+    /**
+     * Verbose log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void v(String tag, String s) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);
+    }
+
+    /**
+     * Debug log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void d(String tag, String s) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);
+    }
+
+    /**
+     * Info log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void i(String tag, String s) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);
+    }
+
+    /**
+     * Warning log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void w(String tag, String s) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);
+    }
+
+    /**
+     * Error log message.
+     *
+     * @param tag
+     * @param s
+     */
+    public static void e(String tag, String s) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);
+    }
+
+    /**
+     * Verbose log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void v(String tag, String s, Throwable e) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);
+    }
+
+    /**
+     * Debug log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void d(String tag, String s, Throwable e) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);
+    }
+
+    /**
+     * Info log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void i(String tag, String s, Throwable e) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);
+    }
+
+    /**
+     * Warning log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void w(String tag, String s, Throwable e) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);
+    }
+
+    /**
+     * Error log message.
+     *
+     * @param tag
+     * @param s
+     * @param e
+     */
+    public static void e(String tag, String s, Throwable e) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);
+    }
+
+    /**
+     * Verbose log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void v(String tag, String s, Object... args) {
+        if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));
+    }
+
+    /**
+     * Debug log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void d(String tag, String s, Object... args) {
+        if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));
+    }
+
+    /**
+     * Info log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void i(String tag, String s, Object... args) {
+        if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));
+    }
+
+    /**
+     * Warning log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void w(String tag, String s, Object... args) {
+        if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));
+    }
+
+    /**
+     * Error log message with printf formatting.
+     *
+     * @param tag
+     * @param s
+     * @param args
+     */
+    public static void e(String tag, String s, Object... args) {
+        if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-android/framework/src/org/apache/cordova/api/LegacyContext.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/LegacyContext.java b/lib/cordova-android/framework/src/org/apache/cordova/api/LegacyContext.java
new file mode 100644
index 0000000..fe154f7
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/LegacyContext.java
@@ -0,0 +1,154 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+// 
+// http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cordova.api;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+
+@Deprecated
+public class LegacyContext implements CordovaInterface {
+    private static final String LOG_TAG = "Deprecation Notice";
+    private CordovaInterface cordova;
+
+    public LegacyContext(CordovaInterface cordova) {
+        this.cordova = cordova;
+    }
+
+    @Deprecated
+    public void cancelLoadUrl() {
+        Log.i(LOG_TAG, "Replace ctx.cancelLoadUrl() with cordova.cancelLoadUrl()");
+    }
+
+    @Deprecated
+    public Activity getActivity() {
+        Log.i(LOG_TAG, "Replace ctx.getActivity() with cordova.getActivity()");
+        return this.cordova.getActivity();
+    }
+
+    @Deprecated
+    public Context getContext() {
+        Log.i(LOG_TAG, "Replace ctx.getContext() with cordova.getContext()");
+        return this.cordova.getActivity();
+    }
+
+    @Deprecated
+    public Object onMessage(String arg0, Object arg1) {
+        Log.i(LOG_TAG, "Replace ctx.onMessage() with cordova.onMessage()");
+        return this.cordova.onMessage(arg0, arg1);
+    }
+
+    @Deprecated
+    public void setActivityResultCallback(CordovaPlugin arg0) {
+        Log.i(LOG_TAG, "Replace ctx.setActivityResultCallback() with cordova.setActivityResultCallback()");
+        this.cordova.setActivityResultCallback(arg0);
+    }
+
+    @Deprecated
+    public void startActivityForResult(CordovaPlugin arg0, Intent arg1, int arg2) {
+        Log.i(LOG_TAG, "Replace ctx.startActivityForResult() with cordova.startActivityForResult()");
+        this.cordova.startActivityForResult(arg0, arg1, arg2);
+    }
+
+    @Deprecated
+    public void startActivity(Intent intent) {
+        Log.i(LOG_TAG, "Replace ctx.startActivity() with cordova.getActivity().startActivity()");
+        this.cordova.getActivity().startActivity(intent);
+    }
+
+    @Deprecated
+    public Object getSystemService(String name) {
+        Log.i(LOG_TAG, "Replace ctx.getSystemService() with cordova.getActivity().getSystemService()");
+        return this.cordova.getActivity().getSystemService(name);
+    }
+
+    @Deprecated
+    public AssetManager getAssets() {
+        Log.i(LOG_TAG, "Replace ctx.getAssets() with cordova.getActivity().getAssets()");
+        return this.cordova.getActivity().getAssets();
+    }
+
+    @Deprecated
+    public void runOnUiThread(Runnable runnable) {
+        Log.i(LOG_TAG, "Replace ctx.runOnUiThread() with cordova.getActivity().runOnUiThread()");
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+
+    @Deprecated
+    public Context getApplicationContext() {
+        Log.i(LOG_TAG, "Replace ctx.getApplicationContext() with cordova.getActivity().getApplicationContext()");
+        return this.cordova.getActivity().getApplicationContext();
+    }
+
+    @Deprecated
+    public PackageManager getPackageManager() {
+        Log.i(LOG_TAG, "Replace ctx.getPackageManager() with cordova.getActivity().getPackageManager()");
+        return this.cordova.getActivity().getPackageManager();
+    }
+
+    @Deprecated
+    public SharedPreferences getSharedPreferences(String name, int mode) {
+        Log.i(LOG_TAG, "Replace ctx.getSharedPreferences() with cordova.getActivity().getSharedPreferences()");
+        return this.cordova.getActivity().getSharedPreferences(name, mode);
+    }
+
+    @Deprecated
+    public void unregisterReceiver(BroadcastReceiver receiver) {
+        Log.i(LOG_TAG, "Replace ctx.unregisterReceiver() with cordova.getActivity().unregisterReceiver()");
+        this.cordova.getActivity().unregisterReceiver(receiver);
+    }
+
+    @Deprecated
+    public Resources getResources() {
+        Log.i(LOG_TAG, "Replace ctx.getResources() with cordova.getActivity().getResources()");
+        return this.cordova.getActivity().getResources();
+    }
+
+    @Deprecated
+    public ComponentName startService(Intent service) {
+        Log.i(LOG_TAG, "Replace ctx.startService() with cordova.getActivity().startService()");
+        return this.cordova.getActivity().startService(service);
+    }
+
+    @Deprecated
+    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+        Log.i(LOG_TAG, "Replace ctx.bindService() with cordova.getActivity().bindService()");
+        return this.cordova.getActivity().bindService(service, conn, flags);
+    }
+
+    @Deprecated
+    public void unbindService(ServiceConnection conn) {
+        Log.i(LOG_TAG, "Replace ctx.unbindService() with cordova.getActivity().unbindService()");
+        this.cordova.getActivity().unbindService(conn);
+    }
+
+    public ExecutorService getThreadPool() {
+        Log.i(LOG_TAG, "Replace ctx.getThreadPool() with cordova.getThreadPool()");
+        return this.cordova.getThreadPool();
+    }
+}