You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2014/07/04 05:02:48 UTC

[7/8] Merge branch 'master' into 4.0.x (Bridge fixes)

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ca23056/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/CordovaChromeClient.java
index 847a466,f2c3350..87177b4
mode 100644,100755..100644
--- a/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/framework/src/org/apache/cordova/CordovaChromeClient.java
@@@ -18,15 -18,391 +18,10 @@@
  */
  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.util.Log;
 -import android.view.Gravity;
 -import android.view.KeyEvent;
 -import android.view.View;
 -import android.view.ViewGroup.LayoutParams;
 -import android.webkit.ConsoleMessage;
 -import android.webkit.JsPromptResult;
 -import android.webkit.JsResult;
  import android.webkit.ValueCallback;
 -import android.webkit.WebChromeClient;
 -import android.webkit.WebStorage;
 -import android.webkit.WebView;
 -import android.webkit.GeolocationPermissions.Callback;
 -import android.widget.EditText;
 -import android.widget.LinearLayout;
 -import android.widget.ProgressBar;
 -import android.widget.RelativeLayout;
 -
 -/**
 - * This class is the WebChromeClient that implements callbacks for our web view.
 - * The kind of callbacks that happen here are on the chrome outside the document,
 - * such as onCreateWindow(), onConsoleMessage(), onProgressChanged(), etc. Related
 - * to but different than CordovaWebViewClient.
 - *
 - * @see <a href="http://developer.android.com/reference/android/webkit/WebChromeClient.html">WebChromeClient</a>
 - * @see <a href="http://developer.android.com/guide/webapps/webview.html">WebView guide</a>
 - * @see CordovaWebViewClient
 - * @see CordovaWebView
 - */
 -public class CordovaChromeClient extends WebChromeClient {
 -
 -    public static final int FILECHOOSER_RESULTCODE = 5173;
 -    private static final String LOG_TAG = "CordovaChromeClient";
 -    private String TAG = "CordovaLog";
 -    private long MAX_QUOTA = 100 * 1024 * 1024;
 -    protected CordovaInterface cordova;
 -    protected CordovaWebView appView;
 -
 -    // the video progress view
 -    private View mVideoProgressView;
 -    
 -    // File Chooser
 -    public ValueCallback<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
 -     * @see Other implementation in the Dialogs plugin.
 -     */
 -    @Override
 -    public boolean onJsAlert(WebView view, String url, String message, final JsResult 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.show();
 -        return true;
 -    }
 -
 -    /**
 -     * Tell the client to display a confirm dialog to the user.
 -     *
 -     * @param view
 -     * @param url
 -     * @param message
 -     * @param result
 -     * @see Other implementation in the Dialogs plugin.
 -     */
 -    @Override
 -    public boolean onJsConfirm(WebView view, String url, String message, final JsResult 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.show();
 -        return true;
 -    }
 -
 -    /**
 -     * Tell the client to display a prompt dialog to the user.
 -     * If the client returns true, WebView will assume that the client will
 -     * handle the prompt dialog and call the appropriate JsPromptResult 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!
 -     *
 -     * @see Other implementation in the Dialogs plugin.
 -     */
 -    @Override
 -    public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, JsPromptResult result) {
 -        // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.
 -        if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) {
 -            JSONArray array;
 -            try {
 -                array = new JSONArray(defaultValue.substring(4));
 -                int bridgeSecret = array.getInt(0);
 -                String service = array.getString(1);
 -                String action = array.getString(2);
 -                String callbackId = array.getString(3);
 -                String r = appView.exposedJsApi.exec(bridgeSecret, service, action, callbackId, message);
 -                result.confirm(r == null ? "" : r);
 -            } catch (JSONException e) {
 -                e.printStackTrace();
 -                result.cancel();
 -            } catch (IllegalAccessException e) {
 -                e.printStackTrace();
 -                result.cancel();
 -            }
 -        }
 -
 -        // Sets the native->JS bridge mode. 
 -        else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) {
 -            try {
 -                int bridgeSecret = Integer.parseInt(defaultValue.substring(16));
 -                appView.exposedJsApi.setNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message));
 -                result.cancel();
 -            } catch (NumberFormatException e){
 -                e.printStackTrace();
 -                result.cancel();
 -            } catch (IllegalAccessException e) {
 -                e.printStackTrace();
 -                result.cancel();
 -            }
 -        }
 -
 -        // Polling for JavaScript messages 
 -        else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) {
 -            int bridgeSecret = Integer.parseInt(defaultValue.substring(9));
 -            try {
 -                String r = appView.exposedJsApi.retrieveJsMessages(bridgeSecret, "1".equals(message));
 -                result.confirm(r == null ? "" : r);
 -            } catch (IllegalAccessException e) {
 -                e.printStackTrace();
 -                result.cancel();
 -            }
 -        }
 -
 -        else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {
 -            String startUrl = Config.getStartUrl();
 -            // Protect against random iframes being able to talk through the bridge.
 -            // Trust only file URLs and the start URL's domain.
 -            // The extra origin.startsWith("http") is to protect against iframes with data: having "" as origin.
 -            if (origin.startsWith("file:") || (origin.startsWith("http") && startUrl.startsWith(origin))) {
 -                // Enable the bridge
 -                int bridgeMode = Integer.parseInt(defaultValue.substring(9));
 -                appView.jsMessageQueue.setBridgeMode(bridgeMode);
 -                // Tell JS the bridge secret.
 -                int secret = appView.exposedJsApi.generateBridgeSecret();
 -                result.confirm(""+secret);
 -            } else {
 -                Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin);
 -                result.cancel();
 -            }
 -        } else {
 -            // Returning false would also show a dialog, but the default one shows the origin (ugly).
 -            final JsPromptResult 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.show();
 -        }
 -        return true;
 -    }
 -
 -    /**
 -     * Handle database quota exceeded notification.
 -     */
 -    @Override
 -    public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
 -            long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
 -    {
 -        LOG.d(TAG, "onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
 -        quotaUpdater.updateQuota(MAX_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(ConsoleMessage consoleMessage)
 -    {
 -        if (consoleMessage.message() != null)
 -            LOG.d(TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());
 -         return super.onConsoleMessage(consoleMessage);
 -    }
 -
 -    @Override
 -    /**
 -     * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
 -     *
 -     * @param origin
 -     * @param callback
 -     */
 -    public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
 -        super.onGeolocationPermissionsShowPrompt(origin, 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, WebChromeClient.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(ValueCallback<Uri> uploadMsg) {
 -        this.openFileChooser(uploadMsg, "*/*");
 -    }
  
 -    public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {
 -        this.openFileChooser(uploadMsg, acceptType, null);
 -    }
 -    
 -    public void openFileChooser(ValueCallback<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 ValueCallback<Uri> getValueCallback() {
 -        return this.mUploadMessage;
 -    }
 +public interface CordovaChromeClient {
- 
-     int FILECHOOSER_RESULTCODE = 0;
- 
 +    void setWebView(CordovaWebView appView);
- 
 +    ValueCallback<Uri> getValueCallback();
- 
  }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ca23056/framework/src/org/apache/cordova/CordovaUriHelper.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ca23056/framework/src/org/apache/cordova/ExposedJsApi.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/ExposedJsApi.java
index d0f8abf,97f6038..b84fcfb
mode 100644,100755..100644
--- a/framework/src/org/apache/cordova/ExposedJsApi.java
+++ b/framework/src/org/apache/cordova/ExposedJsApi.java
@@@ -1,17 -1,98 +1,12 @@@
 -/*
 -       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.webkit.JavascriptInterface;
 -
 -import org.apache.cordova.PluginManager;
  import org.json.JSONException;
  
- import android.webkit.JavascriptInterface;
- 
 -/**
 - * Contains APIs that the JS can call. All functions in here should also have
 - * an equivalent entry in CordovaChromeClient.java, and be added to
 - * cordova-js/lib/android/plugin/android/promptbasednativeapi.js
 +/*
 + * Any exposed Javascript API MUST implement these three things!
   */
- 
 -/* package */ class ExposedJsApi {
 -    
 -    private PluginManager pluginManager;
 -    private NativeToJsMessageQueue jsMessageQueue;
 -    private volatile int bridgeSecret = -1; // written by UI thread, read by JS thread.
 -    
 -    public ExposedJsApi(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) {
 -        this.pluginManager = pluginManager;
 -        this.jsMessageQueue = jsMessageQueue;
 -    }
 -
 -    @JavascriptInterface
 -    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
 -        verifySecret(bridgeSecret);
 -        // If the arguments weren't received, send a message back to JS.  It will switch bridge modes and try again.  See CB-2666.
 -        // We send a message meant specifically for this case.  It starts with "@" so no other message can be encoded into the same string.
 -        if (arguments == null) {
 -            return "@Null arguments.";
 -        }
 -
 -        jsMessageQueue.setPaused(true);
 -        try {
 -            // Tell the resourceApi what thread the JS is running on.
 -            CordovaResourceApi.jsThread = Thread.currentThread();
 -            
 -            pluginManager.exec(service, action, callbackId, arguments);
 -            String ret = "";
 -            if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {
 -                ret = jsMessageQueue.popAndEncode(false);
 -            }
 -            return ret;
 -        } catch (Throwable e) {
 -            e.printStackTrace();
 -            return "";
 -        } finally {
 -            jsMessageQueue.setPaused(false);
 -        }
 -    }
 -    
 -    @JavascriptInterface
 -    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
 -        verifySecret(bridgeSecret);
 -        jsMessageQueue.setBridgeMode(value);
 -    }
 -    
 -    @JavascriptInterface
 -    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
 -        verifySecret(bridgeSecret);
 -        return jsMessageQueue.popAndEncode(fromOnlineEvent);
 -    }
 -
 -    private void verifySecret(int value) throws IllegalAccessException {
 -        if (bridgeSecret < 0 || value != bridgeSecret) {
 -            throw new IllegalAccessException();
 -        }
 -    }
 -
 -    /** Called on page transitions */
 -    void clearBridgeSecret() {
 -        bridgeSecret = -1;
 -    }
 -
 -    /** Called by cordova.js to initialize the bridge. */
 -    int generateBridgeSecret() {
 -        bridgeSecret = (int)(Math.random() * Integer.MAX_VALUE);
 -        return bridgeSecret;
 -    }
 +public interface ExposedJsApi {
- 
-     @JavascriptInterface
-     public String exec(String service, String action, String callbackId, String arguments) throws JSONException;
-     public void setNativeToJsBridgeMode(int value);
-     public String retrieveJsMessages(boolean fromOnlineEvent);
++    public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException;
++    public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException;
++    public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException;
  }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ca23056/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index 2501c98,67793d7..3c6ad21
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@@ -32,9 -32,10 +32,10 @@@ import android.webkit.WebResourceRespon
  import android.webkit.WebView;
  
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
 -public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 +public class IceCreamCordovaWebViewClient extends AndroidWebViewClient implements CordovaWebViewClient{
  
      private static final String TAG = "IceCreamCordovaWebViewClient";
+     private CordovaUriHelper helper;
  
      public IceCreamCordovaWebViewClient(CordovaInterface cordova) {
          super(cordova);

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ca23056/framework/src/org/apache/cordova/PluginManager.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/PluginManager.java
index 50fe6b7,02536ba..c8cecf2
--- a/framework/src/org/apache/cordova/PluginManager.java
+++ b/framework/src/org/apache/cordova/PluginManager.java
@@@ -65,10 -63,6 +62,8 @@@ public class PluginManager 
      // Using <url-filter> is deprecated.
      protected HashMap<String, List<String>> urlMap = new HashMap<String, List<String>>();
  
-     private AtomicInteger numPendingUiExecs;
-     
 +    private Set<String> pluginIdWhitelist;
 +
      /**
       * Constructor.
       *
@@@ -79,12 -73,7 +74,11 @@@
          this.ctx = ctx;
          this.app = app;
          this.firstRun = true;
-         this.numPendingUiExecs = new AtomicInteger(0);
      }
 +    
 +    public void setPluginIdWhitelist(Set<String> pluginIdWhitelist) {
 +        this.pluginIdWhitelist = pluginIdWhitelist;
 +    }
  
      /**
       * Init when loading a new HTML page into webview.