cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject [07/17] added fireos code from https://github.com/archananaik/cordova-amazon-fireos sans history
Date Mon, 25 Nov 2013 23:43:40 GMT
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/b3b7c0b9/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaChromeClient.java b/framework/src/org/apache/cordova/CordovaChromeClient.java
new file mode 100755
index 0000000..e506d6e
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -0,0 +1,434 @@
+/*
+       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.CordovaInterface;
+import org.apache.cordova.LOG;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.annotation.TargetApi;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import com.amazon.android.webkit.AmazonConsoleMessage;
+import com.amazon.android.webkit.AmazonJsPromptResult;
+import com.amazon.android.webkit.AmazonJsResult;
+import com.amazon.android.webkit.AmazonValueCallback;
+import com.amazon.android.webkit.AmazonWebChromeClient;
+import com.amazon.android.webkit.AmazonWebStorage;
+import com.amazon.android.webkit.AmazonWebView;
+import com.amazon.android.webkit.AmazonGeolocationPermissions;
+import com.amazon.android.webkit.AmazonMediaDeviceSettings;
+
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+
+/**
+ * This class is the AmazonWebChromeClient that implements callbacks for our web view.
+ */
+public class CordovaChromeClient extends AmazonWebChromeClient {
+
+    public static final int FILECHOOSER_RESULTCODE = 5173;
+    private static final String LOG_TAG = "CordovaChromeClient";
+    private String TAG = "CordovaLog";
+
+    /* Using a conservative database quota (used primarily for the stock Android back-end) */
+    private static final long DB_QUOTA = 5 * 1024 * 1024;
+    
+    protected CordovaInterface cordova;
+    protected CordovaWebView appView;
+
+    // the video progress view
+    private View mVideoProgressView;
+    
+    // File Chooser
+    public AmazonValueCallback<Uri> mUploadMessage;
+    
+    /**
+     * Constructor.
+     *
+     * @param cordova
+     */
+    public CordovaChromeClient(CordovaInterface cordova) {
+        this.cordova = cordova;
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param ctx
+     * @param app
+     */
+    public CordovaChromeClient(CordovaInterface ctx, CordovaWebView app) {
+        this.cordova = ctx;
+        this.appView = app;
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param view
+     */
+    public void setWebView(CordovaWebView view) {
+        this.appView = view;
+    }
+
+    /**
+     * Tell the client to display a javascript alert dialog.
+     *
+     * @param view
+     * @param url
+     * @param message
+     * @param result
+     */
+    @Override
+    public boolean onJsAlert(AmazonWebView view, String url, String message, final AmazonJsResult result) {
+        AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
+        dlg.setMessage(message);
+        dlg.setTitle("Alert");
+        //Don't let alerts break the back button
+        dlg.setCancelable(true);
+        dlg.setPositiveButton(android.R.string.ok,
+                new AlertDialog.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.confirm();
+                    }
+                });
+        dlg.setOnCancelListener(
+                new DialogInterface.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        result.cancel();
+                    }
+                });
+        dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
+            //DO NOTHING
+            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_BACK)
+                {
+                    result.confirm();
+                    return false;
+                }
+                else
+                    return true;
+            }
+        });
+        dlg.create();
+        dlg.show();
+        return true;
+    }
+
+    /**
+     * Tell the client to display a confirm dialog to the user.
+     *
+     * @param view
+     * @param url
+     * @param message
+     * @param result
+     */
+    @Override
+    public boolean onJsConfirm(AmazonWebView view, String url, String message, final AmazonJsResult result) {
+        AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
+        dlg.setMessage(message);
+        dlg.setTitle("Confirm");
+        dlg.setCancelable(true);
+        dlg.setPositiveButton(android.R.string.ok,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.confirm();
+                    }
+                });
+        dlg.setNegativeButton(android.R.string.cancel,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        result.cancel();
+                    }
+                });
+        dlg.setOnCancelListener(
+                new DialogInterface.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog) {
+                        result.cancel();
+                    }
+                });
+        dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
+            //DO NOTHING
+            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                if (keyCode == KeyEvent.KEYCODE_BACK)
+                {
+                    result.cancel();
+                    return false;
+                }
+                else
+                    return true;
+            }
+        });
+        dlg.create();
+        dlg.show();
+        return true;
+    }
+
+    /**
+     * Tell the client to display a prompt dialog to the user.
+     * If the client returns true, AmazonWebView will assume that the client will
+     * handle the prompt dialog and call the appropriate AmazonJsPromptResult method.
+     *
+     * Since we are hacking prompts for our own purposes, we should not be using them for
+     * this purpose, perhaps we should hack console.log to do this instead!
+     *
+     * @param view
+     * @param url
+     * @param message
+     * @param defaultValue
+     * @param result
+     */
+    @Override
+    public boolean onJsPrompt(AmazonWebView view, String url, String message, String defaultValue, AmazonJsPromptResult result) {
+
+        // Security check to make sure any requests are coming from the page initially
+        // loaded in webview and not another loaded in an iframe.
+        boolean reqOk = false;
+        if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
+            reqOk = true;
+        }
+
+        // Calling PluginManager.exec() to call a native service using 
+        // prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
+        if (reqOk && defaultValue != null && defaultValue.length() > 3 && defaultValue.substring(0, 4).equals("gap:")) {
+            JSONArray array;
+            try {
+                array = new JSONArray(defaultValue.substring(4));
+                String service = array.getString(0);
+                String action = array.getString(1);
+                String callbackId = array.getString(2);
+                String r = this.appView.exposedJsApi.exec(service, action, callbackId, message);
+                result.confirm(r == null ? "" : r);
+            } catch (JSONException e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+
+        // Sets the native->JS bridge mode. 
+        else if (reqOk && defaultValue != null && defaultValue.equals("gap_bridge_mode:")) {
+        	try {
+                this.appView.exposedJsApi.setNativeToJsBridgeMode(Integer.parseInt(message));
+                result.confirm("");
+        	} catch (NumberFormatException e){
+                result.confirm("");
+                e.printStackTrace();
+        	}
+        }
+
+        // Polling for JavaScript messages 
+        else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
+            String r = this.appView.exposedJsApi.retrieveJsMessages("1".equals(message));
+            result.confirm(r == null ? "" : r);
+        }
+
+        // Do NO-OP so older code doesn't display dialog
+        else if (defaultValue != null && defaultValue.equals("gap_init:")) {
+            result.confirm("OK");
+        }
+
+        // Show dialog
+        else {
+            final AmazonJsPromptResult res = result;
+            AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity());
+            dlg.setMessage(message);
+            final EditText input = new EditText(this.cordova.getActivity());
+            if (defaultValue != null) {
+                input.setText(defaultValue);
+            }
+            dlg.setView(input);
+            dlg.setCancelable(false);
+            dlg.setPositiveButton(android.R.string.ok,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            String usertext = input.getText().toString();
+                            res.confirm(usertext);
+                        }
+                    });
+            dlg.setNegativeButton(android.R.string.cancel,
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int which) {
+                            res.cancel();
+                        }
+                    });
+            dlg.create();
+            dlg.show();
+        }
+        return true;
+    }
+
+    /**
+     * Handle database quota exceeded notification.
+     *
+     * @param url
+     * @param databaseIdentifier
+     * @param currentQuota
+     * @param estimatedSize
+     * @param totalUsedQuota
+     * @param quotaUpdater
+     */
+    @Override
+    public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
+            long totalUsedQuota, AmazonWebStorage.QuotaUpdater quotaUpdater)
+    {
+        LOG.d(TAG, "Exceeded database quota - adjusting to " + DB_QUOTA + " bytes");
+
+        // This function is only called on the stock Android back-end due to the default
+        // quota initializing to 0 bytes. When on Chromium-compatible devices or platforms,
+        // the quota is essentially "unlimited" given the sufficient disk space.
+        if (currentQuota < DB_QUOTA) {
+            quotaUpdater.updateQuota(DB_QUOTA);
+            
+        }
+        
+    }
+
+    // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html
+    // Expect this to not compile in a future Android release!
+    @SuppressWarnings("deprecation")
+    @Override
+    public void onConsoleMessage(String message, int lineNumber, String sourceID)
+    {
+        //This is only for Android 2.1
+        if(android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.ECLAIR_MR1)
+        {
+            LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message);
+            super.onConsoleMessage(message, lineNumber, sourceID);
+        }
+    }
+
+    @TargetApi(8)
+    @Override
+    public boolean onConsoleMessage(AmazonConsoleMessage consoleMessage)
+    {
+        if (consoleMessage.message() != null)
+            LOG.d(TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());
+         return super.onConsoleMessage(consoleMessage);
+    }
+
+    
+    /**
+     * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified
+     * origin.
+     * <p>
+     * Note- This prompt is displayed when web content from the specified origin is attempting to use the Geolocation
+     * API
+     * <ul>
+     * <li>1. getCurrentPosition(PositionCallback successCallback, PositionErrorCallback errorCallback, optional
+     * PositionOptions options)</li>
+     * <li>2. watchPosition(PositionCallback successCallback, PositionErrorCallback errorCallback, optional
+     * PositionOptions options)</li>
+     * </ul>
+     * 
+     * @param origin
+     * @param callback
+     */
+    @Override
+    public void onGeolocationPermissionsShowPrompt(String origin, AmazonGeolocationPermissions.Callback callback) {
+        callback.invoke(origin, true, false);
+    }
+    
+    // API level 7 is required for this, see if we could lower this using something else
+    @Override
+    public void onShowCustomView(View view, AmazonWebChromeClient.CustomViewCallback callback) {
+        this.appView.showCustomView(view, callback);
+    }
+
+	@Override
+	public void onHideCustomView() {
+    	this.appView.hideCustomView();
+	}
+    
+    @Override
+    /**
+     * Ask the host application for a custom progress view to show while
+     * a <video> is loading.
+     * @return View The progress view.
+     */
+    public View getVideoLoadingProgressView() {
+
+	    if (mVideoProgressView == null) {	        
+	    	// Create a new Loading view programmatically.
+	    	
+	    	// create the linear layout
+	    	LinearLayout layout = new LinearLayout(this.appView.getContext());
+	        layout.setOrientation(LinearLayout.VERTICAL);
+	        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+	        layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+	        layout.setLayoutParams(layoutParams);
+	        // the proress bar
+	        ProgressBar bar = new ProgressBar(this.appView.getContext());
+	        LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+	        barLayoutParams.gravity = Gravity.CENTER;
+	        bar.setLayoutParams(barLayoutParams);   
+	        layout.addView(bar);
+	        
+	        mVideoProgressView = layout;
+	    }
+    return mVideoProgressView; 
+    }
+    
+    public void openFileChooser(AmazonValueCallback<Uri> uploadMsg) {
+        this.openFileChooser(uploadMsg, "*/*");
+    }
+
+    public void openFileChooser( AmazonValueCallback<Uri> uploadMsg, String acceptType ) {
+        this.openFileChooser(uploadMsg, acceptType, null);
+    }
+    
+    public void openFileChooser(AmazonValueCallback<Uri> uploadMsg, String acceptType, String capture)
+    {
+        mUploadMessage = uploadMsg;
+        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+        i.addCategory(Intent.CATEGORY_OPENABLE);
+        i.setType("*/*");
+        this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"),
+                FILECHOOSER_RESULTCODE);
+    }
+    
+    public AmazonValueCallback<Uri> getValueCallback() {
+        return this.mUploadMessage;
+    }
+    
+    /**
+     * Notify the host application that media access is denied.
+     * <p>
+     * Note- getUserMedia() JS API is currently not supported by AmazonWebView
+     * 
+     * @param origin
+     *            The origin of the web content attempting to use the media device request api
+     * @param callback
+     *            The callback to use to set the permission state for the origin
+     */
+    @Override
+    public void onMediaDevicePermissionsShowPrompt(String origin, AmazonMediaDeviceSettings.Callback callback) {
+        // Currently, media access should always be denied
+        callback.invoke(false, true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/b3b7c0b9/framework/src/org/apache/cordova/CordovaInterface.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaInterface.java b/framework/src/org/apache/cordova/CordovaInterface.java
new file mode 100755
index 0000000..ffe49bd
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaInterface.java
@@ -0,0 +1,80 @@
+/*
+       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.app.Activity;
+import android.content.Intent;
+
+import org.apache.cordova.CordovaPlugin;
+
+import java.util.concurrent.ExecutorService;
+
+import com.amazon.android.webkit.AmazonWebKitFactory;
+
+/**
+ * The Activity interface that is implemented by CordovaActivity.
+ * 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();
+    
+    /**
+     * Get the WebKit factory.
+     * @return
+     */
+    public abstract AmazonWebKitFactory getFactory();
+}

http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/b3b7c0b9/framework/src/org/apache/cordova/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaPlugin.java b/framework/src/org/apache/cordova/CordovaPlugin.java
new file mode 100644
index 0000000..8111e7b
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaPlugin.java
@@ -0,0 +1,182 @@
+/*
+       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.CordovaArgs;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CallbackContext;
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import android.content.Intent;
+import android.net.Uri;
+
+/**
+ * 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 intent				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 config.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;
+    }
+
+    /**
+     * Hook for redirecting requests. Applies to WebView requests as well as requests made by plugins.
+     */
+    public Uri remapUri(Uri uri) {
+        return null;
+    }
+    
+    /**
+     * 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-amazon-fireos/blob/b3b7c0b9/framework/src/org/apache/cordova/CordovaResourceApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaResourceApi.java b/framework/src/org/apache/cordova/CordovaResourceApi.java
new file mode 100644
index 0000000..96f3d25
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaResourceApi.java
@@ -0,0 +1,416 @@
+/*
+       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.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Looper;
+import android.util.Base64;
+import android.webkit.MimeTypeMap;
+
+import com.squareup.okhttp.OkHttpClient;
+
+import org.apache.http.util.EncodingUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.util.Locale;
+
+public class CordovaResourceApi {
+    @SuppressWarnings("unused")
+    private static final String LOG_TAG = "CordovaResourceApi";
+
+    public static final int URI_TYPE_FILE = 0;
+    public static final int URI_TYPE_ASSET = 1;
+    public static final int URI_TYPE_CONTENT = 2;
+    public static final int URI_TYPE_RESOURCE = 3;
+    public static final int URI_TYPE_DATA = 4;
+    public static final int URI_TYPE_HTTP = 5;
+    public static final int URI_TYPE_HTTPS = 6;
+    public static final int URI_TYPE_UNKNOWN = -1;
+    
+    private static final String[] LOCAL_FILE_PROJECTION = { "_data" };
+    
+    // Creating this is light-weight.
+    private static OkHttpClient httpClient = new OkHttpClient();
+    
+    static Thread jsThread;
+
+    private final AssetManager assetManager;
+    private final ContentResolver contentResolver;
+    private final PluginManager pluginManager;
+    private boolean threadCheckingEnabled = true;
+
+
+    public CordovaResourceApi(Context context, PluginManager pluginManager) {
+        this.contentResolver = context.getContentResolver();
+        this.assetManager = context.getAssets();
+        this.pluginManager = pluginManager;
+    }
+    
+    public void setThreadCheckingEnabled(boolean value) {
+        threadCheckingEnabled = value;
+    }
+
+    public boolean isThreadCheckingEnabled() {
+        return threadCheckingEnabled;
+    }
+    
+    public static int getUriType(Uri uri) {
+        assertNonRelative(uri);
+        String scheme = uri.getScheme();
+        if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+            return URI_TYPE_CONTENT;
+        }
+        if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+            return URI_TYPE_RESOURCE;
+        }
+        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+            if (uri.getPath().startsWith("/android_asset/")) {
+                return URI_TYPE_ASSET;
+            }
+            return URI_TYPE_FILE;
+        }
+        if ("data".equals(scheme)) {
+            return URI_TYPE_DATA;
+        }
+        if ("http".equals(scheme)) {
+            return URI_TYPE_HTTP;
+        }
+        if ("https".equals(scheme)) {
+            return URI_TYPE_HTTPS;
+        }
+        return URI_TYPE_UNKNOWN;
+    }
+    
+    public Uri remapUri(Uri uri) {
+        assertNonRelative(uri);
+        Uri pluginUri = pluginManager.remapUri(uri);
+        return pluginUri != null ? pluginUri : uri;
+    }
+
+    public String remapPath(String path) {
+        return remapUri(Uri.fromFile(new File(path))).getPath();
+    }
+    
+    /**
+     * Returns a File that points to the resource, or null if the resource
+     * is not on the local filesystem.
+     */
+    public File mapUriToFile(Uri uri) {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE:
+                return new File(uri.getPath());
+            case URI_TYPE_CONTENT: {
+                Cursor cursor = contentResolver.query(uri, LOCAL_FILE_PROJECTION, null, null, null);
+                if (cursor != null) {
+                    try {
+                        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
+                        if (columnIndex != -1 && cursor.getCount() > 0) {
+                            cursor.moveToFirst();
+                            String realPath = cursor.getString(columnIndex);
+                            if (realPath != null) {
+                                return new File(realPath);
+                            }
+                        }
+                    } finally {
+                        cursor.close();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    public String getMimeType(Uri uri) {
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE:
+            case URI_TYPE_ASSET:
+                return getMimeTypeFromPath(uri.getPath());
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE:
+                return contentResolver.getType(uri);
+            case URI_TYPE_DATA: {
+                return getDataUriMimeType(uri);
+            }
+            case URI_TYPE_HTTP:
+            case URI_TYPE_HTTPS: {
+                try {
+                    HttpURLConnection conn = httpClient.open(new URL(uri.toString()));
+                    conn.setDoInput(false);
+                    conn.setRequestMethod("HEAD");
+                    return conn.getHeaderField("Content-Type");
+                } catch (IOException e) {
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    private String getMimeTypeFromPath(String path) {
+        String extension = path;
+        int lastDot = extension.lastIndexOf('.');
+        if (lastDot != -1) {
+            extension = extension.substring(lastDot + 1);
+        }
+        // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+        extension = extension.toLowerCase(Locale.getDefault());
+        if (extension.equals("3ga")) {
+            return "audio/3gpp";
+        }
+        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+    }
+    
+    /**
+     * Opens a stream to the givne URI, also providing the MIME type & length.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     * @throws Throws an IllegalStateException if called on a foreground thread.
+     */
+    public OpenForReadResult openForRead(Uri uri) throws IOException {
+        return openForRead(uri, false);
+    }
+
+    /**
+     * Opens a stream to the givne URI, also providing the MIME type & length.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     * @throws Throws an IllegalStateException if called on a foreground thread and skipThreadCheck is false.
+     */
+    public OpenForReadResult openForRead(Uri uri, boolean skipThreadCheck) throws IOException {
+        if (!skipThreadCheck) {
+            assertBackgroundThread();
+        }
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE: {
+                FileInputStream inputStream = new FileInputStream(uri.getPath());
+                String mimeType = getMimeTypeFromPath(uri.getPath());
+                long length = inputStream.getChannel().size();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
+            }
+            case URI_TYPE_ASSET: {
+                String assetPath = uri.getPath().substring(15);
+                AssetFileDescriptor assetFd = null;
+                InputStream inputStream;
+                long length = -1;
+                try {
+                    assetFd = assetManager.openFd(assetPath);
+                    inputStream = assetFd.createInputStream();
+                    length = assetFd.getLength();
+                } catch (FileNotFoundException e) {
+                    // Will occur if the file is compressed.
+                    inputStream = assetManager.open(assetPath);
+                }
+                String mimeType = getMimeTypeFromPath(assetPath);
+                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
+            }
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE: {
+                String mimeType = contentResolver.getType(uri);
+                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, "r");
+                InputStream inputStream = assetFd.createInputStream();
+                long length = assetFd.getLength();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
+            }
+            case URI_TYPE_DATA: {
+                OpenForReadResult ret = readDataUri(uri);
+                if (ret == null) {
+                    break;
+                }
+                return ret;
+            }
+            case URI_TYPE_HTTP:
+            case URI_TYPE_HTTPS: {
+                HttpURLConnection conn = httpClient.open(new URL(uri.toString()));
+                conn.setDoInput(true);
+                String mimeType = conn.getHeaderField("Content-Type");
+                int length = conn.getContentLength();
+                InputStream inputStream = conn.getInputStream();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
+            }
+        }
+        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
+    }
+
+    public OutputStream openOutputStream(Uri uri) throws IOException {
+        return openOutputStream(uri, false);
+    }
+
+    /**
+     * Opens a stream to the given URI.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     */
+    public OutputStream openOutputStream(Uri uri, boolean append) throws IOException {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE: {
+                File localFile = new File(uri.getPath());
+                File parent = localFile.getParentFile();
+                if (parent != null) {
+                    parent.mkdirs();
+                }
+                return new FileOutputStream(localFile, append);
+            }
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE: {
+                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, append ? "wa" : "w");
+                return assetFd.createOutputStream();
+            }
+        }
+        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
+    }
+    
+    public HttpURLConnection createHttpConnection(Uri uri) throws IOException {
+        assertBackgroundThread();
+        return httpClient.open(new URL(uri.toString()));
+    }
+    
+    // Copies the input to the output in the most efficient manner possible.
+    // Closes both streams.
+    public void copyResource(OpenForReadResult input, OutputStream outputStream) throws IOException {
+        assertBackgroundThread();
+        try {
+            InputStream inputStream = input.inputStream;
+            if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {
+                FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();
+                FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();
+                long offset = 0;
+                long length = input.length;
+                if (input.assetFd != null) {
+                    offset = input.assetFd.getStartOffset();
+                }
+                outChannel.transferFrom(inChannel, offset, length);
+            } else {
+                final int BUFFER_SIZE = 8192;
+                byte[] buffer = new byte[BUFFER_SIZE];
+                
+                for (;;) {
+                    int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+                    
+                    if (bytesRead <= 0) {
+                        break;
+                    }
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+            }            
+        } finally {
+            input.inputStream.close();
+            if (outputStream != null) {
+                outputStream.close();
+            }
+        }
+    }
+
+    public void copyResource(Uri sourceUri, OutputStream outputStream) throws IOException {
+        copyResource(openForRead(sourceUri), outputStream);
+    }
+
+    
+    private void assertBackgroundThread() {
+        if (threadCheckingEnabled) {
+            Thread curThread = Thread.currentThread();
+            if (curThread == Looper.getMainLooper().getThread()) {
+                throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+            if (curThread == jsThread) {
+                throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+        }
+    }
+    
+    private String getDataUriMimeType(Uri uri) {
+        String uriAsString = uri.getSchemeSpecificPart();
+        int commaPos = uriAsString.indexOf(',');
+        if (commaPos == -1) {
+            return null;
+        }
+        String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
+        if (mimeParts.length > 0) {
+            return mimeParts[0];
+        }
+        return null;
+    }
+
+    private OpenForReadResult readDataUri(Uri uri) {
+        String uriAsString = uri.getSchemeSpecificPart();
+        int commaPos = uriAsString.indexOf(',');
+        if (commaPos == -1) {
+            return null;
+        }
+        String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
+        String contentType = null;
+        boolean base64 = false;
+        if (mimeParts.length > 0) {
+            contentType = mimeParts[0];
+        }
+        for (int i = 1; i < mimeParts.length; ++i) {
+            if ("base64".equalsIgnoreCase(mimeParts[i])) {
+                base64 = true;
+            }
+        }
+        String dataPartAsString = uriAsString.substring(commaPos + 1);
+        byte[] data = base64 ? Base64.decode(dataPartAsString, Base64.DEFAULT) : EncodingUtils.getBytes(dataPartAsString, "UTF-8");
+        InputStream inputStream = new ByteArrayInputStream(data);
+        return new OpenForReadResult(uri, inputStream, contentType, data.length, null);
+    }
+    
+    private static void assertNonRelative(Uri uri) {
+        if (!uri.isAbsolute()) {
+            throw new IllegalArgumentException("Relative URIs are not supported.");
+        }
+    }
+    
+    public static final class OpenForReadResult {
+        public final Uri uri;
+        public final InputStream inputStream;
+        public final String mimeType;
+        public final long length;
+        public final AssetFileDescriptor assetFd;
+        
+        OpenForReadResult(Uri uri, InputStream inputStream, String mimeType, long length, AssetFileDescriptor assetFd) {
+            this.uri = uri;
+            this.inputStream = inputStream;
+            this.mimeType = mimeType;
+            this.length = length;
+            this.assetFd = assetFd;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/b3b7c0b9/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
new file mode 100755
index 0000000..3a93ce0
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -0,0 +1,1074 @@
+/*
+       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 java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.apache.cordova.Config;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.LOG;
+import org.apache.cordova.PluginManager;
+import org.apache.cordova.PluginResult;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.Log;
+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 com.amazon.android.webkit.AmazonWebBackForwardList;
+import com.amazon.android.webkit.AmazonWebHistoryItem;
+import com.amazon.android.webkit.AmazonWebChromeClient;
+import com.amazon.android.webkit.AmazonWebKitFactories;
+import com.amazon.android.webkit.AmazonWebSettings;
+import com.amazon.android.webkit.AmazonWebView;
+import com.amazon.android.webkit.AmazonWebKitFactory;
+
+import android.widget.FrameLayout;
+
+public class CordovaWebView extends AmazonWebView {
+
+    
+    public static final String TAG = "CordovaWebView";
+    
+    public static final String CORDOVA_VERSION = "3.2.0-dev";
+
+    private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
+    private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
+
+    public PluginManager pluginManager;
+    private boolean paused;
+
+    private BroadcastReceiver receiver;
+
+
+    /** Activities and other important classes **/
+    private CordovaInterface cordova;
+    CordovaWebViewClient viewClient;
+    @SuppressWarnings("unused")
+    private CordovaChromeClient chromeClient;
+
+    private String url;
+
+    // Flag to track that a loadUrl timeout occurred
+    int loadUrlTimeout = 0;
+
+    private boolean bound;
+
+    private boolean handleButton = false;
+    
+    private long lastMenuEventTime = 0;
+
+    NativeToJsMessageQueue jsMessageQueue;
+    ExposedJsApi exposedJsApi;
+
+    /** custom view created by the browser (a video player for example) */
+    private View mCustomView;
+    private AmazonWebChromeClient.CustomViewCallback mCustomViewCallback;
+
+    private ActivityResult mResult = null;
+
+    private CordovaResourceApi resourceApi;
+
+    private static final String APPCACHE_DIR = "database";
+
+    private static final String APPCACHE_DIR_EMPTY = "NONEXISTENT_PATH";
+    private static final String SAFARI_UA = "Safari";
+    private static final String MOBILE_SAFARI_UA = "Mobile Safari";
+    private static final String CORDOVA_AMAZON_FIREOS_UA = "cordova-amazon-fireos/" + CORDOVA_VERSION;
+
+    private static final String LOCAL_STORAGE_DIR = "database";
+
+    /**
+     * Arbitrary size limit for app cache resources
+     */
+    public static final long APP_CACHE_LIMIT = (1024 * 1024 * 50);
+
+    /**
+     * An enumeration to specify the desired back-end to use when constructing
+     * the WebView.
+     */
+    public enum WebViewBackend {
+
+        /** The stock Android WebView back-end */
+        ANDROID,
+
+        /** The Chromium AmazonWebView beck-end */
+        CHROMIUM,
+
+        /**
+         * Automatically select the back-end depending on the device
+         * configuration
+         */
+        AUTOMATIC;
+
+        /**
+         * @return the Android string resource ID for the name of this back-end
+         */
+        public int getNameRes() {
+            switch (this) {
+            case ANDROID:
+                return R.string.backend_name_stock_android;
+            case CHROMIUM:
+                return R.string.backend_name_amazon_chromium;
+            case AUTOMATIC:
+            default:
+                return R.string.backend_name_unknown;
+            }
+        }
+    }
+    class ActivityResult {
+        
+        int request;
+        int result;
+        Intent incoming;
+        
+        public ActivityResult(int req, int res, Intent intent) {
+            request = req;
+            result = res;
+            incoming = intent;
+        }
+
+        
+    }
+    
+    static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
+            new FrameLayout.LayoutParams(
+            ViewGroup.LayoutParams.MATCH_PARENT,
+            ViewGroup.LayoutParams.MATCH_PARENT,
+            Gravity.CENTER);
+    
+    /**
+     * Constructor.
+     *
+     * @param context
+     */
+    public CordovaWebView(Context context) {
+        super(context);
+
+        if (CordovaInterface.class.isInstance(context))
+        {
+            this.cordova = (CordovaInterface) context;
+            this.cordova.getFactory().initializeWebView(this, 0xFFFFFF, false, null);
+        }
+        else
+        {
+            Log.d(TAG, "Your activity must implement CordovaInterface to work");
+        }
+        this.loadConfiguration();
+        this.setup();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param context
+     * @param attrs
+     */
+    public CordovaWebView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        if (CordovaInterface.class.isInstance(context))
+        {
+            this.cordova = (CordovaInterface) context;
+            this.cordova.getFactory().initializeWebView(this, 0xFFFFFF, false, null);
+        }
+        else
+        {
+            Log.d(TAG, "Your activity must implement CordovaInterface to work");
+        }
+        this.setWebChromeClient(new CordovaChromeClient(this.cordova, this));
+        this.initWebViewClient(this.cordova);
+        this.loadConfiguration();
+        this.setup();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param context
+     * @param attrs
+     * @param defStyle
+     *
+     */
+    public CordovaWebView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        if (CordovaInterface.class.isInstance(context))
+        {
+            this.cordova = (CordovaInterface) context;
+            this.cordova.getFactory().initializeWebView(this, 0xFFFFFF, false, null);
+        }
+        else
+        {
+            Log.d(TAG, "Your activity must implement CordovaInterface to work");
+        }
+        this.setWebChromeClient(new CordovaChromeClient(this.cordova, this));
+        this.loadConfiguration();
+        this.setup();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param context
+     * @param attrs
+     * @param defStyle
+     * @param privateBrowsing
+     */
+    @TargetApi(11)
+    public CordovaWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
+        // super(context, attrs, defStyle, privateBrowsing); // DEPRECATED
+        super(context, attrs, defStyle);
+
+        if (CordovaInterface.class.isInstance(context))
+        {
+            this.cordova = (CordovaInterface) context;
+            this.cordova.getFactory().initializeWebView(this, 0xFFFFFF, privateBrowsing, null);
+        }
+        else
+        {
+            Log.d(TAG, "Your activity must implement CordovaInterface to work");
+        }
+        this.setWebChromeClient(new CordovaChromeClient(this.cordova));
+        this.initWebViewClient(this.cordova);
+        this.loadConfiguration();
+        this.setup();
+    }
+
+
+    private void initWebViewClient(CordovaInterface cordova) {
+        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB ||
+                android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
+        {
+            this.setWebViewClient(new CordovaWebViewClient(this.cordova, this));
+        }
+        else
+        {
+            this.setWebViewClient(new IceCreamCordovaWebViewClient(this.cordova, this));
+        }
+    }
+
+    /**
+     * Initialize webview.
+     */
+    @SuppressWarnings("deprecation")
+    @SuppressLint("NewApi")
+    private void setup() {
+        this.setInitialScale(0);
+        this.setVerticalScrollBarEnabled(false);
+        if (shouldRequestFocusOnInit()) {
+			this.requestFocusFromTouch();
+		}
+		// Enable JavaScript
+        AmazonWebSettings settings = this.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setMediaPlaybackRequiresUserGesture(false);    
+        
+        // Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)
+        try {
+            Method gingerbread_getMethod =  AmazonWebSettings.class.getMethod("setNavDump", new Class[] { boolean.class });
+            
+            String manufacturer = android.os.Build.MANUFACTURER;
+            Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
+            if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&
+                    android.os.Build.MANUFACTURER.contains("HTC"))
+            {
+                gingerbread_getMethod.invoke(settings, true);
+            }
+        } catch (NoSuchMethodException e) {
+            Log.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8");
+        } catch (IllegalArgumentException e) {
+            Log.d(TAG, "Doing the NavDump failed with bad arguments");
+        } catch (IllegalAccessException e) {
+            Log.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore");
+        } catch (InvocationTargetException e) {
+            Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore.");
+        }
+
+        //We don't save any form data in the application
+        settings.setSaveFormData(false);
+        settings.setSavePassword(false);
+        
+        // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
+        // while we do this
+        if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+            Level16Apis.enableUniversalAccess(settings);
+                
+        if (getWebViewBackend(this.cordova.getFactory()) == WebViewBackend.ANDROID) {
+        	File appCacheDir = this.cordova.getActivity().getDir(APPCACHE_DIR, Context.MODE_PRIVATE);
+            if (appCacheDir.exists()) {
+                settings.setAppCachePath(appCacheDir.getPath());
+                settings.setAppCacheMaxSize(APP_CACHE_LIMIT);
+                settings.setAppCacheEnabled(true);
+            } else {
+                // shouldn't get here...
+                Log.e(TAG, "Unable to construct application cache directory, feature disabled");
+            }
+
+            File storageDir = this.cordova.getActivity().getDir(LOCAL_STORAGE_DIR, Context.MODE_PRIVATE);
+            if (storageDir.exists()) {
+                settings.setDatabasePath(storageDir.getPath());
+                settings.setDatabaseEnabled(true);
+                settings.setGeolocationDatabasePath(storageDir.getPath());
+            } else {
+                // shouldn't get here...
+                Log.e(TAG, "Unable to construct local storage directory, feature disabled");
+            }
+        } else {
+            // setting a custom path (as well as the max cache size) is not supported by Chromium,
+            // however setting the path to a non-null non-empty string is required for it to function
+            settings.setAppCachePath(APPCACHE_DIR_EMPTY);
+            settings.setAppCacheEnabled(true);
+            
+            // enable the local storage database normally with the Chromium back-end
+            settings.setDatabaseEnabled(true);
+        }
+
+        // Enable DOM storage
+        settings.setDomStorageEnabled(true);
+
+        // Enable built-in geolocation
+        settings.setGeolocationEnabled(true);
+        
+         // Fix UserAgent string
+        String userAgent = settings.getUserAgentString();
+        if ((userAgent.indexOf(MOBILE_SAFARI_UA) == -1) && (userAgent.indexOf(SAFARI_UA) != -1)) {
+            // Replace Safari with Mobile Safari
+            userAgent = userAgent.replace(SAFARI_UA, MOBILE_SAFARI_UA);
+        }
+        userAgent = userAgent.concat(" " + CORDOVA_AMAZON_FIREOS_UA); 
+        settings.setUserAgentString(userAgent);
+
+        // Fix for CB-1405
+        // Google issue 4641
+        this.updateUserAgentString();
+        
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        if (this.receiver == null) {
+            this.receiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    updateUserAgentString();
+                }
+            };
+            this.cordova.getActivity().registerReceiver(this.receiver, intentFilter);
+        }
+        // end CB-1405
+
+        settings.setUseWideViewPort(true);
+
+        pluginManager = new PluginManager(this, this.cordova);
+        jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
+        exposedJsApi = new ExposedJsApi(pluginManager, jsMessageQueue);
+        resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
+        exposeJsInterface();
+    }
+    
+    /**
+     * The actual back-end used when constructing the WebView. Note that this
+     * may differ from the requested back-end depending on the device
+     * configuration.
+     * 
+     * @return either {@link WebViewBackend#AMAZON} or
+     *         {@link WebViewBackend#ANDROID}
+     */
+    static WebViewBackend getWebViewBackend(AmazonWebKitFactory factory) {
+    	// This is to figure out if WebView is using Chromium based webapp runtime or stock AndroidWebView.
+    	// On Kindle devices default is Chromium based. There is no public API to figure out the difference. 
+    	// EmbeddedWebKitFactory is not a plublic class so only way to check is using this AmazonWebKitFactories.EMBEDDED_FACTORY class name.
+    	if (factory.getClass().getName().equals(AmazonWebKitFactories.EMBEDDED_FACTORY) ) {
+            return WebViewBackend.CHROMIUM;
+        }
+        return WebViewBackend.ANDROID;
+    }
+
+	/**
+	 * Override this method to decide wether or not you need to request the
+	 * focus when your application start
+	 * 
+	 * @return
+	 */
+    protected boolean shouldRequestFocusOnInit() {
+		return true;
+	}
+
+	private void updateUserAgentString() {
+        this.getSettings().getUserAgentString();
+    }
+
+    private void exposeJsInterface() {
+        int SDK_INT = Build.VERSION.SDK_INT;
+        boolean isHoneycomb = (SDK_INT >= Build.VERSION_CODES.HONEYCOMB && SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2);
+        if (isHoneycomb || (SDK_INT < Build.VERSION_CODES.GINGERBREAD)) {
+            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
+            // use the prompt bridge instead.
+            return;            
+        } else if (SDK_INT < Build.VERSION_CODES.HONEYCOMB && Build.MANUFACTURER.equals("unknown")) {
+            // addJavascriptInterface crashes on the 2.3 emulator.
+            Log.i(TAG, "Disabled addJavascriptInterface() bridge callback due to a bug on the 2.3 emulator");
+            return;
+        }
+        this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
+    }
+
+    /**
+     * Set the WebViewClient.
+     *
+     * @param client
+     */
+    public void setWebViewClient(CordovaWebViewClient client) {
+        this.viewClient = client;
+        super.setWebViewClient(client);
+    }
+
+    /**
+     * Set the AmazonWebChromeClient.
+     *
+     * @param client
+     */
+    public void setWebChromeClient(CordovaChromeClient client) {
+        this.chromeClient = client;
+        super.setWebChromeClient(client);
+    }
+    
+    public CordovaChromeClient getWebChromeClient() {
+        return this.chromeClient;
+    }
+
+    /**
+     * Load the url into the webview.
+     *
+     * @param url
+     */
+    @Override
+    public void loadUrl(String url) {
+        if (url.equals("about:blank") || url.startsWith("javascript:")) {
+            this.loadUrlNow(url);
+        }
+        else {
+
+            String initUrl = this.getProperty("url", null);
+
+            // If first page of app, then set URL to load to be the one passed in
+            if (initUrl == null) {
+                this.loadUrlIntoView(url);
+            }
+            // Otherwise use the URL specified in the activity's extras bundle
+            else {
+                this.loadUrlIntoView(initUrl);
+            }
+        }
+    }
+
+    /**
+     * Load the url into the webview after waiting for period of time.
+     * This is used to display the splashscreen for certain amount of time.
+     *
+     * @param url
+     * @param time              The number of ms to wait before loading webview
+     */
+    public void loadUrl(final String url, int time) {
+        String initUrl = this.getProperty("url", null);
+
+        // If first page of app, then set URL to load to be the one passed in
+        if (initUrl == null) {
+            this.loadUrlIntoView(url, time);
+        }
+        // Otherwise use the URL specified in the activity's extras bundle
+        else {
+            this.loadUrlIntoView(initUrl);
+        }
+    }
+
+    /**
+     * Load the url into the webview.
+     *
+     * @param url
+     */
+    public void loadUrlIntoView(final String url) {
+        LOG.d(TAG, ">>> loadUrl(" + url + ")");
+
+        this.url = url;
+        this.pluginManager.init();
+
+
+        // Create a timeout timer for loadUrl
+        final CordovaWebView me = this;
+        final int currentLoadUrlTimeout = me.loadUrlTimeout;
+        final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("LoadUrlTimeoutValue", "20000"));
+
+        // Timeout error method
+        final Runnable loadError = new Runnable() {
+            public void run() {
+                me.stopLoading();
+                LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
+                if (viewClient != null) {
+                    viewClient.onReceivedError(me, -6, "The connection to the server was unsuccessful.", url);
+                }
+            }
+        };
+
+        // Timeout timer method
+        final Runnable timeoutCheck = new Runnable() {
+            public void run() {
+                try {
+                    synchronized (this) {
+                        wait(loadUrlTimeoutValue);
+                    }
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+
+                // If timeout, then stop loading and handle error
+                if (me.loadUrlTimeout == currentLoadUrlTimeout) {
+                    me.cordova.getActivity().runOnUiThread(loadError);
+                }
+            }
+        };
+
+        // Load url
+        this.cordova.getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                Thread thread = new Thread(timeoutCheck);
+                thread.start();
+                me.loadUrlNow(url);
+            }
+        });
+    }
+
+    /**
+     * Load URL in webview.
+     *
+     * @param url
+     */
+    void loadUrlNow(String url) {
+        if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
+            LOG.d(TAG, ">>> loadUrlNow()");
+        }
+        if (url.startsWith("file://") || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
+            super.loadUrl(url);
+        }
+    }
+
+    /**
+     * Load the url into the webview after waiting for period of time.
+     * This is used to display the splashscreen for certain amount of time.
+     *
+     * @param url
+     * @param time              The number of ms to wait before loading webview
+     */
+    public void loadUrlIntoView(final String url, final int time) {
+
+        // If not first page of app, then load immediately
+        // Add support for browser history if we use it.
+        if ((url.startsWith("javascript:")) || this.canGoBack()) {
+        }
+
+        // If first page, then show splashscreen
+        else {
+
+            LOG.d(TAG, "loadUrlIntoView(%s, %d)", url, time);
+
+            // Send message to show splashscreen now if desired
+            this.postMessage("splashscreen", "show");
+        }
+
+        // Load url
+        this.loadUrlIntoView(url);
+    }
+    
+    /**
+     * Send JavaScript statement back to JavaScript.
+     * (This is a convenience method)
+     *
+     * @param statement
+     */
+    public void sendJavascript(String statement) {
+        this.jsMessageQueue.addJavaScript(statement);
+    }
+
+    /**
+     * Send a plugin result back to JavaScript.
+     * (This is a convenience method)
+     *
+     * @param result
+     * @param callbackId
+     */
+    public void sendPluginResult(PluginResult result, String callbackId) {
+        this.jsMessageQueue.addPluginResult(result, callbackId);
+    }
+
+    /**
+     * Send a message to all plugins.
+     *
+     * @param id            The message id
+     * @param data          The message data
+     */
+    public void postMessage(String id, Object data) {
+        if (this.pluginManager != null) {
+            this.pluginManager.postMessage(id, data);
+        }
+    }
+
+
+    /**
+     * Go to previous page in history.  (We manage our own history)
+     *
+     * @return true if we went back, false if we are already at top
+     */
+    public boolean backHistory() {
+
+        // Check webview first to see if there is a history
+        // This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
+        if (super.canGoBack()) {
+            printBackForwardList();
+            super.goBack();
+            
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Load the specified URL in the Cordova webview or a new browser instance.
+     *
+     * NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
+     *
+     * @param url           The url to load.
+     * @param openExternal  Load url in browser instead of Cordova webview.
+     * @param clearHistory  Clear the history stack, so new page becomes top of history
+     * @param params        Parameters for new app
+     */
+    public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
+        LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
+
+        // If clearing history
+        if (clearHistory) {
+            this.clearHistory();
+        }
+
+        // If loading into our webview
+        if (!openExternal) {
+
+            // Make sure url is in whitelist
+            if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
+                // TODO: What about params?
+                // Load new URL
+                this.loadUrl(url);
+            }
+            // Load in default viewer if not
+            else {
+                LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list.  Loading into browser instead. (URL=" + url + ")");
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(TAG, "Error loading url " + url, e);
+                }
+            }
+        }
+
+        // Load in default view intent
+        else {
+            try {
+                Intent intent = new Intent(Intent.ACTION_VIEW);
+                intent.setData(Uri.parse(url));
+                cordova.getActivity().startActivity(intent);
+            } catch (android.content.ActivityNotFoundException e) {
+                LOG.e(TAG, "Error loading url " + url, e);
+            }
+        }
+    }
+
+    /**
+     * Check configuration parameters from Config.
+     * Approved list of URLs that can be loaded into Cordova
+     *      <access origin="http://server regexp" subdomains="true" />
+     * Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
+     *      <log level="DEBUG" />
+     */
+    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.
+     *
+     * @param name
+     * @param defaultValue
+     * @return
+     */
+    public String getProperty(String name, String defaultValue) {
+        Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
+        if (bundle == null) {
+            return defaultValue;
+        }
+        name = name.toLowerCase(Locale.getDefault());
+        Object p = bundle.get(name);
+        if (p == null) {
+            return defaultValue;
+        }
+        return p.toString();
+    }
+
+    /*
+     * onKeyDown
+     */
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event)
+    {
+        if(keyDownCodes.contains(keyCode))
+        {
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+                    // only override default behavior is event bound
+                    LOG.d(TAG, "Down Key Hit");
+                    this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
+                    return true;
+            }
+            // If volumeup key
+            else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+                    LOG.d(TAG, "Up Key Hit");
+                    this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
+                    return true;
+            }
+            else
+            {
+                return super.onKeyDown(keyCode, event);
+            }
+        }
+        else if(keyCode == KeyEvent.KEYCODE_BACK)
+        {
+            return !(this.startOfHistory()) || this.bound;
+        }
+        else if(keyCode == KeyEvent.KEYCODE_MENU)
+        {
+            //How did we get here?  Is there a childView?
+            View childView = this.getFocusedChild();
+            if(childView != null)
+            {
+                //Make sure we close the keyboard if it's present
+                InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+                imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
+                cordova.getActivity().openOptionsMenu();
+                return true;
+            } else {
+                return super.onKeyDown(keyCode, event);
+            }
+        }
+        
+        return super.onKeyDown(keyCode, event);
+    }
+    
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event)
+    {
+        // If back key
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            // A custom view is currently displayed  (e.g. playing a video)
+            if(mCustomView != null) {
+                this.hideCustomView();
+            } else {
+                // The webview is currently displayed
+                // If back key is bound, then send event to JavaScript
+                if (this.bound) {
+                    this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
+                    return true;
+                } else {
+                    // If not bound
+                    // Go to previous page in webview if it is possible to go back
+                    if (this.backHistory()) {
+                        return true;
+                    }
+                    // If not, then invoke default behaviour
+                    else {
+                        //this.activityState = ACTIVITY_EXITING;
+                    	//return false;
+                    	// If they hit back button when app is initializing, app should exit instead of hang until initilazation (CB2-458)
+                    	this.cordova.getActivity().finish();
+                    }
+                }
+            }
+        }
+        // Legacy
+        else if (keyCode == KeyEvent.KEYCODE_MENU) {
+            if (this.lastMenuEventTime < event.getEventTime()) {
+                this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');");
+            }
+            this.lastMenuEventTime = event.getEventTime();
+            return super.onKeyUp(keyCode, event);
+        }
+        // If search key
+        else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+            this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
+            return true;
+        }
+        else if(keyUpCodes.contains(keyCode))
+        {
+            //What the hell should this do?
+            return super.onKeyUp(keyCode, event);
+        }
+
+        //Does webkit change this behavior?
+        return super.onKeyUp(keyCode, event);
+    }
+
+    
+    public void bindButton(boolean override)
+    {
+        this.bound = override;
+    }
+
+    public void bindButton(String button, boolean override) {
+        // TODO Auto-generated method stub
+        if (button.compareTo("volumeup")==0) {
+          keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_UP);
+        }
+        else if (button.compareTo("volumedown")==0) {
+          keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_DOWN);
+        }
+      }
+
+    public void bindButton(int keyCode, boolean keyDown, boolean override) {
+       if(keyDown)
+       {
+           keyDownCodes.add(keyCode);
+       }
+       else
+       {
+           keyUpCodes.add(keyCode);
+       }
+    }
+
+    public boolean isBackButtonBound()
+    {
+        return this.bound;
+    }
+    
+    public void handlePause(boolean keepRunning)
+    {
+        LOG.d(TAG, "Handle the pause");
+        // Send pause event to JavaScript
+        this.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};");
+
+        // Forward to plugins
+        if (this.pluginManager != null) {
+            this.pluginManager.onPause(keepRunning);
+        }
+
+        // If app doesn't want to run in background
+        if (!keepRunning) {
+            // Pause JavaScript timers (including setInterval)
+            this.pauseTimers();
+            this.onPause();
+        }
+        paused = true;
+   
+    }
+    
+    public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
+    {
+
+        this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
+        
+        // Forward to plugins
+        if (this.pluginManager != null) {
+            this.pluginManager.onResume(keepRunning);
+        }
+
+        //resume first and then resumeTimers
+        this.onResume();
+        // Resume JavaScript timers (including setInterval)
+        this.resumeTimers();
+        paused = false;
+    }
+    
+    public void handleDestroy()
+    {
+        // Send destroy event to JavaScript
+        this.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
+
+        // Load blank page so that JavaScript onunload is called
+        this.loadUrl("about:blank");
+
+        // Forward to plugins
+        if (this.pluginManager != null) {
+            this.pluginManager.onDestroy();
+        }
+        
+        // unregister the receiver
+        if (this.receiver != null) {
+            try {
+                this.cordova.getActivity().unregisterReceiver(this.receiver);
+            } catch (Exception e) {
+                Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
+            }
+        }
+    }
+    
+    public void onNewIntent(Intent intent)
+    {
+        //Forward to plugins
+        if (this.pluginManager != null) {
+            this.pluginManager.onNewIntent(intent);
+        }
+    }
+    
+    public boolean isPaused()
+    {
+        return paused;
+    }
+
+    public boolean hadKeyEvent() {
+        return handleButton;
+    }
+
+    // Wrapping these functions in their own class prevents warnings in adb like:
+    // VFY: unable to resolve virtual method 285: Landroid/webkit/AmazonWebSettings;.setAllowUniversalAccessFromFileURLs
+    @TargetApi(16)
+    private static class Level16Apis {
+        static void enableUniversalAccess(AmazonWebSettings settings) {
+            settings.setAllowUniversalAccessFromFileURLs(true);
+        }
+    }
+    
+    public void printBackForwardList() {
+        AmazonWebBackForwardList currentList = this.copyBackForwardList();
+        int currentSize = currentList.getSize();
+        for(int i = 0; i < currentSize; ++i)
+        {
+            AmazonWebHistoryItem item = currentList.getItemAtIndex(i);
+            String url = item.getUrl();
+            LOG.d(TAG, "The URL at index: " + Integer.toString(i) + "is " + url );
+        }
+    }
+    
+    
+    //Can Go Back is BROKEN!
+    public boolean startOfHistory()
+    {
+        AmazonWebBackForwardList currentList = this.copyBackForwardList();
+        AmazonWebHistoryItem item = currentList.getItemAtIndex(0);
+        if( item!=null){	// Null-fence in case they haven't called loadUrl yet (CB-2458)
+	        String url = item.getUrl();
+	        String currentUrl = this.getUrl();
+	        LOG.d(TAG, "The current URL is: " + currentUrl);
+	        LOG.d(TAG, "The URL at item 0 is:" + url);
+	        return currentUrl.equals(url);
+        }
+        return false;
+    }
+
+    public void showCustomView(View view, AmazonWebChromeClient.CustomViewCallback callback) {
+        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
+        Log.d(TAG, "showing Custom View");
+        // if a view already exists then immediately terminate the new one
+        if (mCustomView != null) {
+            callback.onCustomViewHidden();
+            return;
+        }
+        
+        // Store the view and its callback for later (to kill it properly)
+        mCustomView = view;
+        mCustomViewCallback = callback;
+        
+        // Add the custom view to its container.
+        ViewGroup parent = (ViewGroup) this.getParent();
+        parent.addView(view, COVER_SCREEN_GRAVITY_CENTER);
+        
+        // Hide the content view.
+        this.setVisibility(View.GONE);
+        
+        // Finally show the custom view container.
+        parent.setVisibility(View.VISIBLE);
+        parent.bringToFront();
+    }
+
+    public void hideCustomView() {
+        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
+        Log.d(TAG, "Hidding Custom View");
+        if (mCustomView == null) return;
+
+        // Hide the custom view.
+        mCustomView.setVisibility(View.GONE);
+        
+        // Remove the custom view from its container.
+        ViewGroup parent = (ViewGroup) this.getParent();
+        parent.removeView(mCustomView);
+        mCustomView = null;
+        mCustomViewCallback.onCustomViewHidden();
+        
+        // Show the content view.
+        this.setVisibility(View.VISIBLE);
+    }
+    
+    /**
+     * if the video overlay is showing then we need to know 
+     * as it effects back button handling
+     * 
+     * @return
+     */
+    public boolean isCustomViewShowing() {
+        return mCustomView != null;
+    }
+    
+    public AmazonWebBackForwardList restoreState(Bundle savedInstanceState)
+    {
+        AmazonWebBackForwardList myList = super.restoreState(savedInstanceState);
+        Log.d(TAG, "AmazonWebView restoration crew now restoring!");
+        //Initialize the plugin manager once more
+        this.pluginManager.init();
+        return myList;
+    }
+
+    public void storeResult(int requestCode, int resultCode, Intent intent) {
+        mResult = new ActivityResult(requestCode, resultCode, intent);
+    }
+    
+    public CordovaResourceApi getResourceApi() {
+        return resourceApi;
+    }
+}


Mime
View raw message