cordova-plugin-themeablebrowser icon indicating copy to clipboard operation
cordova-plugin-themeablebrowser copied to clipboard

Cannot Upload Files Even After Tweaking [Modified Code]

Open lethalazo opened this issue 8 years ago • 0 comments

I Am Loading Facebook Site In The Browser And Looks Like No Cordova Browser Support File Uploading.

#I Wonder How The Native Browsers Enable Upload In The Webview Afterall Themeable Browser Is Doing The Similar Job As The Native Browsers (Loading WebView) I Tried To Tweak The Code (My First Ever Interaction With .java Code) But No Success I Need Uploads In The Browser Badly :( Please Help ASAP

Here's The Code

New Code At The Top Of Class And At The End

`package com.initialxy.cordova.themeablebrowser;

import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Browser; import android.text.InputType; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.webkit.CookieManager; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.VideoView; import android.webkit.DownloadListener;

import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date;

import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.PluginResult.Status; import org.apache.cordova.CordovaArgs; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaWebView; import org.apache.cordova.PluginManager; import org.apache.cordova.PluginResult; import org.apache.cordova.Whitelist; import org.json.JSONException; import org.json.JSONObject; import org.apache.cordova.file.FileUtils; import org.apache.cordova.filetransfer.FileTransfer; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ClipDrawable; import android.widget.ProgressBar; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;

@SuppressLint("SetJavaScriptEnabled") public class ThemeableBrowser extends CordovaPlugin {

private static final String NULL = "null";
protected static final String LOG_TAG = "ThemeableBrowser";
private static final String SELF = "_self";
private static final String SYSTEM = "_system";
// private static final String BLANK = "_blank";
private static final String EXIT_EVENT = "exit";
private static final String LOAD_START_EVENT = "loadstart";
private static final String LOAD_STOP_EVENT = "loadstop";
private static final String LOAD_ERROR_EVENT = "loaderror";

private static final String ALIGN_LEFT = "left";
private static final String ALIGN_RIGHT = "right";

private static final int TOOLBAR_DEF_HEIGHT = 44;
private static final int DISABLED_ALPHA = 127;  // 50% AKA 127/255.

private static final String EVT_ERR = "ThemeableBrowserError";
private static final String EVT_WRN = "ThemeableBrowserWarning";
private static final String ERR_CRITICAL = "critical";
private static final String ERR_LOADFAIL = "loadfail";
private static final String WRN_UNEXPECTED = "unexpected";
private static final String WRN_UNDEFINED = "undefined";

private String mCM;
private ValueCallback<Uri> mUM;
private ValueCallback<Uri[]> mUMA;
private static final int FCR = 1;
// private CordovaInterface cordova;
private ThemeableBrowserDialog dialog;
private WebView inAppWebView;
private EditText edittext;
private CallbackContext callbackContext;
private static final String TAG = "No";

/**
 * Executes the request and returns PluginResult.
 *
 * @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
 * @throws JSONException
 */

public void onCreate(Bundle savedInstanceState){
	super.onCreate(savedInstanceState);
	inAppWebView.setWebViewClient(new Callback());
	final CordovaWebView thatWebView = this.webView;
	final ProgressBar progressbar = new ProgressBar(cordova.getActivity(), null, android.R.attr.progressBarStyleHorizontal);
    inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView, progressbar){
            	//For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg){
            mUM = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("image/*");
            cordova.setActivityResultCallback (this);
            cordova.getActivity().startActivityForResult(Intent.createChooser(i,"File Chooser"), FCR);
        }
        // // For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
        public void openFileChooser(ValueCallback uploadMsg, String acceptType){
            mUM = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            cordova.setActivityResultCallback (this);
            cordova.getActivity().startActivityForResult(
                    Intent.createChooser(i, "File Browser"),
                    FCR);
        }
        // //For Android 4.1+
        // public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
        //     mUM = uploadMsg;
        //     Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        //     i.addCategory(Intent.CATEGORY_OPENABLE);
        //     i.setType("image/*");
        //     cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Chooser"), cordova.getActivity().FCR);
        // }
        //For Android 5.0+
        public boolean onShowFileChooser(
                WebView webView, ValueCallback<Uri[]> filePathCallback,
                WebChromeClient.FileChooserParams fileChooserParams){
            if(mUMA != null){
                mUMA.onReceiveValue(null);
            }
            mUMA = filePathCallback;
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            if(takePictureIntent.resolveActivity(cordova.getActivity().getPackageManager()) != null){
                File photoFile = null;
                try{
                    photoFile = createImageFile();
                    takePictureIntent.putExtra("PhotoPath", mCM);
                }catch(IOException ex){
                    Log.e(TAG, "Image file creation failed", ex);
                }
                if(photoFile != null){
                    mCM = "file:" + photoFile.getAbsolutePath();
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
                }else{
                    takePictureIntent = null;
                }
            }
            Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
            contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
            contentSelectionIntent.setType("image/*");
            Intent[] intentArray;
            if(takePictureIntent != null){
                intentArray = new Intent[]{takePictureIntent};
            }else{
                intentArray = new Intent[0];
            }

            Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
            chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
            chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
            cordova.setActivityResultCallback (this);
            cordova.getActivity().startActivityForResult(chooserIntent, FCR);
            return true;
        }
    });
}

@Override public void onActivityResult(int requestCode, int resultCode, Intent intent){ super.onActivityResult(requestCode, resultCode, intent); if(Build.VERSION.SDK_INT >= 21){ Uri[] results = null; //Check if response is positive if(resultCode== Activity.RESULT_OK){ if(requestCode == FCR){ if(null == mUMA){ return; } if(intent == null){ //Capture Photo if no image available if(mCM != null){ results = new Uri[]{Uri.parse(mCM)}; } }else{ String dataString = intent.getDataString(); if(dataString != null){ results = new Uri[]{Uri.parse(dataString)}; } } } } mUMA.onReceiveValue(results); mUMA = null; }else{ if(requestCode == FCR){ if(null == mUM) return; Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); mUM.onReceiveValue(result); mUM = null; } } }

public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
    if (action.equals("open")) {
        this.callbackContext = callbackContext;
        final String url = args.getString(0);
        String t = args.optString(1);
        if (t == null || t.equals("") || t.equals(NULL)) {
            t = SELF;
        }
        final String target = t;
        final Options features = parseFeature(args.optString(2));

        this.cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String result = "";
                // SELF
                if (SELF.equals(target)) {
                    /* This code exists for compatibility between 3.x and 4.x versions of Cordova.
                     * Previously the Config class had a static method, isUrlWhitelisted(). That
                     * responsibility has been moved to the plugins, with an aggregating method in
                     * PluginManager.
                     */
                    Boolean shouldAllowNavigation = null;
                    if (url.startsWith("javascript:")) {
                        shouldAllowNavigation = true;
                    }
                    if (shouldAllowNavigation == null) {
                        shouldAllowNavigation = new Whitelist().isUrlWhiteListed(url);
                    }
                    if (shouldAllowNavigation == null) {
                        try {
                            Method gpm = webView.getClass().getMethod("getPluginManager");
                            PluginManager pm = (PluginManager)gpm.invoke(webView);
                            Method san = pm.getClass().getMethod("shouldAllowNavigation", String.class);
                            shouldAllowNavigation = (Boolean)san.invoke(pm, url);
                        } catch (NoSuchMethodException e) {
                        } catch (IllegalAccessException e) {
                        } catch (InvocationTargetException e) {
                        }
                    }
                    // load in webview
                    if (Boolean.TRUE.equals(shouldAllowNavigation)) {
                        webView.loadUrl(url);
                    }
                    //Load the dialer
                    else if (url.startsWith(WebView.SCHEME_TEL))
                    {
                        try {
                            Intent intent = new Intent(Intent.ACTION_DIAL);
                            intent.setData(Uri.parse(url));
                            cordova.getActivity().startActivity(intent);
                        } catch (android.content.ActivityNotFoundException e) {
                            emitError(ERR_CRITICAL,
                                    String.format("Error dialing %s: %s", url, e.toString()));
                        }
                    }
                    // load in ThemeableBrowser
                    else {
                        result = showWebPage(url, features);
                    }
                }
                // SYSTEM
                else if (SYSTEM.equals(target)) {
                    result = openExternal(url);
                }
                // BLANK - or anything else
                else {
                    result = showWebPage(url, features);
                }

                PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
                pluginResult.setKeepCallback(true);
                callbackContext.sendPluginResult(pluginResult);
            }
        });
    }
    else if (action.equals("close")) {
        closeDialog();
    }
    else if (action.equals("injectScriptCode")) {
        String jsWrapper = null;
        if (args.getBoolean(1)) {
            jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
        }
        injectDeferredObject(args.getString(0), jsWrapper);
    }
    else if (action.equals("injectScriptFile")) {
        String jsWrapper;
        if (args.getBoolean(1)) {
            jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
        } else {
            jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
        }
        injectDeferredObject(args.getString(0), jsWrapper);
    }
    else if (action.equals("injectStyleCode")) {
        String jsWrapper;
        if (args.getBoolean(1)) {
            jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
        } else {
            jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
        }
        injectDeferredObject(args.getString(0), jsWrapper);
    }
    else if (action.equals("injectStyleFile")) {
        String jsWrapper;
        if (args.getBoolean(1)) {
            jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
        } else {
            jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
        }
        injectDeferredObject(args.getString(0), jsWrapper);
    }
    else if (action.equals("show")) {
        this.cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialog.show();
            }
        });
        PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
        pluginResult.setKeepCallback(true);
        this.callbackContext.sendPluginResult(pluginResult);
    }
    else if (action.equals("reload")) {
        if (inAppWebView != null) {
            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    inAppWebView.reload();
                }
            });
        }
    }
    else {
        return false;
    }
    return true;
}

/**
 * Called when the view navigates.
 */
@Override
public void onReset() {
    closeDialog();
}

/**
 * Called by AccelBroker when listener is to be shut down.
 * Stop listener.
 */
public void onDestroy() {
    closeDialog();
}

/**
 * Inject an object (script or style) into the ThemeableBrowser WebView.
 *
 * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
 * provides a consistent method for injecting JavaScript code into the document.
 *
 * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
 * quotes) and wrapped using string formatting. (The wrapper string should have a single
 * '%s' marker)
 *
 * @param source      The source object (filename or script/style text) to inject into
 *                    the document.
 * @param jsWrapper   A JavaScript string to wrap the source string in, so that the object
 *                    is properly injected, or null if the source string is JavaScript text
 *                    which should be executed directly.
 */
private void injectDeferredObject(String source, String jsWrapper) {
    String scriptToInject;
    if (jsWrapper != null) {
        org.json.JSONArray jsonEsc = new org.json.JSONArray();
        jsonEsc.put(source);
        String jsonRepr = jsonEsc.toString();
        String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
        scriptToInject = String.format(jsWrapper, jsonSourceString);
    } else {
        scriptToInject = source;
    }
    final String finalScriptToInject = scriptToInject;
    this.cordova.getActivity().runOnUiThread(new Runnable() {
        @SuppressLint("NewApi")
        @Override
        public void run() {
            if (inAppWebView != null) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                    // This action will have the side-effect of blurring the currently focused
                    // element
                    inAppWebView.loadUrl("javascript:" + finalScriptToInject);
                } else {
                    inAppWebView.evaluateJavascript(finalScriptToInject, null);
                }
            }
        }
    });
}

/**
 * Put the list of features into a hash map
 *
 * @param optString
 * @return
 */
private Options parseFeature(String optString) {
    Options result = null;
    if (optString != null && !optString.isEmpty()) {
        try {
            result = ThemeableBrowserUnmarshaller.JSONToObj(
                    optString, Options.class);
        } catch (Exception e) {
            emitError(ERR_CRITICAL,
                    String.format("Invalid JSON @s", e.toString()));
        }
    } else {
        emitWarning(WRN_UNDEFINED,
                "No config was given, defaults will be used, "
                + "which is quite boring.");
    }

    if (result == null) {
        result = new Options();
    }

    // Always show location, this property is overwritten.
    result.location = true;

    return result;
}

/**
 * Display a new browser with the specified URL.
 *
 * @param url
 * @return
 */
public String openExternal(String url) {
    try {
        Intent intent = null;
        intent = new Intent(Intent.ACTION_VIEW);
        // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
        // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
        Uri uri = Uri.parse(url);
        if ("file".equals(uri.getScheme())) {
            intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
        } else {
            intent.setData(uri);
        }
        intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
        this.cordova.getActivity().startActivity(intent);
        return "";
    } catch (android.content.ActivityNotFoundException e) {
        Log.d(LOG_TAG, "ThemeableBrowser: Error loading url "+url+":"+ e.toString());
        return e.toString();
    }
}

/**
 * Closes the dialog
 */
public void closeDialog() {
    this.cordova.getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // The JS protects against multiple calls, so this should happen only when
            // closeDialog() is called by other native code.
            if (inAppWebView == null) {
                emitWarning(WRN_UNEXPECTED, "Close called but already closed.");
                return;
            }

            inAppWebView.setWebViewClient(new WebViewClient() {
                // NB: wait for about:blank before dismissing
                public void onPageFinished(WebView view, String url) {
                    if (dialog != null) {
                        dialog.dismiss();
                    }

                    // Clean up.
                    dialog = null;
                    inAppWebView = null;
                    edittext = null;
                    callbackContext = null;
                }
            });

            // NB: From SDK 19: "If you call methods on WebView from any
            // thread other than your app's UI thread, it can cause
            // unexpected results."
            // http://developer.android.com/guide/webapps/migrating.html#Threads
            inAppWebView.loadUrl("about:blank");

            try {
                JSONObject obj = new JSONObject();
                obj.put("type", EXIT_EVENT);
                sendUpdate(obj, false);
            } catch (JSONException ex) {
            }
        }
    });
}

private void emitButtonEvent(Event event, String url) {
    emitButtonEvent(event, url, null);
}

private void emitButtonEvent(Event event, String url, Integer index) {
    if (event != null && event.event != null) {
        try {
            JSONObject obj = new JSONObject();
            obj.put("type", event.event);
            obj.put("url", url);
            if (index != null) {
                obj.put("index", index.intValue());
            }
            sendUpdate(obj, true);
        } catch (JSONException e) {
            // Ignore, should never happen.
        }
    } else {
        emitWarning(WRN_UNDEFINED,
                "Button clicked, but event property undefined. "
                + "No event will be raised.");
    }
}

private void emitError(String code, String message) {
    emitLog(EVT_ERR, code, message);
}

private void emitWarning(String code, String message) {
    emitLog(EVT_WRN, code, message);
}

private void emitLog(String type, String code, String message) {
    if (type != null) {
        try {
            JSONObject obj = new JSONObject();
            obj.put("type", type);
            obj.put("code", code);
            obj.put("message", message);
            sendUpdate(obj, true);
        } catch (JSONException e) {
            // Ignore, should never happen.
        }
    }
}

/**
 * Checks to see if it is possible to go back one page in history, then does so.
 */
public void goBack() {
    if (this.inAppWebView != null && this.inAppWebView.canGoBack()) {
        this.inAppWebView.goBack();
    }
}

/**
 * Can the web browser go back?
 * @return boolean
 */
public boolean canGoBack() {
    return this.inAppWebView != null && this.inAppWebView.canGoBack();
}

/**
 * Checks to see if it is possible to go forward one page in history, then does so.
 */
private void goForward() {
    if (this.inAppWebView != null && this.inAppWebView.canGoForward()) {
        this.inAppWebView.goForward();
    }
}

/**
 * Navigate to the new page
 *
 * @param url to load
 */
private void navigate(String url) {
    InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);

    if (!url.startsWith("http") && !url.startsWith("file:")) {
        this.inAppWebView.loadUrl("http://" + url);
    } else {
        this.inAppWebView.loadUrl(url);
    }
    this.inAppWebView.setDownloadListener(new DownloadListener() {
                public void onDownloadStart(String url, String userAgent,
                        String contentDisposition, String mimetype,
                        long contentLength) {
                  Intent i = new Intent(Intent.ACTION_VIEW);
                  i.setData(Uri.parse(url));
                  cordova.getActivity().startActivity(i);
                }
            });
    this.inAppWebView.requestFocus();
}

private ThemeableBrowser getThemeableBrowser() {
    return this;
}

/**
 * Display a new browser with the specified URL.
 *
 * @param url
 * @param features
 * @return
 */
public String showWebPage(final String url, final Options features) {
    final CordovaWebView thatWebView = this.webView;

    // Create dialog in new thread
    Runnable runnable = new Runnable() {
        @SuppressLint("NewApi")
        public void run() {
            // Let's create the main dialog
            dialog = new ThemeableBrowserDialog(cordova.getActivity(),
                    android.R.style.Theme_Black_NoTitleBar,
                    features.hardwareback);
            if (!features.disableAnimation) {
                dialog.getWindow().getAttributes().windowAnimations
                        = android.R.style.Animation_Dialog;
            }
            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            dialog.setCancelable(true);
            dialog.setThemeableBrowser(getThemeableBrowser());

            // Main container layout
            ViewGroup main = null;

            if (features.fullscreen) {
                main = new FrameLayout(cordova.getActivity());
            } else {
                main = new LinearLayout(cordova.getActivity());
                ((LinearLayout) main).setOrientation(LinearLayout.VERTICAL);
            }

            // Toolbar layout
            Toolbar toolbarDef = features.toolbar;
            FrameLayout toolbar = new FrameLayout(cordova.getActivity());
            toolbar.setBackgroundColor(hexStringToColor(
                    toolbarDef != null && toolbarDef.color != null
                            ? toolbarDef.color : "#ffffffff"));
            toolbar.setLayoutParams(new ViewGroup.LayoutParams(
                    LayoutParams.MATCH_PARENT,
                    dpToPixels(toolbarDef != null
                            ? toolbarDef.height : TOOLBAR_DEF_HEIGHT)));

            if (toolbarDef != null
                    && (toolbarDef.image != null || toolbarDef.wwwImage != null)) {
                try {
                    Drawable background = getImage(toolbarDef.image
                            , toolbarDef.wwwImage, toolbarDef.wwwImageDensity);
                    setBackground(toolbar, background);
                } catch (Resources.NotFoundException e) {
                    emitError(ERR_LOADFAIL,
                            String.format("Image for toolbar, %s, failed to load",
                                    toolbarDef.image));
                } catch (IOException ioe) {
                    emitError(ERR_LOADFAIL,
                            String.format("Image for toolbar, %s, failed to load",
                                    toolbarDef.wwwImage));
                }
            }

            // Left Button Container layout
            LinearLayout leftButtonContainer = new LinearLayout(cordova.getActivity());
            FrameLayout.LayoutParams leftButtonContainerParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            leftButtonContainerParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
            leftButtonContainer.setLayoutParams(leftButtonContainerParams);
            leftButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);

            // Right Button Container layout
            LinearLayout rightButtonContainer = new LinearLayout(cordova.getActivity());
            FrameLayout.LayoutParams rightButtonContainerParams = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            rightButtonContainerParams.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
            rightButtonContainer.setLayoutParams(rightButtonContainerParams);
            rightButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);

            // Edit Text Box
            edittext = new EditText(cordova.getActivity());
            RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
            textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
            edittext.setLayoutParams(textLayoutParams);
            edittext.setSingleLine(true);
            edittext.setText(url);
            edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
            edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
            edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
            edittext.setOnKeyListener(new View.OnKeyListener() {
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    // If the event is a key-down event on the "enter" button
                    if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
                        navigate(edittext.getText().toString());
                        return true;
                    }
                    return false;
                }
            });

            // Back button
            final Button back = createButton(
                features.backButton,
                "back button",
                new View.OnClickListener() {
                    public void onClick(View v) {
                        emitButtonEvent(
                                features.backButton,
                                inAppWebView.getUrl());

                        if (features.backButtonCanClose && !canGoBack()) {
                            closeDialog();
                        } else {
                            goBack();
                        }
                    }
                }
            );

            if (back != null) {
                back.setEnabled(features.backButtonCanClose);
            }

            // Forward button
            final Button forward = createButton(
                features.forwardButton,
                "forward button",
                new View.OnClickListener() {
                    public void onClick(View v) {
                        emitButtonEvent(
                                features.forwardButton,
                                inAppWebView.getUrl());

                        goForward();
                    }
                }
            );

            if (back != null) {
                back.setEnabled(false);
            }


            // Close/Done button
            Button close = createButton(
                features.closeButton,
                "close button",
                new View.OnClickListener() {
                    public void onClick(View v) {
                        emitButtonEvent(
                                features.closeButton,
                                inAppWebView.getUrl());
                        closeDialog();
                    }
                }
            );

            // Menu button
            Spinner menu = features.menu != null
                    ? new MenuSpinner(cordova.getActivity()) : null;
            if (menu != null) {
                menu.setLayoutParams(new LinearLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                menu.setContentDescription("menu button");
                setButtonImages(menu, features.menu, DISABLED_ALPHA);

                // We are not allowed to use onClickListener for Spinner, so we will use
                // onTouchListener as a fallback.
                menu.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        if (event.getAction() == MotionEvent.ACTION_UP) {
                            emitButtonEvent(
                                    features.menu,
                                    inAppWebView.getUrl());
                        }
                        return false;
                    }
                });

                if (features.menu.items != null) {
                    HideSelectedAdapter<EventLabel> adapter
                            = new HideSelectedAdapter<EventLabel>(
                            cordova.getActivity(),
                            android.R.layout.simple_spinner_item,
                            features.menu.items);
                    adapter.setDropDownViewResource(
                            android.R.layout.simple_spinner_dropdown_item);
                    menu.setAdapter(adapter);
                    menu.setOnItemSelectedListener(
                            new AdapterView.OnItemSelectedListener() {
                                @Override
                                public void onItemSelected(
                                        AdapterView<?> adapterView,
                                        View view, int i, long l) {
                                    if (inAppWebView != null
                                            && i < features.menu.items.length) {
                                        emitButtonEvent(
                                                features.menu.items[i],
                                                inAppWebView.getUrl(), i);
                                    }
                                }

                                @Override
                                public void onNothingSelected(
                                        AdapterView<?> adapterView) {
                                }
                            }
                    );
                }
            }

            // Title
            final TextView title = features.title != null
                    ? new TextView(cordova.getActivity()) : null;
            if (title != null) {
                FrameLayout.LayoutParams titleParams
                        = new FrameLayout.LayoutParams(
                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
                titleParams.gravity = Gravity.CENTER;
                title.setLayoutParams(titleParams);
                title.setSingleLine();
                title.setEllipsize(TextUtils.TruncateAt.END);
                title.setGravity(Gravity.CENTER);
                title.setTextColor(hexStringToColor(
                        features.title.color != null
                                ? features.title.color : "#000000ff"));
                if (features.title.staticText != null) {
                    title.setText(features.title.staticText);
                }
            }
            final ProgressBar progressbar = new ProgressBar(cordova.getActivity(), null, android.R.attr.progressBarStyleHorizontal);
            FrameLayout.LayoutParams progressbarLayout = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, 6);
            //progressbarLayout.
            progressbar.setLayoutParams(progressbarLayout);
            if (features.browserProgress != null){
                Integer progressColor=Color.BLUE;
                if ( features.browserProgress.progressColor != null
                        && features.browserProgress.progressColor.length() > 0) {
                    progressColor = Color.parseColor(features.browserProgress.progressColor);
                }
                ClipDrawable progressDrawable = new ClipDrawable(new ColorDrawable(progressColor), Gravity.LEFT, ClipDrawable.HORIZONTAL);
                progressbar.setProgressDrawable(progressDrawable);
                Integer progressBgColor = Color.GRAY;
                if ( features.browserProgress.progressBgColor != null
                        && features.browserProgress.progressBgColor.length() > 0) {
                    progressBgColor = Color.parseColor(features.browserProgress.progressBgColor);
                }
                progressbar.setBackgroundColor(progressBgColor);
            }
            // WebView
            inAppWebView = new WebView(cordova.getActivity());
            final ViewGroup.LayoutParams inAppWebViewParams = features.fullscreen
                    ? new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
                    : new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0);
            if (!features.fullscreen) {
                ((LinearLayout.LayoutParams) inAppWebViewParams).weight = 1;
            }
            inAppWebView.setLayoutParams(inAppWebViewParams);
            inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView, progressbar));
            WebViewClient client = new ThemeableBrowserClient(thatWebView, new PageLoadListener() {
                @Override
                public void onPageFinished(String url, boolean canGoBack, boolean canGoForward) {
                    if (inAppWebView != null
                            && title != null && features.title != null
                            && features.title.staticText == null
                            && features.title.showPageTitle) {
                        title.setText(inAppWebView.getTitle());
                    }

                    if (back != null) {
                        back.setEnabled(canGoBack || features.backButtonCanClose);
                    }

                    if (forward != null) {
                        forward.setEnabled(canGoForward);
                    }
                }
            });
            inAppWebView.setWebViewClient(client);
            WebSettings settings = inAppWebView.getSettings();
            settings.setJavaScriptEnabled(true);
            settings.setJavaScriptCanOpenWindowsAutomatically(true);
            settings.setBuiltInZoomControls(features.zoom);
            settings.setDisplayZoomControls(false);
            settings.setAllowFileAccess(true);
            settings.setPluginState(android.webkit.WebSettings.PluginState.ON);

            //Toggle whether this is enabled or not!
            Bundle appSettings = cordova.getActivity().getIntent().getExtras();
            boolean enableDatabase = appSettings == null || appSettings.getBoolean("ThemeableBrowserStorageEnabled", true);
            if (enableDatabase) {
                String databasePath = cordova.getActivity().getApplicationContext().getDir("themeableBrowserDB", Context.MODE_PRIVATE).getPath();
                settings.setDatabasePath(databasePath);
                settings.setDatabaseEnabled(true);
            }
            settings.setDomStorageEnabled(true);

            if (features.clearcache) {
                CookieManager.getInstance().removeAllCookie();
            } else if (features.clearsessioncache) {
                CookieManager.getInstance().removeSessionCookie();
            }

            inAppWebView.loadUrl(url);
            inAppWebView.setDownloadListener(new DownloadListener() {
                public void onDownloadStart(String url, String userAgent,
                        String contentDisposition, String mimetype,
                        long contentLength) {
                  Intent i = new Intent(Intent.ACTION_VIEW);
                  i.setData(Uri.parse(url));
                  cordova.getActivity().startActivity(i);
                }
            });
            inAppWebView.setId(Integer.valueOf(6));
            inAppWebView.getSettings().setLoadWithOverviewMode(true);
            inAppWebView.getSettings().setUseWideViewPort(true);
            inAppWebView.requestFocus();
            inAppWebView.requestFocusFromTouch();

            // Add buttons to either leftButtonsContainer or
            // rightButtonsContainer according to user's alignment
            // configuration.
            int leftContainerWidth = 0;
            int rightContainerWidth = 0;

            if (features.customButtons != null) {
                for (int i = 0; i < features.customButtons.length; i++) {
                    final BrowserButton buttonProps = features.customButtons[i];
                    final int index = i;
                    Button button = createButton(
                        buttonProps,
                        String.format("custom button at %d", i),
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                if (inAppWebView != null) {
                                    emitButtonEvent(buttonProps,
                                            inAppWebView.getUrl(), index);
                                }
                            }
                        }
                    );

                    if (ALIGN_RIGHT.equals(buttonProps.align)) {
                        rightButtonContainer.addView(button);
                        rightContainerWidth
                                += button.getLayoutParams().width;
                    } else {
                        leftButtonContainer.addView(button, 0);
                        leftContainerWidth
                                += button.getLayoutParams().width;
                    }
                }
            }

            // Back and forward buttons must be added with special ordering logic such
            // that back button is always on the left of forward button if both buttons
            // are on the same side.
            if (forward != null && features.forwardButton != null
                    && !ALIGN_RIGHT.equals(features.forwardButton.align)) {
                leftButtonContainer.addView(forward, 0);
                leftContainerWidth
                        += forward.getLayoutParams().width;
            }

            if (back != null && features.backButton != null
                    && ALIGN_RIGHT.equals(features.backButton.align)) {
                rightButtonContainer.addView(back);
                rightContainerWidth
                        += back.getLayoutParams().width;
            }

            if (back != null && features.backButton != null
                    && !ALIGN_RIGHT.equals(features.backButton.align)) {
                leftButtonContainer.addView(back, 0);
                leftContainerWidth
                        += back.getLayoutParams().width;
            }

            if (forward != null && features.forwardButton != null
                    && ALIGN_RIGHT.equals(features.forwardButton.align)) {
                rightButtonContainer.addView(forward);
                rightContainerWidth
                        += forward.getLayoutParams().width;
            }

            if (menu != null) {
                if (features.menu != null
                        && ALIGN_RIGHT.equals(features.menu.align)) {
                    rightButtonContainer.addView(menu);
                    rightContainerWidth
                            += menu.getLayoutParams().width;
                } else {
                    leftButtonContainer.addView(menu, 0);
                    leftContainerWidth
                            += menu.getLayoutParams().width;
                }
            }

            if (close != null) {
                if (features.closeButton != null
                        && ALIGN_RIGHT.equals(features.closeButton.align)) {
                    rightButtonContainer.addView(close);
                    rightContainerWidth
                            += close.getLayoutParams().width;
                } else {
                    leftButtonContainer.addView(close, 0);
                    leftContainerWidth
                            += close.getLayoutParams().width;
                }
            }

            // Add the views to our toolbar
            toolbar.addView(leftButtonContainer);
            // Don't show address bar.
            // toolbar.addView(edittext);
            toolbar.addView(rightButtonContainer);

            if (title != null) {
                int titleMargin = Math.max(
                        leftContainerWidth, rightContainerWidth);

                FrameLayout.LayoutParams titleParams
                        = (FrameLayout.LayoutParams) title.getLayoutParams();
                titleParams.setMargins(titleMargin, 0, titleMargin, 0);
                toolbar.addView(title);
            }

            if (features.fullscreen) {
                // If full screen mode, we have to add inAppWebView before adding toolbar.
                main.addView(inAppWebView);
            }

            // Don't add the toolbar if its been disabled
            if (features.location) {
                // Add our toolbar to our main view/layout
                main.addView(toolbar);
                if (features.browserProgress!=null&&features.browserProgress.showProgress){
                   main.addView(progressbar);
               }
            }

            if (!features.fullscreen) {
                // If not full screen, we add inAppWebView after adding toolbar.
                main.addView(inAppWebView);
            }

            WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
            lp.copyFrom(dialog.getWindow().getAttributes());
            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
            lp.height = WindowManager.LayoutParams.MATCH_PARENT;

            dialog.setContentView(main);
            dialog.show();
            dialog.getWindow().setAttributes(lp);
            // the goal of openhidden is to load the url and not display it
            // Show() needs to be called to cause the URL to be loaded
            if(features.hidden) {
                dialog.hide();
            }
        }
    };
    this.cordova.getActivity().runOnUiThread(runnable);
    return "";
}

/**
 * Convert our DIP units to Pixels
 *
 * @return int
 */
private int dpToPixels(int dipValue) {
    int value = (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            (float) dipValue,
            cordova.getActivity().getResources().getDisplayMetrics()
    );

    return value;
}

private int hexStringToColor(String hex) {
    int result = 0;

    if (hex != null && !hex.isEmpty()) {
        if (hex.charAt(0) == '#') {
            hex = hex.substring(1);
        }

        // No alpha, that's fine, we will just attach ff.
        if (hex.length() < 8) {
            hex += "ff";
        }

        result = (int) Long.parseLong(hex, 16);

        // Almost done, but Android color code is in form of ARGB instead of
        // RGBA, so we gotta shift it a bit.
        int alpha = (result & 0xff) << 24;
        result = result >> 8 & 0xffffff | alpha;
    }

    return result;
}

/**
* This is a rather unintuitive helper method to load images. The reason why this method exists
* is because due to some service limitations, one may not be able to add images to native
* resource bundle. So this method offers a way to load image from www contents instead.
* However loading from native resource bundle is already preferred over loading from www. So
* if name is given, then it simply loads from resource bundle and the other two parameters are
* ignored. If name is not given, then altPath is assumed to be a file path _under_ www and
* altDensity is the desired density of the given image file, because without native resource
* bundle, we can't tell what density the image is supposed to be so it needs to be given
* explicitly.
*/
private Drawable getImage(String name, String altPath, double altDensity) throws IOException {
    Drawable result = null;
    Resources activityRes = cordova.getActivity().getResources();

    if (name != null) {
        int id = activityRes.getIdentifier(name, "drawable",
                cordova.getActivity().getPackageName());
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            result = activityRes.getDrawable(id);
        } else {
            result = activityRes.getDrawable(id, cordova.getActivity().getTheme());
        }
    } else if (altPath != null) {
        File file = new File("www", altPath);
        InputStream is = null;
        try {
            is = cordova.getActivity().getAssets().open(file.getPath());
            Bitmap bitmap = BitmapFactory.decodeStream(is);
            bitmap.setDensity((int) (DisplayMetrics.DENSITY_MEDIUM * altDensity));
            result = new BitmapDrawable(activityRes, bitmap);
        } finally {
            // Make sure we close this input stream to prevent resource leak.
            try {
                is.close();
            } catch (Exception e) {}
        }
    }
    return result;
}

private void setButtonImages(View view, BrowserButton buttonProps, int disabledAlpha) {
    Drawable normalDrawable = null;
    Drawable disabledDrawable = null;
    Drawable pressedDrawable = null;

    CharSequence description = view.getContentDescription();

    if (buttonProps.image != null || buttonProps.wwwImage != null) {
        try {
            normalDrawable = getImage(buttonProps.image, buttonProps.wwwImage,
                    buttonProps.wwwImageDensity);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            params.width = normalDrawable.getIntrinsicWidth();
            params.height = normalDrawable.getIntrinsicHeight();
        } catch (Resources.NotFoundException e) {
            emitError(ERR_LOADFAIL,
                    String.format("Image for %s, %s, failed to load",
                            description, buttonProps.image));
        } catch (IOException ioe) {
            emitError(ERR_LOADFAIL,
                    String.format("Image for %s, %s, failed to load",
                            description, buttonProps.wwwImage));
        }
    } else {
        emitWarning(WRN_UNDEFINED,
                String.format("Image for %s is not defined. Button will not be shown",
                        description));
    }

    if (buttonProps.imagePressed != null || buttonProps.wwwImagePressed != null) {
        try {
            pressedDrawable = getImage(buttonProps.imagePressed, buttonProps.wwwImagePressed,
                    buttonProps.wwwImageDensity);
        } catch (Resources.NotFoundException e) {
            emitError(ERR_LOADFAIL,
                    String.format("Pressed image for %s, %s, failed to load",
                            description, buttonProps.imagePressed));
        } catch (IOException e) {
            emitError(ERR_LOADFAIL,
                    String.format("Pressed image for %s, %s, failed to load",
                            description, buttonProps.wwwImagePressed));
        }
    } else {
        emitWarning(WRN_UNDEFINED,
                String.format("Pressed image for %s is not defined.",
                        description));
    }

    if (normalDrawable != null) {
        // Create the disabled state drawable by fading the normal state
        // drawable. Drawable.setAlpha() stopped working above Android 4.4
        // so we gotta bring out some bitmap magic. Credit goes to:
        // http://stackoverflow.com/a/7477572
        Bitmap enabledBitmap = ((BitmapDrawable) normalDrawable).getBitmap();
        Bitmap disabledBitmap = Bitmap.createBitmap(
                normalDrawable.getIntrinsicWidth(),
                normalDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(disabledBitmap);

        Paint paint = new Paint();
        paint.setAlpha(disabledAlpha);
        canvas.drawBitmap(enabledBitmap, 0, 0, paint);

        Resources activityRes = cordova.getActivity().getResources();
        disabledDrawable = new BitmapDrawable(activityRes, disabledBitmap);
    }

    StateListDrawable states = new StateListDrawable();
    if (pressedDrawable != null) {
        states.addState(
            new int[] {
                android.R.attr.state_pressed
            },
            pressedDrawable
        );
    }
    if (normalDrawable != null) {
        states.addState(
            new int[] {
                android.R.attr.state_enabled
            },
            normalDrawable
        );
    }
    if (disabledDrawable != null) {
        states.addState(
            new int[] {},
            disabledDrawable
        );
    }

    setBackground(view, states);
}

private void setBackground(View view, Drawable drawable) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        view.setBackgroundDrawable(drawable);
    } else {
        view.setBackground(drawable);
    }
}

private Button createButton(BrowserButton buttonProps, String description,
        View.OnClickListener listener) {
    Button result = null;
    if (buttonProps != null) {
        result = new Button(cordova.getActivity());
        result.setContentDescription(description);
        result.setLayoutParams(new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        setButtonImages(result, buttonProps, DISABLED_ALPHA);
        if (listener != null) {
            result.setOnClickListener(listener);
        }
    } else {
        emitWarning(WRN_UNDEFINED,
                String.format("%s is not defined. Button will not be shown.",
                        description));
    }
    return result;
}

/**
 * Create a new plugin success result and send it back to JavaScript
 *
 * @param obj a JSONObject contain event payload information
 */
private void sendUpdate(JSONObject obj, boolean keepCallback) {
    sendUpdate(obj, keepCallback, PluginResult.Status.OK);
}

/**
 * Create a new plugin result and send it back to JavaScript
 *
 * @param obj a JSONObject contain event payload information
 * @param status the status code to return to the JavaScript environment
 */
private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
    if (callbackContext != null) {
        PluginResult result = new PluginResult(status, obj);
        result.setKeepCallback(keepCallback);
        callbackContext.sendPluginResult(result);
        if (!keepCallback) {
            callbackContext = null;
        }
    }
}

public static interface PageLoadListener {
    public void onPageFinished(String url, boolean canGoBack,
            boolean canGoForward);
}

/**
 * The webview client receives notifications about appView
 */
public class ThemeableBrowserClient extends WebViewClient {
    PageLoadListener callback;
    CordovaWebView webView;

    /**
     * Constructor.
     *
     * @param webView
     * @param callback
     */
    public ThemeableBrowserClient(CordovaWebView webView,
            PageLoadListener callback) {
        this.webView = webView;
        this.callback = callback;
    }

    /**
     * Override the URL that should be loaded
     *
     * This handles a small subset of all the URIs that would be encountered.
     *
     * @param webView
     * @param url
     */
    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url) {
        if (url.startsWith(WebView.SCHEME_TEL)) {
            try {
                Intent intent = new Intent(Intent.ACTION_DIAL);
                intent.setData(Uri.parse(url));
                cordova.getActivity().startActivity(intent);
                return true;
            } catch (android.content.ActivityNotFoundException e) {
                Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
            }
        } else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) {
            try {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse(url));
                cordova.getActivity().startActivity(intent);
                return true;
            } catch (android.content.ActivityNotFoundException e) {
                Log.e(LOG_TAG, "Error with " + url + ": " + e.toString());
            }
        }
        // If sms:5551212?body=This is the message
        else if (url.startsWith("sms:")) {
            try {
                Intent intent = new Intent(Intent.ACTION_VIEW);

                // Get address
                String address = null;
                int parmIndex = url.indexOf('?');
                if (parmIndex == -1) {
                    address = url.substring(4);
                } else {
                    address = url.substring(4, parmIndex);

                    // If body, then set sms body
                    Uri uri = Uri.parse(url);
                    String query = uri.getQuery();
                    if (query != null) {
                        if (query.startsWith("body=")) {
                            intent.putExtra("sms_body", query.substring(5));
                        }
                    }
                }
                intent.setData(Uri.parse("sms:" + address));
                intent.putExtra("address", address);
                intent.setType("vnd.android-dir/mms-sms");
                cordova.getActivity().startActivity(intent);
                return true;
            } catch (android.content.ActivityNotFoundException e) {
                Log.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
            }
        }
        return false;
    }


    /*
     * onPageStarted fires the LOAD_START_EVENT
     *
     * @param view
     * @param url
     * @param favicon
     */
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        String newloc = "";
        if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
            newloc = url;
        }
        else
        {
            // Assume that everything is HTTP at this point, because if we don't specify,
            // it really should be.  Complain loudly about this!!!
            Log.e(LOG_TAG, "Possible Uncaught/Unknown URI");
            newloc = "https://duckduckgo.com?q=" + url;
        }

        // Update the UI if we haven't already
        if (!newloc.equals(edittext.getText().toString())) {
            edittext.setText(newloc);
        }

        try {
            JSONObject obj = new JSONObject();
            obj.put("type", LOAD_START_EVENT);
            obj.put("url", newloc);
            sendUpdate(obj, true);
        } catch (JSONException ex) {
            Log.e(LOG_TAG, "URI passed in has caused a JSON error.");
        }
    }

    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);

        try {
            JSONObject obj = new JSONObject();
            obj.put("type", LOAD_STOP_EVENT);
            obj.put("url", url);

            sendUpdate(obj, true);

            if (this.callback != null) {
                this.callback.onPageFinished(url, view.canGoBack(),
                        view.canGoForward());
            }
        } catch (JSONException ex) {
        }
    }

    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);

        try {
            JSONObject obj = new JSONObject();
            obj.put("type", LOAD_ERROR_EVENT);
            obj.put("url", failingUrl);
            obj.put("code", errorCode);
            obj.put("message", description);

            sendUpdate(obj, true, PluginResult.Status.ERROR);
        } catch (JSONException ex) {
        }
    }
}

/**
 * Like Spinner but will always trigger onItemSelected even if a selected
 * item is selected, and always ignore default selection.
 */
public class MenuSpinner extends Spinner {
    private OnItemSelectedListener listener;

    public MenuSpinner(Context context) {
        super(context);
    }

    @Override
    public void setSelection(int position) {
        super.setSelection(position);

        if (listener != null) {
            listener.onItemSelected(null, this, position, 0);
        }
    }

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
        this.listener = listener;
    }
}

/**
 * Extension of ArrayAdapter. The only difference is that it hides the
 * selected text that's shown inside spinner.
 * @param <T>
 */
private static class HideSelectedAdapter<T> extends ArrayAdapter {

    public HideSelectedAdapter(Context context, int resource, T[] objects) {
        super(context, resource, objects);
    }

    public View getView (int position, View convertView, ViewGroup parent) {
        View v = super.getView(position, convertView, parent);
        v.setVisibility(View.GONE);
        return v;
    }
}


/**
 * A class to hold parsed option properties.
 */
private static class Options {
    public boolean location = true;
    public boolean hidden = false;
    public boolean clearcache = false;
    public boolean clearsessioncache = false;
    public boolean zoom = true;
    public boolean hardwareback = true;

    public Toolbar toolbar;
    public Title title;
    public BrowserButton backButton;
    public BrowserButton forwardButton;
    public BrowserButton closeButton;
    public BrowserMenu menu;
    public BrowserButton[] customButtons;
    public boolean backButtonCanClose;
    public boolean disableAnimation;
    public boolean fullscreen;
    public BrowserProgress browserProgress;
}

private static class Event {
    public String event;
}

private static class EventLabel extends Event {
    public String label;

    public String toString() {
        return label;
    }
}

private static class BrowserButton extends Event {
    public String image;
    public String wwwImage;
    public String imagePressed;
    public String wwwImagePressed;
    public double wwwImageDensity = 1;
    public String align = ALIGN_LEFT;
}

private static class BrowserMenu extends BrowserButton {
    public EventLabel[] items;
}

private static class BrowserProgress {
    public boolean showProgress;
    public String progressBgColor;
    public String progressColor;
}

private static class Toolbar {
    public int height = TOOLBAR_DEF_HEIGHT;
    public String color;
    public String image;
    public String wwwImage;
    public double wwwImageDensity = 1;
}

private static class Title {
    public String color;
    public String staticText;
    public boolean showPageTitle;
}

private File createImageFile() throws IOException{
    @SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "img_"+timeStamp+"_";
    File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(imageFileName,".jpg",storageDir);
}

}`

lethalazo avatar Dec 29 '16 11:12 lethalazo