Merge "Make JavascriptInterface annotation public." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 1326307..9c127b7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26943,6 +26943,9 @@
     method public boolean useHttpAuthUsernamePassword();
   }
 
+  public abstract class JavascriptInterface implements java.lang.annotation.Annotation {
+  }
+
   public class JsPromptResult extends android.webkit.JsResult {
     method public void confirm(java.lang.String);
   }
diff --git a/core/java/android/webkit/JavascriptInterface.java b/core/java/android/webkit/JavascriptInterface.java
index 3f1ed12..6cd2a7b 100644
--- a/core/java/android/webkit/JavascriptInterface.java
+++ b/core/java/android/webkit/JavascriptInterface.java
@@ -25,9 +25,8 @@
  * Annotation that allows exposing methods to JavaScript. Starting from API level
  * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} and above, only methods explicitly
  * marked with this annotation are available to the Javascript code. See
- * {@link android.webkit.Webview#addJavaScriptInterface} for more information about it.
+ * {@link android.webkit.WebView#addJavascriptInterface} for more information about it.
  *
- * @hide
  */
 @SuppressWarnings("javadoc")
 @Retention(RetentionPolicy.RUNTIME)
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 35993f6..05b86a3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -26,7 +26,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.http.SslCertificate;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.Message;
@@ -1494,10 +1493,20 @@
     /**
      * Injects the supplied Java object into this WebView. The object is
      * injected into the JavaScript context of the main frame, using the
-     * supplied name. This allows the Java object's public methods to be
-     * accessed from JavaScript. Note that that injected objects will not
+     * supplied name. This allows the Java object's methods to be
+     * accessed from JavaScript. For API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
+     * and above, only public methods that are annotated with
+     * {@link android.webkit.JavascriptInterface} can be accessed from JavaScript.
+     * For API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or below,
+     * all public methods (including the inherited ones) can be accessed, see the
+     * important security note below for implications. Note that injected objects will not
      * appear in JavaScript until the page is next (re)loaded. For example:
-     * <pre> webView.addJavascriptInterface(new Object(), "injectedObject");
+     * <pre>
+     * class JsObject {
+     *    {@literal @}JavascriptInterface
+     *    public String toString() { return "injectedObject"; }
+     * }
+     * webView.addJavascriptInterface(new JsObject(), "injectedObject");
      * webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
      * webView.loadUrl("javascript:alert(injectedObject.toString())");</pre>
      * <p>
@@ -1505,7 +1514,9 @@
      * <ul>
      * <li> This method can be used to allow JavaScript to control the host
      * application. This is a powerful feature, but also presents a security
-     * risk, particularly as JavaScript could use reflection to access an
+     * risk for applications targeting API level
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or below, because
+     * JavaScript could use reflection to access an
      * injected object's public fields. Use of this method in a WebView
      * containing untrusted content could allow an attacker to manipulate the
      * host application in unintended ways, executing Java code with the
@@ -1514,6 +1525,7 @@
      * <li> JavaScript interacts with Java object on a private, background
      * thread of this WebView. Care is therefore required to maintain thread
      * safety.</li>
+     * <li> The Java object's fields are not accessible.</li>
      * </ul>
      *
      * @param object the Java object to inject into this WebView's JavaScript
@@ -1523,9 +1535,6 @@
     public void addJavascriptInterface(Object object, String name) {
         checkThread();
         mProvider.addJavascriptInterface(object, name);
-        // TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above. Don't forget to
-        // update the doc, set a link to annotation and unhide the annotation.
-        // also describe that fields of java objects are not accessible from JS.
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index a2c1575..d23f52c 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -55,6 +55,7 @@
 import android.net.Uri;
 import android.net.http.SslCertificate;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -4119,10 +4120,17 @@
             return;
         }
         WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
-        // TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above.
+
         arg.mObject = object;
         arg.mInterfaceName = name;
-        arg.mRequireAnnotation = false;
+
+        // starting with JELLY_BEAN_MR1, annotations are mandatory for enabling access to
+        // methods that are accessible from JS.
+        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            arg.mRequireAnnotation = true;
+        } else {
+            arg.mRequireAnnotation = false;
+        }
         mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
     }