Fixes #1963229. Introduces Context#isRestricted().

A restricted Context is a special type of Context that prevents specific features
from being used. For instance, android:onClick, used by View, can be dangerous when
used from within apps widgets. By using a restricted Context to inflate apps widgets,
widgets providers are prevented from using android:onClick.
diff --git a/api/current.xml b/api/current.xml
index d028faa..9bce1f3 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27810,6 +27810,17 @@
 <parameter name="modeFlags" type="int">
 </parameter>
 </method>
+<method name="isRestricted"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="obtainStyledAttributes"
  return="android.content.res.TypedArray"
  abstract="false"
@@ -28323,6 +28334,17 @@
  visibility="public"
 >
 </field>
+<field name="CONTEXT_RESTRICTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INPUT_METHOD_SERVICE"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 00b0593..61cd0fe 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -184,6 +184,7 @@
     private StatusBarManager mStatusBarManager = null;
     private TelephonyManager mTelephonyManager = null;
     private ClipboardManager mClipboardManager = null;
+    private boolean mRestricted;
 
     private final Object mSync = new Object();
 
@@ -1336,6 +1337,7 @@
             mMainThread.getPackageInfo(packageName, flags);
         if (pi != null) {
             ApplicationContext c = new ApplicationContext();
+            c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
             c.init(pi, null, mMainThread);
             if (c.mResources != null) {
                 return c;
@@ -1347,6 +1349,11 @@
             "Application package " + packageName + " not found");
     }
 
+    @Override
+    public boolean isRestricted() {
+        return mRestricted;
+    }
+
     private File getDataDirFile() {
         if (mPackageInfo != null) {
             return mPackageInfo.getDataDirFile();
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 307c4c8..62d9267 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -269,7 +269,7 @@
         try {
             if (mInfo != null) {
                 Context theirContext = mContext.createPackageContext(
-                        mInfo.provider.getPackageName(), 0 /* no flags */);
+                        mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED);
                 LayoutInflater inflater = (LayoutInflater)
                         theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                 inflater = inflater.cloneInContext(theirContext);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b0396f6..9e37ae4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1654,6 +1654,13 @@
      * with extreme care!
      */
     public static final int CONTEXT_IGNORE_SECURITY = 0x00000002;
+    
+    /**
+     * Flag for use with {@link #createPackageContext}: a restricted context may
+     * disable specific features. For instance, a View associated with a restricted
+     * context would ignore particular XML attributes.
+     */
+    public static final int CONTEXT_RESTRICTED = 0x00000004;
 
     /**
      * Return a new Context object for the given application name.  This
@@ -1682,4 +1689,15 @@
      */
     public abstract Context createPackageContext(String packageName,
             int flags) throws PackageManager.NameNotFoundException;
+
+    /**
+     * Indicates whether this Context is restricted.
+     * 
+     * @return True if this Context is restricted, false otherwise.
+     * 
+     * @see #CONTEXT_RESTRICTED
+     */
+    public boolean isRestricted() {
+        return false;
+    }
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 7513b3b..45a082a 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -430,4 +430,9 @@
         throws PackageManager.NameNotFoundException {
         return mBase.createPackageContext(packageName, flags);
     }
+
+    @Override
+    public boolean isRestricted() {
+        return mBase.isRestricted();
+    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b3180ca..ff8868b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1996,6 +1996,11 @@
                     mMinHeight = a.getDimensionPixelSize(attr, 0);
                     break;
                 case R.styleable.View_onClick:
+                    if (context.isRestricted()) {
+                        throw new IllegalStateException("The android:onClick attribute cannot " 
+                                + "be used within a restricted context");
+                    }
+
                     final String handlerName = a.getString(attr);
                     if (handlerName != null) {
                         setOnClickListener(new OnClickListener() {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1b5c5bc..2dac652 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -856,7 +856,7 @@
 
         if (packageName != null) {
             try {
-                c = context.createPackageContext(packageName, 0);
+                c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
             } catch (NameNotFoundException e) {
                 Log.e(LOG_TAG, "Package name " + packageName + " not found");
                 c = context;
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index efc4880..b83a44d6 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -397,4 +397,9 @@
             throws PackageManager.NameNotFoundException {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public boolean isRestricted() {
+        throw new UnsupportedOperationException();        
+    }
 }