Merge change 6813 into donut

* changes:
  Fixes #1972421. Prevents crash in ScrollView/HorizontalScrollView.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 263f927..7615614 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1112,11 +1112,17 @@
 
     /**
      * Broadcast Action: Sent after the screen turns off.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
     /**
      * Broadcast Action: Sent after the screen turns on.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
@@ -1124,6 +1130,9 @@
     /**
      * Broadcast Action: Sent when the user is present after device wakes up (e.g when the
      * keyguard is gone).
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_USER_PRESENT= "android.intent.action.USER_PRESENT";
@@ -1134,6 +1143,9 @@
      * in manifests, only by exlicitly registering for it with
      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
      * Context.registerReceiver()}.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
@@ -1152,6 +1164,9 @@
      * <ul>
      *   <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time zone.</li>
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
@@ -1177,6 +1192,9 @@
      * such as installing alarms.  You must hold the
      * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
      * in order to receive this broadcast.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
@@ -1184,12 +1202,18 @@
      * Broadcast Action: This is broadcast when a user action should request a
      * temporary system dialog to dismiss.  Some examples of temporary system
      * dialogs are the notification window-shade and the recent tasks dialog.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
     /**
      * Broadcast Action: Trigger the download and eventual installation
      * of a package.
      * <p>Input: {@link #getData} is the URI of the package file to download.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
@@ -1203,6 +1227,9 @@
      * <li> {@link #EXTRA_REPLACING} is set to true if this is following
      * an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package.
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
@@ -1214,6 +1241,9 @@
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
@@ -1229,6 +1259,9 @@
      * <li> {@link #EXTRA_REPLACING} is set to true if this will be followed
      * by an {@link #ACTION_PACKAGE_ADDED} broadcast for the same package.
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
@@ -1238,6 +1271,9 @@
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
@@ -1251,6 +1287,9 @@
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
@@ -1263,12 +1302,18 @@
      * <ul>
      * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
     /**
      * Broadcast Action: A user ID has been removed from the system.  The user
      * ID number is stored in the extra data under {@link #EXTRA_UID}.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
@@ -1287,6 +1332,9 @@
      * application to make sure it sees the new changes.  Some system code that
      * can not be restarted will need to watch for this action and handle it
      * appropriately.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      *
      * @see android.content.res.Configuration
      */
@@ -1298,15 +1346,21 @@
      *
      * <p class="note">
      * You can <em>not</em> receive this through components declared
-     * in manifests, only by exlicitly registering for it with
+     * in manifests, only by explicitly registering for it with
      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
      * Context.registerReceiver()}.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
     /**
      * Broadcast Action:  Indicates low battery condition on the device.
      * This broadcast corresponds to the "Low battery warning" system dialog.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
@@ -1314,6 +1368,9 @@
      * Broadcast Action:  Indicates the battery is now okay after being low.
      * This will be sent after {@link #ACTION_BATTERY_LOW} once the battery has
      * gone back up to an okay state.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -1323,6 +1380,9 @@
      * Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
      * stay active to receive this notification.  This action can be used to implement actions
      * that wait until power is available to trigger.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
@@ -1332,6 +1392,9 @@
      * Unlike ACTION_BATTERY_CHANGED, applications will be woken for this and so do not have to
      * stay active to receive this notification.  This action can be used to implement actions
      * that wait until power is available to trigger.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
@@ -1341,16 +1404,25 @@
      * off, not sleeping).  Once the broadcast is complete, the final shutdown
      * will proceed and all unsaved data lost.  Apps will not normally need
      * to handle this, since the forground activity will be paused as well.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     /**
      * Broadcast Action:  Indicates low memory condition on the device
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
     /**
      * Broadcast Action:  Indicates low memory condition on the device no longer exists
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";
@@ -1515,6 +1587,9 @@
      *   then cell radio and possibly other radios such as bluetooth or WiFi may have also been
      *   turned off</li>
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
@@ -1593,6 +1668,9 @@
      * <p>You must hold the
      * {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS}
      * permission to receive this Intent.</p>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_NEW_OUTGOING_CALL =
@@ -1601,6 +1679,9 @@
     /**
      * Broadcast Action: Have the device reboot.  This is only for use by
      * system code.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_REBOOT =
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bf2a895..e587ca7 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -71,6 +71,8 @@
     
     void removePermission(String name);
     
+    boolean isProtectedBroadcast(String actionName);
+    
     int checkSignatures(String pkg1, String pkg2);
     
     String[] getPackagesForUid(int uid);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0e2deed..cebb696 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -720,7 +720,7 @@
                 sa.recycle();
 
                 if (name != null && !pkg.requestedPermissions.contains(name)) {
-                    pkg.requestedPermissions.add(name);
+                    pkg.requestedPermissions.add(name.intern());
                 }
 
                 XmlUtils.skipCurrentTag(parser);
@@ -851,21 +851,6 @@
 
                 XmlUtils.skipCurrentTag(parser);
 
-            } else if (tagName.equals("instrumentation")) {
-                if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
-                    return null;
-                }
-            } else if (tagName.equals("eat-comment")) {
-                // Just skip this tag
-                XmlUtils.skipCurrentTag(parser);
-                continue;
-            } else if (RIGID_PARSER) {
-                outError[0] = "Bad element under <manifest>: "
-                    + parser.getName();
-                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-                return null;
-
-
             } else if (tagName.equals("supports-density")) {
                 sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestSupportsDensity);
@@ -900,6 +885,43 @@
                 sa.recycle();
                 
                 XmlUtils.skipCurrentTag(parser);
+                
+            } else if (tagName.equals("protected-broadcast")) {
+                sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
+
+                String name = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
+
+                sa.recycle();
+
+                if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
+                    if (pkg.protectedBroadcasts == null) {
+                        pkg.protectedBroadcasts = new ArrayList<String>();
+                    }
+                    if (!pkg.protectedBroadcasts.contains(name)) {
+                        pkg.protectedBroadcasts.add(name.intern());
+                    }
+                }
+
+                XmlUtils.skipCurrentTag(parser);
+                
+            } else if (tagName.equals("instrumentation")) {
+                if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
+                    return null;
+                }
+                
+            } else if (tagName.equals("eat-comment")) {
+                // Just skip this tag
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+                
+            } else if (RIGID_PARSER) {
+                outError[0] = "Bad element under <manifest>: "
+                    + parser.getName();
+                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                return null;
+
             } else {
                 Log.w(TAG, "Bad element under <manifest>: "
                       + parser.getName());
@@ -1429,7 +1451,7 @@
                 sa.recycle();
 
                 if (lname != null && !owner.usesLibraries.contains(lname)) {
-                    owner.usesLibraries.add(lname);
+                    owner.usesLibraries.add(lname.intern());
                 }
 
                 XmlUtils.skipCurrentTag(parser);
@@ -2210,8 +2232,8 @@
             return null;
         }
 
-        boolean success = true;
-
+        name = name.intern();
+        
         TypedValue v = sa.peekValue(
                 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
         if (v != null && v.resourceId != 0) {
@@ -2224,7 +2246,7 @@
             if (v != null) {
                 if (v.type == TypedValue.TYPE_STRING) {
                     CharSequence cs = v.coerceToString();
-                    data.putString(name, cs != null ? cs.toString() : null);
+                    data.putString(name, cs != null ? cs.toString().intern() : null);
                 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
                     data.putBoolean(name, v.data != 0);
                 } else if (v.type >= TypedValue.TYPE_FIRST_INT
@@ -2405,6 +2427,8 @@
 
         public final ArrayList<String> requestedPermissions = new ArrayList<String>();
 
+        public ArrayList<String> protectedBroadcasts;
+        
         public final ArrayList<String> usesLibraries = new ArrayList<String>();
         public String[] usesLibraryFiles = null;
 
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index c23df21..6a755c3 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -105,6 +105,18 @@
     private static final String LOG = Uri.class.getSimpleName();
 
     /**
+     * NOTE: EMPTY accesses this field during its own initialization, so this
+     * field *must* be initialized first, or else EMPTY will see a null value!
+     *
+     * Placeholder for strings which haven't been cached. This enables us
+     * to cache null. We intentionally create a new String instance so we can
+     * compare its identity and there is no chance we will confuse it with
+     * user data.
+     */
+    @SuppressWarnings("RedundantStringConstructorCall")
+    private static final String NOT_CACHED = new String("NOT CACHED");
+
+    /**
      * The empty URI, equivalent to "".
      */
     public static final Uri EMPTY = new HierarchicalUri(null, Part.NULL,
@@ -350,15 +362,6 @@
     private final static int NOT_CALCULATED = -2;
 
     /**
-     * Placeholder for strings which haven't been cached. This enables us
-     * to cache null. We intentionally create a new String instance so we can
-     * compare its identity and there is no chance we will confuse it with
-     * user data.
-     */
-    @SuppressWarnings("RedundantStringConstructorCall")
-    private static final String NOT_CACHED = new String("NOT CACHED");
-
-    /**
      * Error message presented when a user tries to treat an opaque URI as
      * hierarchical.
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 51e6c1e..4805193 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -68,6 +68,12 @@
     public static final int PHONE_UID = 1001;
 
     /**
+     * Defines the UID/GID for the user shell.
+     * @hide
+     */
+    public static final int SHELL_UID = 2000;
+
+    /**
      * Defines the UID/GID for the WIFI supplicant process.
      * @hide
      */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 4078fa6..0cfa506 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1620,6 +1620,9 @@
          *
          * It is recommended to display <em>plmn</em> before / above <em>spn</em> if
          * both are displayed.
+         * 
+         * <p>Note this is a protected intent that can only be sent
+         * by the system.
          */
         public static final String SPN_STRINGS_UPDATED_ACTION =
                 "android.provider.Telephony.SPN_STRINGS_UPDATED";
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index e09eb04..38b7b79 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.media.AudioManager;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -109,6 +110,9 @@
         public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
         public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
 
+        // default values for rendering
+        public static final int TTS_DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
+
         // return codes for a TTS engine's check data activity
         public static final int CHECK_VOICE_DATA_PASS = 1;
         public static final int CHECK_VOICE_DATA_FAIL = 0;
@@ -126,10 +130,15 @@
         public static final String TTS_KEY_PARAM_LANGUAGE = "language";
         public static final String TTS_KEY_PARAM_COUNTRY = "country";
         public static final String TTS_KEY_PARAM_VARIANT = "variant";
-        public static final int TTS_PARAM_POSITION_RATE = 0;
-        public static final int TTS_PARAM_POSITION_LANGUAGE = 2;
-        public static final int TTS_PARAM_POSITION_COUNTRY = 4;
-        public static final int TTS_PARAM_POSITION_VARIANT = 6;
+        public static final String TTS_KEY_PARAM_STREAM = "streamType";
+        public static final String TTS_KEY_PARAM_UTTERANCE_ID = "utteranceId";
+        protected static final int TTS_PARAM_POSITION_RATE = 0;
+        protected static final int TTS_PARAM_POSITION_LANGUAGE = 2;
+        protected static final int TTS_PARAM_POSITION_COUNTRY = 4;
+        protected static final int TTS_PARAM_POSITION_VARIANT = 6;
+        protected static final int TTS_PARAM_POSITION_STREAM = 8;
+        protected static final int TTS_PARAM_POSITION_UTTERANCE_ID = 10;
+        protected static final int TTS_NB_CACHED_PARAMS = 6;
     }
 
     /**
@@ -163,11 +172,12 @@
         mPackageName = mContext.getPackageName();
         mInitListener = listener;
 
-        mCachedParams = new String[2*4]; // 4 parameters, store key and value
+        mCachedParams = new String[2*Engine.TTS_NB_CACHED_PARAMS]; // store key and value
         mCachedParams[Engine.TTS_PARAM_POSITION_RATE] = Engine.TTS_KEY_PARAM_RATE;
         mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE] = Engine.TTS_KEY_PARAM_LANGUAGE;
         mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY] = Engine.TTS_KEY_PARAM_COUNTRY;
         mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT] = Engine.TTS_KEY_PARAM_VARIANT;
+        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM] = Engine.TTS_KEY_PARAM_STREAM;
 
         mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] =
                 String.valueOf(Engine.FALLBACK_TTS_DEFAULT_RATE);
@@ -177,6 +187,10 @@
         mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country();
         mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant();
 
+        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] =
+                String.valueOf(Engine.TTS_DEFAULT_STREAM);
+        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID+ 1] = "";
+
         initTts();
     }
 
@@ -347,7 +361,14 @@
                 return result;
             }
             try {
-                // TODO support extra parameters, passing cache of current parameters for the moment
+                String extra = params.get(Engine.TTS_KEY_PARAM_STREAM);
+                if (extra != null) {
+                    mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = extra;
+                }
+                extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                if (extra != null) {
+                    mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID] = extra;
+                }
                 result = mITts.speak(mPackageName, text, queueMode, mCachedParams);
             } catch (RemoteException e) {
                 // TTS died; restart it.
@@ -362,7 +383,8 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                resetCachedParams();
+                return result;
             }
         }
     }
@@ -388,7 +410,16 @@
                 return result;
             }
             try {
-                // TODO support extra parameters, passing null for the moment
+                if ((params != null) && (!params.isEmpty())) {
+                    String extra = params.get(Engine.TTS_KEY_PARAM_STREAM);
+                    if (extra != null) {
+                        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = extra;
+                    }
+                    extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                    if (extra != null) {
+                        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID] = extra;
+                    }
+                }
                 result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
             } catch (RemoteException e) {
                 // TTS died; restart it.
@@ -403,7 +434,8 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                resetCachedParams();
+                return result;
             }
         }
     }
@@ -426,7 +458,6 @@
                 return result;
             }
             try {
-                // TODO support extra parameters, passing cache of current parameters for the moment
                 result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams);
             } catch (RemoteException e) {
                 // TTS died; restart it.
@@ -696,8 +727,12 @@
                 return result;
             }
             try {
-                // TODO support extra parameters, passing null for the moment
-                if (mITts.synthesizeToFile(mPackageName, text, null, filename)){
+                // no need to read the stream type here
+                String extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                if (extra != null) {
+                    mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID] = extra;
+                }
+                if (mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename)){
                     result = TTS_SUCCESS;
                 }
             } catch (RemoteException e) {
@@ -713,9 +748,21 @@
                 mStarted = false;
                 initTts();
             } finally {
-              return result;
+                resetCachedParams();
+                return result;
             }
         }
     }
 
+
+    /**
+     * Convenience method to reset the cached parameters to the current default values
+     * if they are not persistent between calls to the service.
+     */
+    private void resetCachedParams() {
+        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] =
+                String.valueOf(Engine.TTS_DEFAULT_STREAM);
+        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID+ 1] = "";
+    }
+
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 23967f4..e964cda 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -21,6 +21,39 @@
     package="android" android:sharedUserId="android.uid.system"
     android:sharedUserLabel="@string/android_system_label">
 
+    <!-- ================================================ -->
+    <!-- Special broadcasts that only the system can send -->
+    <!-- ================================================ -->
+    <eat-comment />
+    
+    <protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
+    <protected-broadcast android:name="android.intent.action.SCREEN_ON" />
+    <protected-broadcast android:name="android.intent.action.USER_PRESENT" />
+    <protected-broadcast android:name="android.intent.action.TIME_TICK" />
+    <protected-broadcast android:name="android.intent.action.TIMEZONE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
+    <protected-broadcast android:name="android.intent.action.CLOSE_SYSTEM_DIALOGS" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+    <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
+    <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
+    <protected-broadcast android:name="android.intent.action.BATTERY_OKAY" />
+    <protected-broadcast android:name="android.intent.action.ACTION_POWER_CONNECTED" />
+    <protected-broadcast android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
+    <protected-broadcast android:name="android.intent.action.ACTION_SHUTDOWN" />
+    <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_LOW" />
+    <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" />
+    <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
+    <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
+    <protected-broadcast android:name="android.intent.action.REBOOT" />
+    
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 12a76ba..9dc483c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -887,11 +887,12 @@
         <attr name="largeScreens" format="boolean" />
     </declare-styleable>
 
-    <!-- The <code>expandable</code> specifies if this package supports screen metrics
-         other than 320x480 dip.
-         <p>This appears as a child tag of the
+    <!-- Private tag to declare system protected broadcast actions.
+
+         <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
-    <declare-styleable name="AndroidManifestExpandable" parent="AndroidManifest">
+    <declare-styleable name="AndroidManifestProtectedBroadcast" parent="AndroidManifest">
+        <attr name="name" />
     </declare-styleable>
 
     <!-- The <code>provider</code> tag declares a
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index fdc4caf..ea22410 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -319,14 +319,14 @@
      * @param text
      *            The text that should be spoken
      * @param queueMode
-     *            0 for no queue (interrupts all previous utterances), 1 for
-     *            queued
+     *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
+     *            TextToSpeech.TTS_QUEUE_ADD for queued
      * @param params
      *            An ArrayList of parameters. This is not implemented for all
      *            engines.
      */
     private int speak(String callingApp, String text, int queueMode, ArrayList<String> params) {
-        if (queueMode == 0) {
+        if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
             stop(callingApp);
         }
         mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT));
@@ -342,15 +342,15 @@
      * @param earcon
      *            The earcon that should be played
      * @param queueMode
-     *            0 for no queue (interrupts all previous utterances), 1 for
-     *            queued
+     *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
+     *            TextToSpeech.TTS_QUEUE_ADD for queued
      * @param params
      *            An ArrayList of parameters. This is not implemented for all
      *            engines.
      */
     private int playEarcon(String callingApp, String earcon, int queueMode,
             ArrayList<String> params) {
-        if (queueMode == 0) {
+        if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
             stop(callingApp);
         }
         mSpeechQueue.add(new SpeechItem(callingApp, earcon, params, SpeechItem.EARCON));
@@ -408,7 +408,7 @@
 
     private int playSilence(String callingApp, long duration, int queueMode,
             ArrayList<String> params) {
-        if (queueMode == 0) {
+        if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
             stop(callingApp);
         }
         mSpeechQueue.add(new SpeechItem(callingApp, duration));
@@ -759,8 +759,8 @@
          * @param text
          *            The text that should be spoken
          * @param queueMode
-         *            0 for no queue (interrupts all previous utterances), 1 for
-         *            queued
+         *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
+         *            TextToSpeech.TTS_QUEUE_ADD for queued
          * @param params
          *            An ArrayList of parameters. The first element of this
          *            array controls the type of voice to use.
@@ -779,8 +779,8 @@
          * @param earcon
          *            The earcon that should be played
          * @param queueMode
-         *            0 for no queue (interrupts all previous utterances), 1 for
-         *            queued
+         *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
+         *            TextToSpeech.TTS_QUEUE_ADD for queued
          * @param params
          *            An ArrayList of parameters.
          */
@@ -798,8 +798,8 @@
          * @param duration
          *            The duration of the silence that should be played
          * @param queueMode
-         *            0 for no queue (interrupts all previous utterances), 1 for
-         *            queued
+         *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
+         *            TextToSpeech.TTS_QUEUE_ADD for queued
          * @param params
          *            An ArrayList of parameters.
          */
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 06435c8..0d190ca 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -56,8 +56,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -251,6 +249,9 @@
     final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
             new HashMap<String, PackageParser.PermissionGroup>();
 
+    // Broadcast actions that are only available to the system.
+    final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
+    
     boolean mSystemReady;
     boolean mSafeMode;
     boolean mHasSystemUidErrors;
@@ -1128,6 +1129,12 @@
         }
     }
 
+    public boolean isProtectedBroadcast(String actionName) {
+        synchronized (mPackages) {
+            return mProtectedBroadcasts.contains(actionName);
+        }
+    }
+    
     public int checkSignatures(String pkg1, String pkg2) {
         synchronized (mPackages) {
             PackageParser.Package p1 = mPackages.get(pkg1);
@@ -2500,6 +2507,13 @@
                 if (Config.LOGD) Log.d(TAG, "  Instrumentation: " + r);
             }
     
+            if (pkg.protectedBroadcasts != null) {
+                N = pkg.protectedBroadcasts.size();
+                for (i=0; i<N; i++) {
+                    mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
+                }
+            }
+            
             pkgSetting.setTimeStamp(scanFileTime);
         }
         
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index aad542a..134ab80 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -10832,6 +10832,29 @@
             mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
         }
 
+        /*
+         * Prevent non-system code (defined here to be non-persistent
+         * processes) from sending protected broadcasts.
+         */
+        if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
+                || callingUid == Process.SHELL_UID || callingUid == 0) {
+            // Always okay.
+        } else if (callerApp == null || !callerApp.persistent) {
+            try {
+                if (ActivityThread.getPackageManager().isProtectedBroadcast(
+                        intent.getAction())) {
+                    String msg = "Permission Denial: not allowed to send broadcast "
+                            + intent.getAction() + " from pid="
+                            + callingPid + ", uid=" + callingUid;
+                    Log.w(TAG, msg);
+                    throw new SecurityException(msg);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Remote exception", e);
+                return BROADCAST_SUCCESS;
+            }
+        }
+        
         // Add to the sticky list if requested.
         if (sticky) {
             if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 9152211..02e9800 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -32,6 +32,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_SERVICE_STATE_CHANGED = "android.intent.action.SERVICE_STATE";
 
@@ -50,6 +53,9 @@
      *
      * <p class="note">
      * Requires no permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_RADIO_TECHNOLOGY_CHANGED
             = "android.intent.action.RADIO_TECHNOLOGY";
@@ -66,6 +72,9 @@
      *
      * <p class="note">
      * Requires no permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
             = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
@@ -89,6 +98,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_SIGNAL_STRENGTH_CHANGED = "android.intent.action.SIG_STR";
 
@@ -110,6 +122,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_ANY_DATA_CONNECTION_STATE_CHANGED
             = "android.intent.action.ANY_DATA_STATE";
@@ -127,6 +142,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_DATA_CONNECTION_FAILED
             = "android.intent.action.DATA_CONNECTION_FAILED";
@@ -148,6 +166,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_SIM_STATE_CHANGED
             = "android.intent.action.SIM_STATE_CHANGED";
@@ -163,6 +184,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME";
 
@@ -178,6 +202,9 @@
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_NETWORK_SET_TIMEZONE
             = "android.intent.action.NETWORK_SET_TIMEZONE";
@@ -187,6 +214,9 @@
      * <p class="note">.
      * This is to pop up a notice to show user that the phone is in emergency callback mode
      * and atacalls and outgoing sms are blocked.
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      */
     public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
             = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
@@ -197,6 +227,9 @@
      * <ul>
      *   <li><em>mdn</em> - An Integer of the updated MDN number.</li>
      * </ul>
+     * 
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
      *
      * <p class="note">
      */
diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh
index 0cdf63f..7ada698 100755
--- a/tests/AndroidTests/run_test.sh
+++ b/tests/AndroidTests/run_test.sh
@@ -1,4 +1,4 @@
 framework=/system/framework
 bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
-adb shell exec dalvikvm  -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk \
+adb shell exec dalvikvm  -Xbootclasspath:$bpath -cp /system/app/AndroidTests.apk:/data/app/com.android.unit_tests.apk \
       com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
index 130beeb..e9d3cda 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
@@ -499,4 +499,8 @@
 
         assertEquals(uriString, uri.toString());
     }
+
+    public void testEmptyToStringNotNull() {
+        assertNotNull(Uri.EMPTY.toString());
+    }
 }