Merge "Change TrafficStats to a new JNI implementation." into froyo
diff --git a/Android.mk b/Android.mk
index cecc26a..10b6d67 100644
--- a/Android.mk
+++ b/Android.mk
@@ -117,6 +117,7 @@
 	core/java/android/hardware/ISensorService.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
+        core/java/android/net/IThrottleManager.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/storage/IMountService.aidl \
 	core/java/android/os/storage/IMountServiceListener.aidl \
diff --git a/api/current.xml b/api/current.xml
index e231528..58b9c17 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -34,17 +34,6 @@
  visibility="public"
 >
 </constructor>
-<field name="ACCESS_CACHE_FILESYSTEM"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.permission.ACCESS_CACHE_FILESYSTEM&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ACCESS_CHECKIN_PROPERTIES"
  type="java.lang.String"
  transient="false"
@@ -716,17 +705,6 @@
  visibility="public"
 >
 </field>
-<field name="MOVE_PACKAGE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.permission.MOVE_PACKAGE&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="PERSISTENT_ACTIVITY"
  type="java.lang.String"
  transient="false"
@@ -71656,7 +71634,7 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="setZoomCallback"
+<method name="setZoomChangeListener"
  return="void"
  abstract="false"
  native="false"
@@ -71666,7 +71644,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="cb" type="android.hardware.Camera.ZoomCallback">
+<parameter name="listener" type="android.hardware.Camera.OnZoomChangeListener">
 </parameter>
 </method>
 <method name="startPreview"
@@ -71831,6 +71809,31 @@
 </parameter>
 </method>
 </interface>
+<interface name="Camera.OnZoomChangeListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onZoomChange"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="zoomValue" type="int">
+</parameter>
+<parameter name="stopped" type="boolean">
+</parameter>
+<parameter name="camera" type="android.hardware.Camera">
+</parameter>
+</method>
+</interface>
 <class name="Camera.Parameters"
  extends="java.lang.Object"
  abstract="false"
@@ -73255,31 +73258,6 @@
 >
 </field>
 </class>
-<interface name="Camera.ZoomCallback"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="onZoomUpdate"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="zoomValue" type="int">
-</parameter>
-<parameter name="stopped" type="boolean">
-</parameter>
-<parameter name="camera" type="android.hardware.Camera">
-</parameter>
-</method>
-</interface>
 <class name="GeomagneticField"
  extends="java.lang.Object"
  abstract="false"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 659d70f..9b8b0ac 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -16,6 +16,8 @@
 
 package com.android.commands.pm;
 
+import com.android.internal.content.PackageHelper;
+
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.FeatureInfo;
@@ -33,6 +35,7 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.provider.Settings;
 
 import java.io.File;
 import java.lang.reflect.Field;
@@ -107,6 +110,16 @@
             return;
         }
 
+        if ("setInstallLocation".equals(op)) {
+            runSetInstallLocation();
+            return;
+        }
+
+        if ("getInstallLocation".equals(op)) {
+            runGetInstallLocation();
+            return;
+        }
+
         try {
             if (args.length == 1) {
                 if (args[0].equalsIgnoreCase("-l")) {
@@ -575,6 +588,51 @@
         return Integer.toString(result);
     }
 
+    private void runSetInstallLocation() {
+        int loc;
+
+        String arg = nextArg();
+        if (arg == null) {
+            System.err.println("Error: no install location specified.");
+            showUsage();
+            return;
+        }
+        try {
+            loc = Integer.parseInt(arg);
+        } catch (NumberFormatException e) {
+            System.err.println("Error: install location has to be a number.");
+            showUsage();
+            return;
+        }
+        try {
+            if (!mPm.setInstallLocation(loc)) {
+                System.err.println("Error: install location has to be a number.");
+                showUsage();
+            }
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(PM_NOT_RUNNING_ERR);
+        }
+    }
+
+    private void runGetInstallLocation() {
+        try {
+            int loc = mPm.getInstallLocation();
+            String locStr = "invalid";
+            if (loc == PackageHelper.APP_INSTALL_AUTO) {
+                locStr = "auto";
+            } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) {
+                locStr = "internal";
+            } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+                locStr = "external";
+            }
+            System.out.println(loc + "[" + locStr + "]");
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(PM_NOT_RUNNING_ERR);
+        }
+    }
+
     private void runInstall() {
         int installFlags = 0;
         String installerPackageName = null;
@@ -832,6 +890,7 @@
         System.err.println("       pm uninstall [-k] PACKAGE");
         System.err.println("       pm enable PACKAGE_OR_COMPONENT");
         System.err.println("       pm disable PACKAGE_OR_COMPONENT");
+        System.err.println("       pm setInstallLocation [0/auto] [1/internal] [2/external]");
         System.err.println("");
         System.err.println("The list packages command prints all packages.  Options:");
         System.err.println("  -f: see their associated file.");
@@ -867,10 +926,17 @@
         System.err.println("  -k: keep the data and cache directories around.");
         System.err.println("after the package removal.");
         System.err.println("");
-        System.err.println("The mountsd command simulates mounting/unmounting sdcard.Options:");
-        System.err.println("  -m: true or false.");
-        System.err.println("");
         System.err.println("The enable and disable commands change the enabled state of");
         System.err.println("a given package or component (written as \"package/class\").");
+        System.err.println("");
+        System.err.println("The getInstallLocation command gets the current install location");
+        System.err.println("  0 [auto]: Let system decide the best location");
+        System.err.println("  1 [internal]: Install on internal device storage");
+        System.err.println("  2 [external]: Install on external media");
+        System.err.println("");
+        System.err.println("The setInstallLocation command changes the default install location");
+        System.err.println("  0 [auto]: Let system decide the best location");
+        System.err.println("  1 [internal]: Install on internal device storage");
+        System.err.println("  2 [external]: Install on external media");
     }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b07b690..950f34f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1482,8 +1482,9 @@
         mPackageInfo = packageInfo;
         mResources = mPackageInfo.getResources(mainThread);
 
-        if (container != null && container.getCompatibilityInfo().applicationScale !=
-            mResources.getCompatibilityInfo().applicationScale) {
+        if (mResources != null && container != null
+                && container.getCompatibilityInfo().applicationScale !=
+                        mResources.getCompatibilityInfo().applicationScale) {
             if (DEBUG) {
                 Log.d(TAG, "loaded context has different scaling. Using container's" +
                         " compatiblity info:" + container.getDisplayMetrics());
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 1cb2353..d114ecc 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1307,7 +1307,7 @@
         String blockingPackage = ActivityThread.currentPackageName();
 
         EventLog.writeEvent(
-            EventLogTags.CONTENT_QUERY_OPERATION,
+            EventLogTags.CONTENT_QUERY_SAMPLE,
             uri.toString(),
             projectionBuffer.toString(),
             selection != null ? selection : "",
@@ -1329,7 +1329,7 @@
         }
         String blockingPackage = ActivityThread.currentPackageName();
         EventLog.writeEvent(
-            EventLogTags.CONTENT_UPDATE_OPERATION,
+            EventLogTags.CONTENT_UPDATE_SAMPLE,
             uri.toString(),
             operation,
             selection != null ? selection : "",
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3a2aa55..30822d4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1398,7 +1398,7 @@
      * @see android.os.Vibrator
      */
     public static final String VIBRATOR_SERVICE = "vibrator";
-    
+
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.app.StatusBarManager} for interacting with the status bar.
@@ -1421,6 +1421,17 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
+     * android.net.ThrottleManager} for handling management of
+     * throttling.
+     *
+     * @hide
+     * @see #getSystemService
+     * @see android.net.ThrottleManager
+     */
+    public static final String THROTTLE_SERVICE = "throttle";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.NetworkManagementService} for handling management of
      * system network services
      *
diff --git a/core/java/android/content/EventLogTags.logtags b/core/java/android/content/EventLogTags.logtags
index 0a8c9b0..21ea90a 100644
--- a/core/java/android/content/EventLogTags.logtags
+++ b/core/java/android/content/EventLogTags.logtags
@@ -2,6 +2,6 @@
 
 option java_package android.content;
 
-52002 content_query_operation (uri|3),(projection|3),(selection|3),(sortorder|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
-52003 content_update_operation (uri|3),(operation|3),(selection|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
-52004 binder_operation (descriptor|3),(method_num|1|5),(time|1|3),(blocking_package|3),(sample_percent|1|6)
+52002 content_query_sample (uri|3),(projection|3),(selection|3),(sortorder|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
+52003 content_update_sample (uri|3),(operation|3),(selection|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
+52004 binder_sample (descriptor|3),(method_num|1|5),(time|1|3),(blocking_package|3),(sample_percent|1|6)
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index f90ef63..9939478 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -316,4 +316,7 @@
     void movePackage(String packageName, IPackageMoveObserver observer, int flags);
     
     boolean addPermissionAsync(in PermissionInfo info);
+
+    boolean setInstallLocation(int loc);
+    int getInstallLocation();
 }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index abebdeb9..2495619 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -78,7 +78,7 @@
     private PreviewCallback mPreviewCallback;
     private PictureCallback mPostviewCallback;
     private AutoFocusCallback mAutoFocusCallback;
-    private ZoomCallback mZoomCallback;
+    private OnZoomChangeListener mZoomListener;
     private ErrorCallback mErrorCallback;
     private boolean mOneShot;
     private boolean mWithBuffer;
@@ -96,7 +96,7 @@
         mJpegCallback = null;
         mPreviewCallback = null;
         mPostviewCallback = null;
-        mZoomCallback = null;
+        mZoomListener = null;
 
         Looper looper;
         if ((looper = Looper.myLooper()) != null) {
@@ -270,16 +270,18 @@
     }
 
     /**
-     * Adds a pre-allocated buffer to the callback buffer queue. Applications
-     * can add one or more buffers to the queue. When a preview frame arrives
-     * and there is still available buffer, buffer will be filled and it is
-     * removed from the queue. Then preview callback is invoked with the buffer.
-     * If a frame arrives and there is no buffer left, the frame is discarded.
-     * Applications should add the buffers back when they finish the processing.
+     * Adds a pre-allocated buffer to the preview callback buffer queue.
+     * Applications can add one or more buffers to the queue. When a preview
+     * frame arrives and there is still available buffer, buffer will be filled
+     * and it is removed from the queue. Then preview callback is invoked with
+     * the buffer. If a frame arrives and there is no buffer left, the frame is
+     * discarded. Applications should add the buffers back when they finish the
+     * processing.
      *
-     * Preview width and height can be determined from getPreviewSize, and bitsPerPixel can be
-     * found from {@link android.hardware.Camera.Parameters#getPreviewFormat()}
-     * and {@link android.graphics.ImageFormat#getBitsPerPixel(int)}.
+     * The image format of the callback buffer can be read from {@link
+     * android.hardware.Camera.Parameters#getPreviewFormat()}. bitsPerPixel can
+     * be read from {@link android.graphics.ImageFormat#getBitsPerPixel(int)}.
+     * Preview width and height can be determined from getPreviewSize.
      *
      * Alternatively, a buffer from a previous callback may be passed in or used
      * to determine the size of new preview frame buffers.
@@ -350,8 +352,8 @@
                 return;
 
             case CAMERA_MSG_ZOOM:
-                if (mZoomCallback != null) {
-                    mZoomCallback.onZoomUpdate(msg.arg1, msg.arg2 != 0, mCamera);
+                if (mZoomListener != null) {
+                    mZoomListener.onZoomChange(msg.arg1, msg.arg2 != 0, mCamera);
                 }
                 return;
 
@@ -526,15 +528,15 @@
     }
 
     /**
-     * Zooms to the requested value smoothly. Driver will generate {@link
-     * ZoomCallback} for the zoom value and whether zoom is stopped at the
-     * time. For example, suppose the current zoom is 0 and startSmoothZoom is
-     * called with value 3. Three ZoomCallback will be generated with zoom value
-     * 1, 2, and 3. The applications can call {@link #stopSmoothZoom} to stop
-     * the zoom earlier. The applications should not call startSmoothZoom again
-     * or change the zoom value before zoom stops. If the passing zoom value
-     * equals to the current zoom value, no zoom callback will be generated.
-     * This method is supported if {@link
+     * Zooms to the requested value smoothly. Driver will notify {@link
+     * OnZoomChangeListener} of the zoom value and whether zoom is stopped at
+     * the time. For example, suppose the current zoom is 0 and startSmoothZoom
+     * is called with value 3. Method onZoomChange will be called three times
+     * with zoom value 1, 2, and 3. The applications can call {@link
+     * #stopSmoothZoom} to stop the zoom earlier. The applications should not
+     * call startSmoothZoom again or change the zoom value before zoom stops. If
+     * the passing zoom value equals to the current zoom value, no zoom callback
+     * will be generated. This method is supported if {@link
      * android.hardware.Camera.Parameters#isSmoothZoomSupported} is true.
      *
      * @param value zoom value. The valid range is 0 to {@link
@@ -546,8 +548,8 @@
 
     /**
      * Stops the smooth zoom. The applications should wait for the {@link
-     * ZoomCallback} to know when the zoom is actually stopped. This method is
-     * supported if {@link
+     * OnZoomChangeListener} to know when the zoom is actually stopped. This
+     * method is supported if {@link
      * android.hardware.Camera.Parameters#isSmoothZoomSupported} is true.
      *
      * @throws RuntimeException if the method fails.
@@ -570,35 +572,34 @@
     public native final void setDisplayOrientation(int degrees);
 
     /**
-     * Handles the zoom callback.
-     *
+     * Interface for a callback to be invoked when zoom value changes.
      */
-    public interface ZoomCallback
+    public interface OnZoomChangeListener
     {
         /**
-         * Callback for zoom updates
+         * Called when the zoom value has changed.
          *
          * @param zoomValue the current zoom value. In smooth zoom mode, camera
-         *                  generates this callback for every new zoom value.
+         *                  calls this for every new zoom value.
          * @param stopped whether smooth zoom is stopped. If the value is true,
          *                this is the last zoom update for the application.
          *
          * @param camera  the Camera service object
          * @see #startSmoothZoom(int)
          */
-        void onZoomUpdate(int zoomValue, boolean stopped, Camera camera);
+        void onZoomChange(int zoomValue, boolean stopped, Camera camera);
     };
 
     /**
-     * Registers a callback to be invoked when the zoom value is updated by the
+     * Registers a listener to be notified when the zoom value is updated by the
      * camera driver during smooth zoom.
      *
-     * @param cb the callback to run
+     * @param listener the listener to notify
      * @see #startSmoothZoom(int)
      */
-    public final void setZoomCallback(ZoomCallback cb)
+    public final void setZoomChangeListener(OnZoomChangeListener listener)
     {
-        mZoomCallback = cb;
+        mZoomListener = listener;
     }
 
     // These match the enum in include/ui/Camera.h
@@ -992,7 +993,7 @@
         /**
          * Gets the supported preview sizes.
          *
-         * @return a List of Size object. This method will always return a list
+         * @return a list of Size object. This method will always return a list
          *         with at least one element.
          */
         public List<Size> getSupportedPreviewSizes() {
@@ -1027,7 +1028,7 @@
         /**
          * Gets the supported jpeg thumbnail sizes.
          *
-         * @return a List of Size object. This method will always return a list
+         * @return a list of Size object. This method will always return a list
          *         with at least two elements. Size 0,0 (no thumbnail) is always
          *         supported.
          */
@@ -1098,8 +1099,8 @@
         /**
          * Gets the supported preview frame rates.
          *
-         * @return a List of Integer objects (preview frame rates). null if
-         *         preview frame rate setting is not supported.
+         * @return a list of supported preview frame rates. null if preview
+         *         frame rate setting is not supported.
          */
         public List<Integer> getSupportedPreviewFrameRates() {
             String str = get(KEY_PREVIEW_FRAME_RATE + SUPPORTED_VALUES_SUFFIX);
@@ -1130,11 +1131,11 @@
         }
 
         /**
-         * Returns the image format for preview pictures got from
+         * Returns the image format for preview frames got from
          * {@link PreviewCallback}.
          *
-         * @return the {@link android.graphics.ImageFormat} int representing
-         *         the preview picture format.
+         * @return the preview format.
+         * @see android.graphics.ImageFormat
          */
         public int getPreviewFormat() {
             return pixelFormatForCameraFormat(get(KEY_PREVIEW_FORMAT));
@@ -1143,8 +1144,9 @@
         /**
          * Gets the supported preview formats.
          *
-         * @return a List of Integer objects. This method will always return a
-         *         list with at least one element.
+         * @return a list of supported preview formats. This method will always
+         *         return a list with at least one element.
+         * @see android.graphics.ImageFormat
          */
         public List<Integer> getSupportedPreviewFormats() {
             String str = get(KEY_PREVIEW_FORMAT + SUPPORTED_VALUES_SUFFIX);
@@ -1182,8 +1184,8 @@
         /**
          * Gets the supported picture sizes.
          *
-         * @return a List of Size objects. This method will always return a list
-         *         with at least one element.
+         * @return a list of supported picture sizes. This method will always
+         *         return a list with at least one element.
          */
         public List<Size> getSupportedPictureSizes() {
             String str = get(KEY_PICTURE_SIZE + SUPPORTED_VALUES_SUFFIX);
@@ -1212,7 +1214,8 @@
         /**
          * Returns the image format for pictures.
          *
-         * @return the ImageFormat int representing the picture format
+         * @return the picture format
+         * @see android.graphics.ImageFormat
          */
         public int getPictureFormat() {
             return pixelFormatForCameraFormat(get(KEY_PICTURE_FORMAT));
@@ -1221,8 +1224,9 @@
         /**
          * Gets the supported picture formats.
          *
-         * @return a List of Integer objects (values are ImageFormat.XXX). This
-         *         method will always return a list with at least one element.
+         * @return supported picture formats. This method will always return a
+         *         list with at least one element.
+         * @see android.graphics.ImageFormat
          */
         public List<Integer> getSupportedPictureFormats() {
             String str = get(KEY_PICTURE_FORMAT + SUPPORTED_VALUES_SUFFIX);
@@ -1361,8 +1365,17 @@
         /**
          * Gets the current white balance setting.
          *
-         * @return one of WHITE_BALANCE_XXX string constant. null if white
-         *         balance setting is not supported.
+         * @return current white balance. null if white balance setting is not
+         *         supported.
+         * @see #WHITE_BALANCE_AUTO
+         * @see #WHITE_BALANCE_INCANDESCENT
+         * @see #WHITE_BALANCE_FLUORESCENT
+         * @see #WHITE_BALANCE_WARM_FLUORESCENT
+         * @see #WHITE_BALANCE_DAYLIGHT
+         * @see #WHITE_BALANCE_CLOUDY_DAYLIGHT
+         * @see #WHITE_BALANCE_TWILIGHT
+         * @see #WHITE_BALANCE_SHADE
+         *
          */
         public String getWhiteBalance() {
             return get(KEY_WHITE_BALANCE);
@@ -1371,7 +1384,8 @@
         /**
          * Sets the white balance.
          *
-         * @param value WHITE_BALANCE_XXX string constant.
+         * @param value new white balance.
+         * @see #getWhiteBalance()
          */
         public void setWhiteBalance(String value) {
             set(KEY_WHITE_BALANCE, value);
@@ -1380,8 +1394,9 @@
         /**
          * Gets the supported white balance.
          *
-         * @return a List of WHITE_BALANCE_XXX string constants. null if white
-         *         balance setting is not supported.
+         * @return a list of supported white balance. null if white balance
+         *         setting is not supported.
+         * @see #getWhiteBalance()
          */
         public List<String> getSupportedWhiteBalance() {
             String str = get(KEY_WHITE_BALANCE + SUPPORTED_VALUES_SUFFIX);
@@ -1391,8 +1406,17 @@
         /**
          * Gets the current color effect setting.
          *
-         * @return one of EFFECT_XXX string constant. null if color effect
+         * @return current color effect. null if color effect
          *         setting is not supported.
+         * @see #EFFECT_NONE
+         * @see #EFFECT_MONO
+         * @see #EFFECT_NEGATIVE
+         * @see #EFFECT_SOLARIZE
+         * @see #EFFECT_SEPIA
+         * @see #EFFECT_POSTERIZE
+         * @see #EFFECT_WHITEBOARD
+         * @see #EFFECT_BLACKBOARD
+         * @see #EFFECT_AQUA
          */
         public String getColorEffect() {
             return get(KEY_EFFECT);
@@ -1401,7 +1425,8 @@
         /**
          * Sets the current color effect setting.
          *
-         * @param value EFFECT_XXX string constants.
+         * @param value new color effect.
+         * @see #getColorEffect()
          */
         public void setColorEffect(String value) {
             set(KEY_EFFECT, value);
@@ -1410,8 +1435,9 @@
         /**
          * Gets the supported color effects.
          *
-         * @return a List of EFFECT_XXX string constants. null if color effect
+         * @return a list of supported color effects. null if color effect
          *         setting is not supported.
+         * @see #getColorEffect()
          */
         public List<String> getSupportedColorEffects() {
             String str = get(KEY_EFFECT + SUPPORTED_VALUES_SUFFIX);
@@ -1422,8 +1448,12 @@
         /**
          * Gets the current antibanding setting.
          *
-         * @return one of ANTIBANDING_XXX string constant. null if antibanding
-         *         setting is not supported.
+         * @return current antibanding. null if antibanding setting is not
+         *         supported.
+         * @see #ANTIBANDING_AUTO
+         * @see #ANTIBANDING_50HZ
+         * @see #ANTIBANDING_60HZ
+         * @see #ANTIBANDING_OFF
          */
         public String getAntibanding() {
             return get(KEY_ANTIBANDING);
@@ -1432,7 +1462,8 @@
         /**
          * Sets the antibanding.
          *
-         * @param antibanding ANTIBANDING_XXX string constant.
+         * @param antibanding new antibanding value.
+         * @see #getAntibanding()
          */
         public void setAntibanding(String antibanding) {
             set(KEY_ANTIBANDING, antibanding);
@@ -1441,8 +1472,9 @@
         /**
          * Gets the supported antibanding values.
          *
-         * @return a List of ANTIBANDING_XXX string constants. null if
-         *         antibanding setting is not supported.
+         * @return a list of supported antibanding values. null if antibanding
+         *         setting is not supported.
+         * @see #getAntibanding()
          */
         public List<String> getSupportedAntibanding() {
             String str = get(KEY_ANTIBANDING + SUPPORTED_VALUES_SUFFIX);
@@ -1454,6 +1486,21 @@
          *
          * @return one of SCENE_MODE_XXX string constant. null if scene mode
          *         setting is not supported.
+         * @see #SCENE_MODE_AUTO
+         * @see #SCENE_MODE_ACTION
+         * @see #SCENE_MODE_PORTRAIT
+         * @see #SCENE_MODE_LANDSCAPE
+         * @see #SCENE_MODE_NIGHT
+         * @see #SCENE_MODE_NIGHT_PORTRAIT
+         * @see #SCENE_MODE_THEATRE
+         * @see #SCENE_MODE_BEACH
+         * @see #SCENE_MODE_SNOW
+         * @see #SCENE_MODE_SUNSET
+         * @see #SCENE_MODE_STEADYPHOTO
+         * @see #SCENE_MODE_FIREWORKS
+         * @see #SCENE_MODE_SPORTS
+         * @see #SCENE_MODE_PARTY
+         * @see #SCENE_MODE_CANDLELIGHT
          */
         public String getSceneMode() {
             return get(KEY_SCENE_MODE);
@@ -1466,7 +1513,8 @@
          * applications should call getParameters to know if some parameters are
          * changed.
          *
-         * @param value SCENE_MODE_XXX string constants.
+         * @param value scene mode.
+         * @see #getSceneMode()
          */
         public void setSceneMode(String value) {
             set(KEY_SCENE_MODE, value);
@@ -1475,8 +1523,9 @@
         /**
          * Gets the supported scene modes.
          *
-         * @return a List of SCENE_MODE_XXX string constant. null if scene mode
-         *         setting is not supported.
+         * @return a list of supported scene modes. null if scene mode setting
+         *         is not supported.
+         * @see #getSceneMode()
          */
         public List<String> getSupportedSceneModes() {
             String str = get(KEY_SCENE_MODE + SUPPORTED_VALUES_SUFFIX);
@@ -1486,8 +1535,13 @@
         /**
          * Gets the current flash mode setting.
          *
-         * @return one of FLASH_MODE_XXX string constant. null if flash mode
-         *         setting is not supported.
+         * @return current flash mode. null if flash mode setting is not
+         *         supported.
+         * @see #FLASH_MODE_OFF
+         * @see #FLASH_MODE_AUTO
+         * @see #FLASH_MODE_ON
+         * @see #FLASH_MODE_RED_EYE
+         * @see #FLASH_MODE_TORCH
          */
         public String getFlashMode() {
             return get(KEY_FLASH_MODE);
@@ -1496,7 +1550,8 @@
         /**
          * Sets the flash mode.
          *
-         * @param value FLASH_MODE_XXX string constants.
+         * @param value flash mode.
+         * @see #getFlashMode()
          */
         public void setFlashMode(String value) {
             set(KEY_FLASH_MODE, value);
@@ -1505,8 +1560,9 @@
         /**
          * Gets the supported flash modes.
          *
-         * @return a List of FLASH_MODE_XXX string constants. null if flash mode
-         *         setting is not supported.
+         * @return a list of supported flash modes. null if flash mode setting
+         *         is not supported.
+         * @see #getFlashMode()
          */
         public List<String> getSupportedFlashModes() {
             String str = get(KEY_FLASH_MODE + SUPPORTED_VALUES_SUFFIX);
@@ -1516,11 +1572,15 @@
         /**
          * Gets the current focus mode setting.
          *
-         * @return one of FOCUS_MODE_XXX string constant. If the camera does not
-         *         support auto-focus, this should return {@link
-         *         #FOCUS_MODE_FIXED}. If the focus mode is not FOCUS_MODE_FIXED
-         *         or {@link #FOCUS_MODE_INFINITY}, applications should call
-         *         {@link #autoFocus(AutoFocusCallback)} to start the focus.
+         * @return current focus mode. If the camera does not support
+         *         auto-focus, this should return {@link #FOCUS_MODE_FIXED}. If
+         *         the focus mode is not FOCUS_MODE_FIXED or {@link
+         *         #FOCUS_MODE_INFINITY}, applications should call {@link
+         *         #autoFocus(AutoFocusCallback)} to start the focus.
+         * @see #FOCUS_MODE_AUTO
+         * @see #FOCUS_MODE_INFINITY
+         * @see #FOCUS_MODE_MACRO
+         * @see #FOCUS_MODE_FIXED
          */
         public String getFocusMode() {
             return get(KEY_FOCUS_MODE);
@@ -1529,7 +1589,8 @@
         /**
          * Sets the focus mode.
          *
-         * @param value FOCUS_MODE_XXX string constants.
+         * @param value focus mode.
+         * @see #getFocusMode()
          */
         public void setFocusMode(String value) {
             set(KEY_FOCUS_MODE, value);
@@ -1538,8 +1599,9 @@
         /**
          * Gets the supported focus modes.
          *
-         * @return a List of FOCUS_MODE_XXX string constants. This method will
-         *         always return a list with at least one element.
+         * @return a list of supported focus modes. This method will always
+         *         return a list with at least one element.
+         * @see #getFocusMode()
          */
         public List<String> getSupportedFocusModes() {
             String str = get(KEY_FOCUS_MODE + SUPPORTED_VALUES_SUFFIX);
diff --git a/core/java/android/net/IThrottleManager.aidl b/core/java/android/net/IThrottleManager.aidl
new file mode 100644
index 0000000..298de6e
--- /dev/null
+++ b/core/java/android/net/IThrottleManager.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed 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 android.net;
+
+import android.os.IBinder;
+
+/**
+ * Interface that answers queries about data transfer amounts and throttling
+ */
+/** {@hide} */
+interface IThrottleManager
+{
+    long getByteCount(String iface, int dir, int period, int ago);
+
+    int getThrottle(String iface);
+
+    long getResetTime(String iface);
+
+    long getPeriodStartTime(String iface);
+
+    long getCliffThreshold(String iface, int cliff);
+
+    int getCliffLevel(String iface, int cliff);
+}
diff --git a/core/java/android/net/ThrottleManager.java b/core/java/android/net/ThrottleManager.java
new file mode 100644
index 0000000..0500f6f
--- /dev/null
+++ b/core/java/android/net/ThrottleManager.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed 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 android.net;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.os.Binder;
+import android.os.RemoteException;
+
+/**
+ * Class that handles throttling.  It provides read/write numbers per interface
+ * and methods to apply throttled rates.
+ * {@hide}
+ */
+public class ThrottleManager
+{
+    /**
+     * Broadcast each polling period to indicate new data counts.
+     *
+     * Includes four extras:
+     * EXTRA_CYCLE_READ - a long of the read bytecount for the current cycle
+     * EXTRA_CYCLE_WRITE -a long of the write bytecount for the current cycle
+     * EXTRA_CYLCE_START -a long of MS for the cycle start time
+     * EXTRA_CYCLE_END   -a long of MS for the cycle stop time
+     * {@hide}
+     */
+    public static final String THROTTLE_POLL_ACTION = "android.net.thrott.POLL_ACTION";
+    /**
+     * The lookup key for a long for the read bytecount for this period.  Retrieve with
+     * {@link android.content.Intent#getLongExtra(String)}.
+     * {@hide}
+     */
+    public static final String EXTRA_CYCLE_READ = "cycleRead";
+    /**
+     * contains a long of the number of bytes written in the cycle
+     * {@hide}
+     */
+    public static final String EXTRA_CYCLE_WRITE = "cycleWrite";
+    /**
+     * contains a long of the number of bytes read in the cycle
+     * {@hide}
+     */
+    public static final String EXTRA_CYCLE_START = "cycleStart";
+    /**
+     * contains a long of the ms since 1970 used to init a calendar, etc for the end
+     * of the cycle
+     * {@hide}
+     */
+    public static final String EXTRA_CYCLE_END = "cycleEnd";
+
+    /**
+     * Broadcast when the thottle level changes.
+     * {@hide}
+     */
+    public static final String THROTTLE_ACTION = "android.net.thrott.THROTTLE_ACTION";
+    /**
+     * int of the current bandwidth in TODO
+     * {@hide}
+     */
+    public static final String EXTRA_THROTTLE_LEVEL = "level";
+
+    // {@hide}
+    public static final int DIRECTION_TX = 0;
+    // {@hide}
+    public static final int DIRECTION_RX = 1;
+
+    // {@hide}
+    public static final int PERIOD_CYCLE  = 0;
+    // {@hide}
+    public static final int PERIOD_YEAR   = 1;
+    // {@hide}
+    public static final int PERIOD_MONTH  = 2;
+    // {@hide}
+    public static final int PERIOD_WEEK   = 3;
+    // @hide
+    public static final int PERIOD_7DAY   = 4;
+    // @hide
+    public static final int PERIOD_DAY    = 5;
+    // @hide
+    public static final int PERIOD_24HOUR = 6;
+    // @hide
+    public static final int PERIOD_HOUR   = 7;
+    // @hide
+    public static final int PERIOD_60MIN  = 8;
+    // @hide
+    public static final int PERIOD_MINUTE = 9;
+    // @hide
+    public static final int PERIOD_60SEC  = 10;
+    // @hide
+    public static final int PERIOD_SECOND = 11;
+
+    /**
+     * returns a long of the ms from the epoch to the time the current cycle ends for the
+     * named interface
+     * {@hide}
+     */
+    public long getResetTime(String iface) {
+        try {
+            return mService.getResetTime(iface);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * returns a long of the ms from the epoch to the time the current cycle started for the
+     * named interface
+     * {@hide}
+     */
+    public long getPeriodStartTime(String iface) {
+        try {
+            return mService.getPeriodStartTime(iface);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * returns a long of the byte count either read or written on the named interface
+     * for the period described.  Direction is either DIRECTION_RX or DIRECTION_TX and
+     * period may only be PERIOD_CYCLE for the current cycle (other periods may be supported
+     * in the future).  Ago indicates the number of periods in the past to lookup - 0 means
+     * the current period, 1 is the last one, 2 was two periods ago..
+     * {@hide}
+     */
+    public long getByteCount(String iface, int direction, int period, int ago) {
+        try {
+            return mService.getByteCount(iface, direction, period, ago);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * returns the number of bytes read+written after which a particular cliff
+     * takes effect on the named iface.  Currently only cliff #0 is supported (1 step)
+     * {@hide}
+     */
+    public long getCliffThreshold(String iface, int cliff) {
+        try {
+            return mService.getCliffThreshold(iface, cliff);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * returns the thottling bandwidth (bps) for a given cliff # on the named iface.
+     * only cliff #0 is currently supported.
+     * {@hide}
+     */
+    public int getCliffLevel(String iface, int cliff) {
+        try {
+            return mService.getCliffLevel(iface, cliff);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    private IThrottleManager mService;
+
+    /**
+     * Don't allow use of default constructor.
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    private ThrottleManager() {
+    }
+
+    /**
+     * {@hide}
+     */
+    public ThrottleManager(IThrottleManager service) {
+        if (service == null) {
+            throw new IllegalArgumentException(
+                "ThrottleManager() cannot be constructed with null service");
+        }
+        mService = service;
+    }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f7e7d39..812391c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -166,9 +166,11 @@
      * Standard directory in which to place files that have been downloaded by
      * the user.  Note that this is primarily a convention for the top-level
      * public directory, you are free to download files anywhere in your own
-     * private directories.
+     * private directories.  Also note that though the constant here is
+     * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
+     * backwards compatibility reasons.
      */
-    public static String DIRECTORY_DOWNLOADS = "Downloads";
+    public static String DIRECTORY_DOWNLOADS = "Download";
     
     /**
      * The traditional location for pictures and videos when mounting the
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b8e5747..eb14815 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1611,21 +1611,6 @@
         public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
 
         /**
-         * Let user pick default install location.
-         * @hide
-         */
-        public static final String SET_INSTALL_LOCATION = "set_install_location";
-
-        /**
-         * Default install location value.
-         * 0 = auto, let system decide
-         * 1 = internal
-         * 2 = sdcard
-         * @hide
-         */
-        public static final String DEFAULT_INSTALL_LOCATION = "default_install_location";
-
-        /**
          * Show pointer location on screen?
          * 0 = no
          * 1 = yes
@@ -3295,7 +3280,58 @@
          * @hide
          */
         public static final String UI_NIGHT_MODE = "ui_night_mode";
-        
+
+        /**
+         * Let user pick default install location.
+         * @hide
+         */
+        public static final String SET_INSTALL_LOCATION = "set_install_location";
+
+        /**
+         * Default install location value.
+         * 0 = auto, let system decide
+         * 1 = internal
+         * 2 = sdcard
+         * @hide
+         */
+        public static final String DEFAULT_INSTALL_LOCATION = "default_install_location";
+
+        /**
+         * The bandwidth throttle polling freqency in seconds
+         * @hide
+         */
+        public static final String THROTTLE_POLLING_SEC = "throttle_polling_sec";
+
+        /**
+         * The bandwidth throttle threshold (long)
+         * @hide
+         */
+        public static final String THROTTLE_THRESHOLD = "throttle_threshold";
+
+        /**
+         * The bandwidth throttle value (kbps)
+         * @hide
+         */
+        public static final String THROTTLE_VALUE = "throttle_value";
+
+        /**
+         * The bandwidth throttle reset calendar day (1-28)
+         * @hide
+         */
+        public static final String THROTTLE_RESET_DAY = "throttle_reset_day";
+
+        /**
+         * The throttling notifications we should send
+         * @hide
+         */
+        public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type";
+
+        /**
+         * The interface we throttle
+         * @hide
+         */
+        public static final String THROTTLE_IFACE = "throttle_iface";
+
         /**
          * @hide
          */
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 096ad39..08cd2f0 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -313,6 +313,8 @@
                                                 "Need BLUETOOTH_ADMIN permission");
         if (DBG) log("connectSink(" + device + ")");
 
+        if (!mBluetoothService.isEnabled()) return false;
+
         // ignore if there are any active sinks
         if (lookupSinksMatchingStates(new int[] {
                 BluetoothA2dp.STATE_CONNECTING,
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 42e1539..eee8025 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -129,9 +129,10 @@
                     // is invoked.
                     mTimer.cancel();
                     mTimer = null;
-                    mCurrentProxy.playbackEnded();
+                    if (mVideoView.isPlaying()) {
+                        mVideoView.stopPlayback();
+                    }
                     mCurrentProxy = null;
-                    mVideoView.stopPlayback();
                     mLayout.removeView(mVideoView);
                     mVideoView = null;
                     if (mProgressView != null) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5cfbe73..4233af1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4882,6 +4882,9 @@
                                 // we will not rewrite drag code here, but we
                                 // will try fling if it applies.
                                 WebViewCore.reducePriority();
+                                // to get better performance, pause updating the
+                                // picture
+                                WebViewCore.pauseUpdatePicture(mWebViewCore);
                                 // fall through to TOUCH_DRAG_MODE
                             } else {
                                 break;
@@ -4916,8 +4919,14 @@
                             doFling();
                             break;
                         }
+                        // fall through
+                    case TOUCH_DRAG_START_MODE:
+                        // TOUCH_DRAG_START_MODE should not happen for the real
+                        // device as we almost certain will get a MOVE. But this
+                        // is possible on emulator.
                         mLastVelocity = 0;
                         WebViewCore.resumePriority();
+                        WebViewCore.resumeUpdatePicture(mWebViewCore);
                         break;
                 }
                 stopTouch();
@@ -4963,6 +4972,8 @@
 
     private void startDrag() {
         WebViewCore.reducePriority();
+        // to get better performance, pause updating the picture
+        WebViewCore.pauseUpdatePicture(mWebViewCore);
         if (!mDragFromTextInput) {
             nativeHideCursor();
         }
@@ -5026,6 +5037,7 @@
         }
         if (mTouchMode == TOUCH_DRAG_MODE) {
             WebViewCore.resumePriority();
+            WebViewCore.resumeUpdatePicture(mWebViewCore);
         }
         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
         mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
@@ -5360,6 +5372,7 @@
         }
         if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) {
             WebViewCore.resumePriority();
+            WebViewCore.resumeUpdatePicture(mWebViewCore);
             return;
         }
         float currentVelocity = mScroller.getCurrVelocity();
@@ -6153,7 +6166,7 @@
                 case UPDATE_ZOOM_RANGE: {
                     WebViewCore.RestoreState restoreState
                             = (WebViewCore.RestoreState) msg.obj;
-                    // mScrollX contains the new contentWidth
+                    // mScrollX contains the new minPrefWidth
                     updateZoomRange(restoreState, getViewWidth(),
                             restoreState.mScrollX, false);
                     break;
@@ -6176,7 +6189,7 @@
                     boolean hasRestoreState = restoreState != null;
                     if (hasRestoreState) {
                         updateZoomRange(restoreState, viewSize.x,
-                                draw.mWidthHeight.x, true);
+                                draw.mMinPrefWidth, true);
                         if (!mDrawHistory) {
                             mInZoomOverview = false;
 
@@ -6238,12 +6251,10 @@
                         // sMaxViewportWidth so that if the page doesn't behave
                         // well, the WebView won't go insane. limit the lower
                         // bound to match the default scale for mobile sites.
-                        // we choose the content width to be mZoomOverviewWidth.
-                        // this works for most of the sites. But some sites may
-                        // cause the page layout wider than it needs.
                         mZoomOverviewWidth = Math.min(sMaxViewportWidth, Math
-                                .max((int) (viewWidth / mDefaultScale),
-                                        draw.mWidthHeight.x));
+                                .max((int) (viewWidth / mDefaultScale), Math
+                                        .max(draw.mMinPrefWidth,
+                                                draw.mViewPoint.x)));
                     }
                     if (!mMinZoomScaleFixed) {
                         mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
@@ -6371,6 +6382,7 @@
                     break;
                 case RESUME_WEBCORE_PRIORITY:
                     WebViewCore.resumePriority();
+                    WebViewCore.resumeUpdatePicture(mWebViewCore);
                     break;
 
                 case LONG_PRESS_CENTER:
@@ -6893,13 +6905,12 @@
                 new InvokeListBox(array, enabledArray, selectedArray));
     }
 
-    // viewWidth/contentWidth/updateZoomOverview are only used for mobile sites
     private void updateZoomRange(WebViewCore.RestoreState restoreState,
-            int viewWidth, int contentWidth, boolean updateZoomOverview) {
+            int viewWidth, int minPrefWidth, boolean updateZoomOverview) {
         if (restoreState.mMinScale == 0) {
             if (restoreState.mMobileSite) {
-                if (contentWidth > Math.max(0, viewWidth)) {
-                    mMinZoomScale = (float) viewWidth / contentWidth;
+                if (minPrefWidth > Math.max(0, viewWidth)) {
+                    mMinZoomScale = (float) viewWidth / minPrefWidth;
                     mMinZoomScaleFixed = false;
                     if (updateZoomOverview) {
                         WebSettings settings = getSettings();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 445e7ff..625e7ba 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1705,6 +1705,7 @@
         Region mInvalRegion;
         Point mViewPoint;
         Point mWidthHeight;
+        int mMinPrefWidth;
         RestoreState mRestoreState; // only non-null if it is for the first
                                     // picture set after the first layout
         boolean mFocusSizeChanged;
@@ -1724,6 +1725,13 @@
             // layout.
             draw.mFocusSizeChanged = nativeFocusBoundsChanged();
             draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
+            if (mSettings.getUseWideViewPort()) {
+                draw.mMinPrefWidth = Math.max(
+                        mViewportWidth == -1 ? WebView.DEFAULT_VIEWPORT_WIDTH
+                                : (mViewportWidth == 0 ? mCurrentViewWidth
+                                        : mViewportWidth),
+                        nativeGetContentMinPrefWidth());
+            }
             if (mRestoreState != null) {
                 draw.mRestoreState = mRestoreState;
                 mRestoreState = null;
@@ -1752,9 +1760,9 @@
 
     final DrawFilter mZoomFilter =
                     new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG);
-    final DrawFilter mScrollFilter = null;
-    // If we need to trade more speed for less quality on slower devices
-    // use this: new PaintFlagsDrawFilter(SCROLL_BITS, 0);
+    // If we need to trade better quality for speed, set mScrollFilter to null
+    final DrawFilter mScrollFilter =
+                new PaintFlagsDrawFilter(SCROLL_BITS, 0);
 
     /* package */ void drawContentPicture(Canvas canvas, int color,
                                           boolean animatingZoom,
@@ -2077,7 +2085,7 @@
             restoreState.mDefaultScale = adjust;
             // as mViewportWidth is not 0, it is not mobile site.
             restoreState.mMobileSite = false;
-            // for non-mobile site, we don't need contentWidth, set it as 0
+            // for non-mobile site, we don't need minPrefWidth, set it as 0
             restoreState.mScrollX = 0;
             Message.obtain(mWebView.mPrivateHandler,
                     WebView.UPDATE_ZOOM_RANGE, restoreState).sendToTarget();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9e3e8a4..db71b21b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1031,7 +1031,8 @@
         android:description="@string/permdesc_deletePackages"
         android:protectionLevel="signatureOrSystem" />
 
-    <!-- Allows an application to move location of installed package. -->
+    <!-- Allows an application to move location of installed package.
+         @hide -->
     <permission android:name="android.permission.MOVE_PACKAGE"
         android:label="@string/permlab_movePackage"
         android:description="@string/permdesc_movePackage"
@@ -1207,7 +1208,8 @@
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signatureOrSystem" />
 
-    <!-- Allow an application to read and write the cache partition. -->
+    <!-- Allow an application to read and write the cache partition.
+         @hide -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
         android:label="@string/permlab_cache_filesystem"
         android:description="@string/permdesc_cache_filesystem"
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
index 41ad27d..6b4f66d 100644
--- a/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_throttle_warning.png b/core/res/res/drawable-hdpi/stat_sys_throttle_warning.png
new file mode 100644
index 0000000..c42b00c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_throttle_warning.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_throttled.png b/core/res/res/drawable-hdpi/stat_sys_throttled.png
new file mode 100644
index 0000000..e43fbae
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_throttled.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
index ee77526..d29c6c3 100644
--- a/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_throttle_warning.png b/core/res/res/drawable-mdpi/stat_sys_throttle_warning.png
new file mode 100644
index 0000000..3688803
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_throttle_warning.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_throttled.png b/core/res/res/drawable-mdpi/stat_sys_throttled.png
new file mode 100644
index 0000000..efb64ad
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_throttled.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index a4b2357..945d283 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -152,5 +152,19 @@
         android:layout_marginBottom="80dip"
         />
 
+    <!-- emergency call button shown when sim is PUKd and tab_selector is
+         hidden -->
+    <Button
+        android:id="@+id/emergencyCallButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:drawableLeft="@drawable/ic_emergency"
+        android:layout_centerInParent="true"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="80dip"
+        style="@style/Widget.Button.Transparent"
+        android:drawablePadding="8dip"
+        />
+
 </RelativeLayout>
 
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index e1c9772..6b76004e 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -153,4 +153,16 @@
         android:layout_marginRight="80dip"
         />
 
+    <!-- emergency call button shown when sim is PUKd and tab_selector is
+         hidden -->
+    <Button
+        android:id="@+id/emergencyCallButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:drawableLeft="@drawable/ic_emergency"
+        style="@style/Widget.Button.Transparent"
+        android:drawablePadding="8dip"
+        android:layout_marginRight="80dip"
+        />
+
 </LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 29a815f..7ebbab0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -128,11 +128,15 @@
          in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
     <integer name="config_carDockKeepsScreenOn">1</integer>
 
-    <!-- Control whether being in the desk dock should enable accelerometer based screen orientation -->
+    <!-- Control whether being in the desk dock should enable accelerometer
+         based screen orientation.  Note this should probably default to true
+         like car dock, but we haven't had a chance to test it. -->
     <bool name="config_deskDockEnablesAccelerometer">false</bool>
 
-    <!-- Control whether being in the car dock should enable accelerometer based screen orientation -->
-    <bool name="config_carDockEnablesAccelerometer">false</bool>
+    <!-- Control whether being in the car dock should enable accelerometer based
+         screen orientation.  This defaults to true because putting a device in
+         a car dock make the accelerometer more a physical input (like a lid). -->
+    <bool name="config_carDockEnablesAccelerometer">true</bool>
 
     <!-- Indicate whether the lid state impacts the accessibility of
          the physical keyboard.  0 means it doesn't, 1 means it is accessible
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 48d1ad7..36dc07c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2257,4 +2257,14 @@
     <!-- Shown when the device is tethered -->
     <string name="tethered_notification_title">Tethering active</string>
     <string name="tethered_notification_message">Touch to configure</string>
+
+    <!-- Strings for throttling notification -->
+    <!-- Shown when the user is in danger of being throttled -->
+    <string name="throttle_warning_notification_title">Excessive data use warning</string>
+    <string name="throttle_warning_notification_message">If your data use pattern continues you may be subject to bandwidth restrictions - touch for more information</string>
+
+    <!-- Strings for throttling notification -->
+    <!-- Shown when the users bandwidth is reduced because of excessive data use -->
+    <string name="throttled_notification_title">Bandwidth Restricted</string>
+    <string name="throttled_notification_message">Your mobile data bandwidth is being reduced because of excessive data use - touch for more information</string>
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 152f02e..7fa64ca 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -328,14 +328,14 @@
         boolean checkSd = false;
         int setLoc = 0;
         try {
-            setLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SET_INSTALL_LOCATION);
+            setLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION);
         } catch (SettingNotFoundException e) {
             failStr(e);
         }
         if (setLoc == 1) {
             int userPref = APP_INSTALL_AUTO;
             try {
-                userPref = Settings.System.getInt(mContext.getContentResolver(), Settings.System.DEFAULT_INSTALL_LOCATION);
+                userPref = Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.DEFAULT_INSTALL_LOCATION);
             } catch (SettingNotFoundException e) {
                 failStr(e);
             }
@@ -1302,8 +1302,8 @@
         boolean userSetting = false;
         int origDefaultLoc = PackageInfo.INSTALL_LOCATION_AUTO;
         try {
-            userSetting = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SET_INSTALL_LOCATION) != 0;
-            origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.System.DEFAULT_INSTALL_LOCATION);
+            userSetting = Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION) != 0;
+            origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.DEFAULT_INSTALL_LOCATION);
         } catch (SettingNotFoundException e1) {
         }
         return origDefaultLoc;
@@ -1311,7 +1311,7 @@
 
     private void setInstallLoc(int loc) {
         Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.DEFAULT_INSTALL_LOCATION, loc);
+                Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
     }
     /*
      * Tests for moving apps between internal and external storage
@@ -1963,7 +1963,7 @@
     */
    private boolean getUserSettingSetInstallLocation() {
        try {
-           return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SET_INSTALL_LOCATION) != 0;
+           return Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION) != 0;
            
        } catch (SettingNotFoundException e1) {
        }
@@ -1972,7 +1972,7 @@
 
    private void setUserSettingSetInstallLocation(boolean value) {
        Settings.System.putInt(mContext.getContentResolver(),
-               Settings.System.SET_INSTALL_LOCATION, value ? 1 : 0);
+               Settings.Secure.SET_INSTALL_LOCATION, value ? 1 : 0);
    }
    private void setUserX(boolean enable, int userSetting, int iloc) {
        boolean origUserSetting = getUserSettingSetInstallLocation();
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index 1255949..734a79d 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -109,7 +109,7 @@
 </dd>
 
 <dt><a name="install"></a>{@code android:installLocation}</dt>
-<dd>The default install location for your application.
+<dd>The default install location for the application.
 <p>This attribute was introduced in API Level 8.</p>
 
 <p>The following keyword strings are accepted:</p>
@@ -124,15 +124,15 @@
 saved preference.</td>
 </tr><tr>
    <td>"{@code internalOnly}"</td>
-   <td>Request to be installed only on the internal device storage. If this is set, then
-the application will never be installed on the external storage (SD card). If the internal storage
-is full, then the application will not install.</td>
+   <td>The application requests to be installed on the internal device storage only. If this is set,
+then the application will never be installed on the external storage (SD card). If the internal
+storage is full, then the system will not install the application.</td>
 </tr><tr>
    <td>"{@code preferExternal}"</td>
-   <td>Prefer to be installed on external storage (SD card). There is no guarantee that the system
-will honor this request. The application might be installed on internal storage if the
-external media is unavailable or full, or if the application uses the forward-locking mechanism
-(not supported on external storage).</td>
+   <td>The application prefers to be installed on the external storage (SD card). There is no
+guarantee that the system will honor this request. The application might be installed on internal
+storage if the external media is unavailable or full, or if the application uses the forward-locking
+mechanism (not supported on external storage).</td>
 </tr>
 </table>
 
@@ -149,7 +149,8 @@
 </ul>
 
 <p>The user may also request to move an application from the internal storage to the external
-storage. However, this will not be allowed if this attribute is set to {@code internalOnly}.
+storage. However, the system will not allow the user to move the application to external storage if
+this attribute is set to {@code internalOnly}.
 </p>
 
 </dd>
@@ -159,9 +160,7 @@
 
 <!-- ##api level indication## -->
 <dt>introduced in:</dt>
-<dd>API Level 1 for all attributes except for 
-<code><a href="#uidlabel">sharedUserLabel</a></code>, which was added in 
-level 3.</dd>
+<dd>API Level 1 for all attributes, unless noted otherwise in the attribute description.</dd>
 
 <p>
 <dt>see also:</dt>
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index b5d1e7a..ea31942 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -54,7 +54,7 @@
 
 private:
     enum {
-        kBufferSize = 32 * 1024,
+        kBufferSize = 64 * 1024,
 
         // If we encounter a socket-read error we'll try reconnecting
         // and restarting the read for at most this many times.
@@ -77,9 +77,6 @@
     int mStartingPort;
 
     HTTPStream *mHttp;
-    char *mHost;
-    int mPort;
-    char *mPath;
 
     void *mBuffer;
     size_t mBufferLength;
@@ -95,6 +92,8 @@
     ssize_t sendRangeRequest(size_t offset);
     void initHeaders(const KeyedVector<String8, String8> *overrides);
 
+    status_t connectWithRedirectsAndRange(off_t rangeStart);
+
     HTTPDataSource(const HTTPDataSource &);
     HTTPDataSource &operator=(const HTTPDataSource &);
 };
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index e7022f4..63dfa67 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1091,7 +1091,7 @@
         }
 
         dataSource = new CachingDataSource(
-                mConnectingDataSource, 32 * 1024, 20);
+                mConnectingDataSource, 64 * 1024, 10);
 
         mConnectingDataSource.clear();
     } else {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 284e3bc..86e4bfe 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -105,7 +105,7 @@
         if (httpSource->connect() != OK) {
             return NULL;
         }
-        source = new CachingDataSource(httpSource, 32 * 1024, 20);
+        source = new CachingDataSource(httpSource, 64 * 1024, 10);
     } else {
         // Assume it's a filename.
         source = new FileSource(uri);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 61ffa8d..a0b1993 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -29,71 +29,101 @@
 
 namespace android {
 
-// Given a connected HTTPStream, determine if the given path redirects
-// somewhere else, if so, disconnect the stream, update host path and port
-// accordingly and return true, otherwise return false and leave the stream
-// connected.
-static bool PerformRedirectIfNecessary(
-        HTTPStream *http, const String8 &headers,
-        string *host, string *path, int *port) {
-    String8 request;
-    request.append("GET ");
-    request.append(path->c_str());
-    request.append(" HTTP/1.1\r\n");
-    request.append(headers);
-    request.append("Host: ");
-    request.append(host->c_str());
-    request.append("\r\n\r\n");
+status_t HTTPDataSource::connectWithRedirectsAndRange(off_t rangeStart) {
+    string host = mStartingHost.string();
+    string path = mStartingPath.string();
+    int port = mStartingPort;
 
-    status_t err = http->send(request.string());
+    LOGV("Connecting to host '%s', port %d, path '%s'",
+         host.c_str(), port, path.c_str());
 
-    int http_status;
-    if (err == OK) {
-        err = http->receive_header(&http_status);
+    int numRedirectsRemaining = 5;
+    while (numRedirectsRemaining-- > 0) {
+        status_t err = mHttp->connect(host.c_str(), port);
+
+        if (err != OK) {
+            return err;
+        }
+
+        String8 request;
+        request.append("GET ");
+        request.append(path.c_str());
+        request.append(" HTTP/1.1\r\n");
+        request.append(mHeaders);
+        request.append("Host: ");
+        request.append(host.c_str());
+        request.append("\r\n");
+
+        if (rangeStart > 0) {
+            char range[128];
+            sprintf(range, "Range: bytes=%ld-\r\n", rangeStart);
+
+            request.append(range);
+        }
+
+        request.append("\r\n");
+
+        err = mHttp->send(request.string());
+
+        if (err != OK) {
+            return err;
+        }
+
+        int httpStatus;
+        err = mHttp->receive_header(&httpStatus);
+
+        if (err != OK) {
+            return err;
+        }
+
+        if (httpStatus >= 200 && httpStatus < 300) {
+            return OK;
+        }
+
+        if (httpStatus != 301 && httpStatus != 302) {
+            LOGE("HTTP request failed w/ http status %d", httpStatus);
+            return ERROR_IO;
+        }
+
+        string location;
+        CHECK(mHttp->find_header_value("Location", &location));
+
+        CHECK(string(location, 0, 7) == "http://");
+        location.erase(0, 7);
+        string::size_type slashPos = location.find('/');
+        if (slashPos == string::npos) {
+            slashPos = location.size();
+            location += '/';
+        }
+
+        mHttp->disconnect();
+
+        LOGV("Redirecting to %s\n", location.c_str());
+
+        host = string(location, 0, slashPos);
+
+        string::size_type colonPos = host.find(':');
+        if (colonPos != string::npos) {
+            const char *start = host.c_str() + colonPos + 1;
+            char *end;
+            long tmp = strtol(start, &end, 10);
+            CHECK(end > start && (*end == '\0'));
+
+            port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
+
+            host.erase(colonPos, host.size() - colonPos);
+        } else {
+            port = 80;
+        }
+
+        path = string(location, slashPos);
+
+        mStartingHost = host.c_str();
+        mStartingPath = path.c_str();
+        mStartingPort = port;
     }
 
-    if (err != OK) {
-        return false;
-    }
-
-    if (http_status != 301 && http_status != 302) {
-        return false;
-    }
-
-    string location;
-    CHECK(http->find_header_value("Location", &location));
-
-    CHECK(string(location, 0, 7) == "http://");
-    location.erase(0, 7);
-    string::size_type slashPos = location.find('/');
-    if (slashPos == string::npos) {
-        slashPos = location.size();
-        location += '/';
-    }
-
-    http->disconnect();
-
-    LOGI("Redirecting to %s\n", location.c_str());
-
-    *host = string(location, 0, slashPos);
-
-    string::size_type colonPos = host->find(':');
-    if (colonPos != string::npos) {
-        const char *start = host->c_str() + colonPos + 1;
-        char *end;
-        long tmp = strtol(start, &end, 10);
-        CHECK(end > start && (*end == '\0'));
-
-        *port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
-
-        host->erase(colonPos, host->size() - colonPos);
-    } else {
-        *port = 80;
-    }
-
-    *path = string(location, slashPos);
-
-    return true;
+    return ERROR_IO;
 }
 
 HTTPDataSource::HTTPDataSource(
@@ -147,10 +177,6 @@
     mState = DISCONNECTED;
     mHttp = new HTTPStream;
 
-    mHost = NULL;
-    mPort = 0;
-    mPath = NULL;
-
     initHeaders(headers);
 
     mBuffer = malloc(kBufferSize);
@@ -173,29 +199,18 @@
     mBufferOffset = 0;
     mContentLengthValid = false;
 
-    string host = mStartingHost.string();
-    string path = mStartingPath.string();
-    int port = mStartingPort;
+    status_t err = connectWithRedirectsAndRange(0);
 
-    LOGI("Connecting to host '%s', port %d, path '%s'",
-         host.c_str(), port, path.c_str());
+    if (err != OK) {
+        Mutex::Autolock autoLock(mStateLock);
 
-    int numRedirectsRemaining = 5;
-    do {
-        status_t err = mHttp->connect(host.c_str(), port);
-
-        if (err != OK) {
-            Mutex::Autolock autoLock(mStateLock);
-
-            if (mState != CONNECTING) {
-                LOGV("connect() cancelled");
-            }
-            mState = DISCONNECTED;
-
-            return err;
+        if (mState != CONNECTING) {
+            LOGV("connect() cancelled");
         }
-    } while (PerformRedirectIfNecessary(mHttp, mHeaders, &host, &path, &port)
-             && numRedirectsRemaining-- > 0);
+        mState = DISCONNECTED;
+
+        return err;
+    }
 
     string value;
     if (mHttp->find_header_value("Content-Length", &value)) {
@@ -204,10 +219,6 @@
         mContentLengthValid = true;
     }
 
-    mHost = strdup(host.c_str());
-    mPort = port;
-    mPath = strdup(path.c_str());
-
     Mutex::Autolock autoLock(mStateLock);
 
     if (mState != CONNECTING) {
@@ -219,6 +230,7 @@
     }
 
     mState = CONNECTED;
+
     return OK;
 }
 
@@ -264,56 +276,13 @@
 
     free(mBuffer);
     mBuffer = NULL;
-
-    if (mPath) {
-        free(mPath);
-        mPath = NULL;
-    }
-
-    if (mHost) {
-        free(mHost);
-        mHost = NULL;
-    }
 }
 
 ssize_t HTTPDataSource::sendRangeRequest(size_t offset) {
-    char host[128];
-    sprintf(host, "Host: %s\r\n", mHost);
+    status_t err = connectWithRedirectsAndRange(offset);
 
-    char range[128];
-    if (offset > 0) {
-        sprintf(range, "Range: bytes=%d-\r\n\r\n", offset);
-    } else {
-        range[0] = '\0';
-    }
-
-    int http_status;
-
-    status_t err;
-    int attempt = 1;
-    for (;;) {
-        if ((err = mHttp->send("GET ")) != OK
-            || (err = mHttp->send(mPath)) != OK
-            || (err = mHttp->send(" HTTP/1.1\r\n")) != OK
-            || (err = mHttp->send(mHeaders.string())) != OK
-            || (err = mHttp->send(host)) != OK
-            || (err = mHttp->send(range)) != OK
-            || (err = mHttp->send("\r\n")) != OK
-            || (err = mHttp->receive_header(&http_status)) != OK) {
-
-            if (attempt == 3) {
-                return err;
-            }
-
-            mHttp->connect(mHost, mPort);
-            ++attempt;
-        } else {
-            break;
-        }
-    }
-
-    if ((http_status / 100) != 2) {
-        return UNKNOWN_ERROR;
+    if (err != OK) {
+        return err;
     }
 
     string value;
@@ -349,6 +318,10 @@
 
         memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
 
+        if (copy < size) {
+            LOGV("short read (1), returning %d vs. %d requested", copy, size);
+        }
+
         return copy;
     }
 
@@ -388,8 +361,10 @@
     if (num_bytes_received < 0
             || (mContentLengthValid && num_bytes_received < contentLength)) {
         if (mNumRetriesLeft-- > 0) {
-            disconnect();
-            if (connect() == OK) {
+            mHttp->disconnect();
+            mBufferLength = 0;
+            num_bytes_received = connectWithRedirectsAndRange(mBufferOffset);
+            if (num_bytes_received == OK) {
                 LOGI("retrying connection succeeded.");
                 goto rinse_repeat;
             }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 14c8806..57f9ce7 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -339,25 +339,19 @@
                 checkBoth = true;
                 break check_inner;
             }
-            // Check if user option is enabled
-            boolean setInstallLoc = Settings.System.getInt(getApplicationContext()
+            // Pick user preference
+            int installPreference = Settings.System.getInt(getApplicationContext()
                     .getContentResolver(),
-                    Settings.System.SET_INSTALL_LOCATION, 0) != 0;
-            if (setInstallLoc) {
-                // Pick user preference
-                int installPreference = Settings.System.getInt(getApplicationContext()
-                        .getContentResolver(),
-                        Settings.System.DEFAULT_INSTALL_LOCATION,
-                        PackageHelper.APP_INSTALL_AUTO);
-                if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
-                    checkInt = true;
-                    checkBoth = true;
-                    break check_inner;
-                } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
-                    checkExt = true;
-                    checkBoth = true;
-                    break check_inner;
-                }
+                    Settings.Secure.DEFAULT_INSTALL_LOCATION,
+                    PackageHelper.APP_INSTALL_AUTO);
+            if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
+                checkInt = true;
+                checkBoth = true;
+                break check_inner;
+            } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
+                checkExt = true;
+                checkBoth = true;
+                break check_inner;
             }
             // Fall back to default policy if nothing else is specified.
             checkInt = true;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 34302c4..185d72a9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -56,10 +56,6 @@
     <bool name="def_mount_ums_autostart">false</bool>
     <bool name="def_mount_ums_prompt">true</bool>
     <bool name="def_mount_ums_notify_enabled">true</bool>
-    <!-- Enable User preference for setting install location -->
-    <bool name="set_install_location">true</bool>
-    <!-- Default install location if user preference for setting install location is turned on. -->
-    <integer name="def_install_location">2</integer>
 
     <!-- user interface sound effects -->
     <integer name="def_power_sounds_enabled">1</integer>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index d0e9dd9..0c0bf93 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -39,6 +39,8 @@
 import android.util.Config;
 import android.util.Log;
 import android.util.Xml;
+
+import com.android.internal.content.PackageHelper;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
@@ -61,7 +63,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 55;
+    private static final int DATABASE_VERSION = 56;
 
     private Context mContext;
 
@@ -608,21 +610,8 @@
 
        if (upgradeVersion == 50) {
            /*
-            * New settings for set install location UI.
+            * Install location no longer initiated here.
             */
-           db.beginTransaction();
-           SQLiteStatement stmt = null;
-           try {
-                stmt = db.compileStatement("INSERT INTO system(name,value)"
-                        + " VALUES(?,?);");
-                loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION,
-                        R.bool.set_install_location);
-                db.setTransactionSuccessful();
-            } finally {
-                db.endTransaction();
-                if (stmt != null) stmt.close();
-            }
-
            upgradeVersion = 51;
        }
 
@@ -663,21 +652,8 @@
         
         if (upgradeVersion == 53) {
             /*
-             * New settings for set install location UI.
+             * New settings for set install location UI no longer initiated here.
              */
-            db.beginTransaction();
-            SQLiteStatement stmt = null;
-            try {
-                 stmt = db.compileStatement("INSERT INTO system(name,value)"
-                         + " VALUES(?,?);");
-                 loadIntegerSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
-                         R.integer.def_install_location);
-                 db.setTransactionSuccessful();
-             } finally {
-                 db.endTransaction();
-                 if (stmt != null) stmt.close();
-             }
-
             upgradeVersion = 54;
         }
 
@@ -696,6 +672,28 @@
             upgradeVersion = 55;
         }
 
+        if (upgradeVersion == 55) {
+            /* Move the install location settings. */
+            String[] settingsToMove = {
+                    Secure.SET_INSTALL_LOCATION,
+                    Secure.DEFAULT_INSTALL_LOCATION
+            };
+            moveFromSystemToSecure(db, settingsToMove);
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT INTO system(name,value)"
+                        + " VALUES(?,?);");
+                loadSetting(stmt, Secure.SET_INSTALL_LOCATION, 0);
+                loadSetting(stmt, Secure.DEFAULT_INSTALL_LOCATION,
+                        PackageHelper.APP_INSTALL_AUTO);
+                db.setTransactionSuccessful();
+             } finally {
+                 db.endTransaction();
+                 if (stmt != null) stmt.close();
+             }
+            upgradeVersion = 56;
+        }
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -1021,10 +1019,9 @@
     
             loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
                     R.bool.def_notification_pulse);
-            loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION,
-                    R.bool.set_install_location);
-            loadIntegerSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
-                    R.integer.def_install_location);
+            loadSetting(stmt, Settings.Secure.SET_INSTALL_LOCATION, 0);
+            loadSetting(stmt, Settings.Secure.DEFAULT_INSTALL_LOCATION,
+                    PackageHelper.APP_INSTALL_AUTO);
     
             loadUISoundEffectsSettings(stmt);
     
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 95dbf3c..e6663d4 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -31,8 +31,9 @@
 import android.app.IActivityManager;
 import android.app.admin.IDevicePolicyManager;
 import android.app.backup.IBackupManager;
-import android.content.ComponentName;
 import android.content.Context;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -83,6 +84,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.security.SystemKeyStore;
 import android.util.*;
 import android.view.Display;
@@ -582,11 +584,11 @@
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras);
+                                    extras, null);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras);
+                                        extras, null);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -4471,7 +4473,8 @@
         }
     };
 
-    private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
+    private static final void sendPackageBroadcast(String action, String pkg,
+            Bundle extras, IIntentReceiver finishedReceiver) {
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
@@ -4481,9 +4484,8 @@
                     intent.putExtras(extras);
                 }
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                am.broadcastIntent(
-                    null, intent,
-                            null, null, 0, null, null, null, false, false);
+                am.broadcastIntent(null, intent, null, finishedReceiver,
+                        0, null, null, null, finishedReceiver != null, false);
             } catch (RemoteException ex) {
             }
         }
@@ -4605,12 +4607,14 @@
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
+                        extras, null);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
+                        extras, null);
             }
         }
 
@@ -6052,8 +6056,8 @@
                 extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
 
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, null);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, null);
             }
         }
         // Force a gc here.
@@ -6084,10 +6088,10 @@
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
             }
             if (removedPackage != null) {
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null);
             }
             if (removedUid >= 0) {
-                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
+                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null);
             }
         }
     }
@@ -6789,7 +6793,7 @@
         extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
-        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras);
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null);
     }
 
     public String getInstallerPackageName(String packageName) {
@@ -9512,7 +9516,7 @@
    }
 
    private void sendResourcesChangedBroadcast(boolean mediaStatus,
-           ArrayList<String> pkgList, int uidArr[]) {
+           ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
        int size = pkgList.size();
        if (size > 0) {
            // Send broadcasts here
@@ -9524,7 +9528,7 @@
            }
            String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                    : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
-           sendPackageBroadcast(action, null, extras);
+           sendPackageBroadcast(action, null, extras, finishedReceiver);
        }
    }
 
@@ -9611,7 +9615,7 @@
        }
        // Send a broadcast to let everyone know we are done processing
        if (pkgList.size() > 0) {
-           sendResourcesChangedBroadcast(true, pkgList, uidArr);
+           sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
        }
        if (doGc) {
            Runtime.getRuntime().gc();
@@ -9649,10 +9653,15 @@
        }
        // Send broadcasts
        if (pkgList.size() > 0) {
-           sendResourcesChangedBroadcast(false, pkgList, uidArr);
+           sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
+               public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+                       boolean ordered, boolean sticky) throws RemoteException {
+                   // Force gc now that everyone is done cleaning up, to release
+                   // references on assets.
+                   Runtime.getRuntime().gc();
+               }
+           });
        }
-       // Force gc
-       Runtime.getRuntime().gc();
        // Just unmount all valid containers.
        for (SdInstallArgs args : keys) {
            synchronized (mInstallLock) {
@@ -9742,7 +9751,7 @@
                    }
                    if (returnCode == PackageManager.MOVE_SUCCEEDED) {
                        // Send resources unavailable broadcast
-                       sendResourcesChangedBroadcast(false, pkgList, uidArr);
+                       sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
                        // Update package code and resource paths
                        synchronized (mInstallLock) {
                            synchronized (mPackages) {
@@ -9793,7 +9802,7 @@
                                }
                            }
                            // Send resources available broadcast
-                           sendResourcesChangedBroadcast(true, pkgList, uidArr);
+                           sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
                        }
                    }
                }
@@ -9821,5 +9830,26 @@
            }
        });
    }
+
+   public boolean setInstallLocation(int loc) {
+       mContext.enforceCallingOrSelfPermission(
+               android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
+       if (getInstallLocation() == loc) {
+           return true;
+       }
+       if (loc == PackageHelper.APP_INSTALL_AUTO ||
+               loc == PackageHelper.APP_INSTALL_INTERNAL ||
+               loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+           android.provider.Settings.System.putInt(mContext.getContentResolver(),
+                   android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
+           return true;
+       }
+       return false;
+   }
+
+   public int getInstallLocation() {
+       return android.provider.Settings.System.getInt(mContext.getContentResolver(),
+               android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO);
+   }
 }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 25a60a6..9d5d035 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -99,6 +99,7 @@
         DockObserver dock = null;
         UiModeManagerService uiMode = null;
         RecognitionManagerService recognition = null;
+        ThrottleService throttle = null;
 
         // Critical services...
         try {
@@ -269,6 +270,15 @@
             }
 
             try {
+                Slog.i(TAG, "Throttle Service");
+                throttle = new ThrottleService(context);
+                ServiceManager.addService(
+                        Context.THROTTLE_SERVICE, throttle);
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting ThrottleService", e);
+            }
+
+            try {
               Slog.i(TAG, "Accessibility Manager");
               ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
                       new AccessibilityManagerService(context));
@@ -457,6 +467,7 @@
         final BatteryService batteryF = battery;
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
+        final ThrottleService throttleF = throttle;
         final UiModeManagerService uiModeF = uiMode;
         final AppWidgetService appWidgetF = appWidget;
         final WallpaperManagerService wallpaperF = wallpaper;
@@ -488,6 +499,7 @@
                 if (wallpaperF != null) wallpaperF.systemReady();
                 if (immF != null) immF.systemReady();
                 if (locationF != null) locationF.systemReady();
+                if (throttleF != null) throttleF.systemReady();
             }
         });
 
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
new file mode 100644
index 0000000..36931b2
--- /dev/null
+++ b/services/java/com/android/server/ThrottleService.java
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed 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 com.android.server;
+
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.SharedPreferences;
+import android.net.IThrottleManager;
+import android.net.ThrottleManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Random;
+
+// TODO - add comments - reference the ThrottleManager for public API
+public class ThrottleService extends IThrottleManager.Stub {
+
+    private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
+
+    private static final String TAG = "ThrottleService";
+    private static boolean DBG = true;
+    private Handler mHandler;
+    private HandlerThread mThread;
+
+    private Context mContext;
+
+    private int mPolicyPollPeriodSec;
+    private static final int DEFAULT_POLLING_PERIOD_SEC = 60 * 10;
+    private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
+
+    private static final int TESTING_RESET_PERIOD_SEC = 60 * 3;
+
+    private static final int PERIOD_COUNT = 6;
+
+    private long mPolicyThreshold;
+    // TODO - remove testing stuff?
+    private static final long DEFAULT_TESTING_THRESHOLD = 1 * 1024 * 1024;
+    private static final long DEFAULT_THRESHOLD = 0; // off by default
+
+    private int mPolicyThrottleValue;
+    private static final int DEFAULT_THROTTLE_VALUE = 100; // 100 Kbps
+
+    private int mPolicyResetDay; // 1-28
+
+    private long mLastRead; // read byte count from last poll
+    private long mLastWrite; // write byte count from last poll
+
+    private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
+    private static int POLL_REQUEST = 0;
+    private PendingIntent mPendingPollIntent;
+    private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
+    private static int RESET_REQUEST = 1;
+    private PendingIntent mPendingResetIntent;
+
+    private INetworkManagementService mNMService;
+    private AlarmManager mAlarmManager;
+    private NotificationManager mNotificationManager;
+
+    private DataRecorder mRecorder;
+
+    private int mThrottleLevel; // 0 for none, 1 for first throttle val, 2 for next, etc
+
+    private String mPolicyIface;
+
+    private static final int NOTIFICATION_WARNING   = 2;
+    private static final int NOTIFICATION_ALL       = 0xFFFFFFFF;
+    private int mPolicyNotificationsAllowedMask;
+
+    private Notification mThrottlingNotification;
+    private boolean mWarningNotificationSent = false;
+
+    public ThrottleService(Context context) {
+        if (DBG) Slog.d(TAG, "Starting ThrottleService");
+        mContext = context;
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        Intent pollIntent = new Intent(ACTION_POLL, null);
+        mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+        Intent resetIntent = new Intent(ACTION_RESET, null);
+        mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
+
+        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        mNMService = INetworkManagementService.Stub.asInterface(b);
+
+        mNotificationManager = (NotificationManager)mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+    }
+
+    private void enforceAccessPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE,
+                "ThrottleService");
+    }
+
+    public synchronized long getResetTime(String iface) {
+        enforceAccessPermission();
+        if (iface.equals(mPolicyIface) && (mRecorder != null)) mRecorder.getPeriodEnd();
+        return 0;
+    }
+    public synchronized long getPeriodStartTime(String iface) {
+        enforceAccessPermission();
+        if (iface.equals(mPolicyIface) && (mRecorder != null)) mRecorder.getPeriodStart();
+        return 0;
+    }
+    //TODO - a better name?  getCliffByteCountThreshold?
+    public synchronized long getCliffThreshold(String iface, int cliff) {
+        enforceAccessPermission();
+        if ((cliff == 0) && iface.equals(mPolicyIface)) {
+            return mPolicyThreshold;
+        }
+        return 0;
+    }
+    // TODO - a better name? getThrottleRate?
+    public synchronized int getCliffLevel(String iface, int cliff) {
+        enforceAccessPermission();
+        if ((cliff == 0) && iface.equals(mPolicyIface)) {
+            return mPolicyThrottleValue;
+        }
+        return 0;
+    }
+
+    public synchronized long getByteCount(String iface, int dir, int period, int ago) {
+        enforceAccessPermission();
+        if (iface.equals(mPolicyIface) &&
+                (period == ThrottleManager.PERIOD_CYCLE) &&
+                (mRecorder != null)) {
+            if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
+            if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
+        }
+        return 0;
+    }
+
+    // TODO - a better name - getCurrentThrottleRate?
+    public synchronized int getThrottle(String iface) {
+        enforceAccessPermission();
+        if (iface.equals(mPolicyIface) && (mThrottleLevel == 1)) {
+            return mPolicyThrottleValue;
+        }
+        return 0;
+    }
+
+    void systemReady() {
+        if (DBG) Slog.d(TAG, "systemReady");
+        mContext.registerReceiver(
+            new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
+                }
+            }, new IntentFilter(ACTION_POLL));
+
+        mContext.registerReceiver(
+            new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
+                }
+            }, new IntentFilter(ACTION_RESET));
+
+        // use a new thread as we don't want to stall the system for file writes
+        mThread = new HandlerThread(TAG);
+        mThread.start();
+        mHandler = new MyHandler(mThread.getLooper());
+        mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
+    }
+
+
+    private static final int EVENT_REBOOT_RECOVERY = 0;
+    private static final int EVENT_POLICY_CHANGED  = 1;
+    private static final int EVENT_POLL_ALARM      = 2;
+    private static final int EVENT_RESET_ALARM     = 3;
+    private class MyHandler extends Handler {
+        public MyHandler(Looper l) {
+            super(l);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case EVENT_REBOOT_RECOVERY:
+                onRebootRecovery();
+                break;
+            case EVENT_POLICY_CHANGED:
+                onPolicyChanged();
+                break;
+            case EVENT_POLL_ALARM:
+                onPollAlarm();
+                break;
+            case EVENT_RESET_ALARM:
+                onResetAlarm();
+            }
+        }
+
+        private void onRebootRecovery() {
+            if (DBG) Slog.d(TAG, "onRebootRecovery");
+            // check for sim change TODO
+            // reregister for notification of policy change
+
+            // register for roaming indication change
+            // check for roaming TODO
+
+            mRecorder = new DataRecorder(mContext, ThrottleService.this);
+
+            // get policy
+            mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
+
+            // evaluate current conditions
+            mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
+        }
+
+        private void onSimChange() {
+            // TODO
+        }
+
+        // check for new policy info (threshold limit/value/etc)
+        private void onPolicyChanged() {
+            boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
+
+            int pollingPeriod = DEFAULT_POLLING_PERIOD_SEC;
+            if (testing) pollingPeriod = TESTING_POLLING_PERIOD_SEC;
+            mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
+
+            // TODO - remove testing stuff?
+            long defaultThreshold = DEFAULT_THRESHOLD;
+            if (testing) defaultThreshold = DEFAULT_TESTING_THRESHOLD;
+            synchronized (ThrottleService.this) {
+                mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
+                        Settings.Secure.THROTTLE_THRESHOLD, defaultThreshold);
+                mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.THROTTLE_VALUE, DEFAULT_THROTTLE_VALUE);
+            }
+            mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.THROTTLE_RESET_DAY, -1);
+            if (mPolicyResetDay == -1 ||
+                    ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
+                Random g = new Random();
+                mPolicyResetDay = 1 + g.nextInt(28); // 1-28
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
+            }
+            synchronized (ThrottleService.this) {
+                mPolicyIface = Settings.Secure.getString(mContext.getContentResolver(),
+                        Settings.Secure.THROTTLE_IFACE);
+                // TODO - read default from resource so it's device-specific
+                if (mPolicyIface == null) mPolicyIface = "rmnet0";
+            }
+
+            mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.THROTTLE_NOTIFICATION_TYPE, NOTIFICATION_ALL);
+
+            Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
+                    ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
+                    ", resetDay=" + mPolicyResetDay + ", noteType=" +
+                    mPolicyNotificationsAllowedMask);
+
+            Calendar end = calculatePeriodEnd();
+            Calendar start = calculatePeriodStart(end);
+
+            mRecorder.setNextPeriod(start,end);
+
+            mAlarmManager.cancel(mPendingResetIntent);
+            mAlarmManager.set(AlarmManager.RTC_WAKEUP, end.getTimeInMillis(),
+                    mPendingResetIntent);
+        }
+
+        private void onPollAlarm() {
+            long now = SystemClock.elapsedRealtime();
+            long next = now + mPolicyPollPeriodSec*1000;
+            long incRead = 0;
+            long incWrite = 0;
+            try {
+                incRead = mNMService.getInterfaceRxCounter(mPolicyIface) - mLastRead;
+                incWrite = mNMService.getInterfaceTxCounter(mPolicyIface) - mLastWrite;
+            } catch (RemoteException e) {
+                Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
+            }
+
+            mRecorder.addData(incRead, incWrite);
+
+            long periodRx = mRecorder.getPeriodRx(0);
+            long periodTx = mRecorder.getPeriodTx(0);
+            long total = periodRx + periodTx;
+            if (DBG) {
+                Slog.d(TAG, "onPollAlarm - now =" + now + ", read =" + incRead +
+                        ", written =" + incWrite + ", new total =" + total);
+            }
+            mLastRead += incRead;
+            mLastWrite += incWrite;
+
+            checkThrottleAndPostNotification(total);
+
+            Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
+            broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
+            broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
+            broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, mRecorder.getPeriodStart());
+            broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, mRecorder.getPeriodEnd());
+            mContext.sendStickyBroadcast(broadcast);
+
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
+        }
+
+        private void checkThrottleAndPostNotification(long currentTotal) {
+            // are we even doing this?
+            if (mPolicyThreshold == 0)
+                return;
+
+            // check if we need to throttle
+            if (currentTotal > mPolicyThreshold) {
+                if (mThrottleLevel != 1) {
+                    synchronized (ThrottleService.this) {
+                        mThrottleLevel = 1;
+                    }
+                    if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
+                    try {
+                        mNMService.setInterfaceThrottle(mPolicyIface,
+                                mPolicyThrottleValue, mPolicyThrottleValue);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "error setting Throttle: " + e);
+                    }
+
+                    mNotificationManager.cancel(com.android.internal.R.drawable.
+                            stat_sys_throttle_warning);
+
+                    postNotification(com.android.internal.R.string.throttled_notification_title,
+                            com.android.internal.R.string.throttled_notification_message,
+                            com.android.internal.R.drawable.stat_sys_throttled);
+
+                    Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
+                    broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
+                    mContext.sendStickyBroadcast(broadcast);
+
+                } // else already up!
+            } else {
+                if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
+                    // check if we should warn about throttle
+                    if (currentTotal > (mPolicyThreshold/2) && !mWarningNotificationSent) {
+                        mWarningNotificationSent = true;
+                        mNotificationManager.cancel(com.android.internal.R.drawable.
+                                stat_sys_throttle_warning);
+                        postNotification(com.android.internal.R.string.
+                                throttle_warning_notification_title,
+                                com.android.internal.R.string.
+                                throttle_warning_notification_message,
+                                com.android.internal.R.drawable.stat_sys_throttle_warning);
+                    } else {
+                        mWarningNotificationSent =false;
+                    }
+                }
+            }
+        }
+
+        private void postNotification(int titleInt, int messageInt, int icon) {
+            Intent intent = new Intent();
+            // TODO - fix up intent
+            intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
+            intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+
+            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+            Resources r = Resources.getSystem();
+            CharSequence title = r.getText(titleInt);
+            CharSequence message = r.getText(messageInt);
+            if (mThrottlingNotification == null) {
+                mThrottlingNotification = new Notification();
+                mThrottlingNotification.when = 0;
+                // TODO -  fixup icon
+                mThrottlingNotification.icon = icon;
+                mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
+//                mThrottlingNotification.flags = Notification.FLAG_ONGOING_EVENT;
+            }
+            mThrottlingNotification.tickerText = title;
+            mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
+
+            mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
+        }
+
+
+        private synchronized void clearThrottleAndNotification() {
+            if (mThrottleLevel == 1) {
+                synchronized (ThrottleService.this) {
+                    mThrottleLevel = 0;
+                }
+                try {
+                    mNMService.setInterfaceThrottle(mPolicyIface, -1, -1);
+                } catch (Exception e) {
+                    Slog.e(TAG, "error clearing Throttle: " + e);
+                }
+                Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
+                broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
+                mContext.sendStickyBroadcast(broadcast);
+            }
+            mNotificationManager.cancel(com.android.internal.R.drawable.stat_sys_throttle_warning);
+            mNotificationManager.cancel(com.android.internal.R.drawable.stat_sys_throttled);
+            mWarningNotificationSent = false;
+        }
+
+        private Calendar calculatePeriodEnd() {
+            Calendar end = GregorianCalendar.getInstance();
+            int day = end.get(Calendar.DAY_OF_MONTH);
+            end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
+            end.set(Calendar.HOUR_OF_DAY, 0);
+            end.set(Calendar.MINUTE, 0);
+            if (day >= mPolicyResetDay) {
+                int month = end.get(Calendar.MONTH);
+                if (month == Calendar.DECEMBER) {
+                    end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
+                    month = Calendar.JANUARY - 1;
+                }
+                end.set(Calendar.MONTH, month + 1);
+            }
+
+            // TODO - remove!
+            if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
+                end = GregorianCalendar.getInstance();
+                end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
+            }
+            return end;
+        }
+        private Calendar calculatePeriodStart(Calendar end) {
+            Calendar start = (Calendar)end.clone();
+            int month = end.get(Calendar.MONTH);
+            if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
+                month = Calendar.DECEMBER + 1;
+                start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
+            }
+            start.set(Calendar.MONTH, month - 1);
+
+            // TODO - remove!!
+            if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
+                start = (Calendar)end.clone();
+                start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
+            }
+            return start;
+        }
+
+        private void onResetAlarm() {
+            if (DBG) {
+                Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
+                        " bytes read and " + mRecorder.getPeriodTx(0) + " written");
+            }
+
+            Calendar end = calculatePeriodEnd();
+            Calendar start = calculatePeriodStart(end);
+
+            clearThrottleAndNotification();
+
+            mRecorder.setNextPeriod(start,end);
+
+            mAlarmManager.set(AlarmManager.RTC_WAKEUP, end.getTimeInMillis(),
+                    mPendingResetIntent);
+        }
+    }
+
+    // records bytecount data for a given time and accumulates it into larger time windows
+    // for logging and other purposes
+    //
+    // since time can be changed (user or network action) we will have to track the time of the
+    // last recording and deal with it.
+    private static class DataRecorder {
+        long[] mPeriodRxData;
+        long[] mPeriodTxData;
+        int mCurrentPeriod;
+        int mPeriodCount;
+
+        Calendar mPeriodStart;
+        Calendar mPeriodEnd;
+
+        ThrottleService mParent;
+        Context mContext;
+        SharedPreferences mSharedPreferences;
+
+        DataRecorder(Context context, ThrottleService parent) {
+            mContext = context;
+            mParent = parent;
+
+            synchronized (mParent) {
+                mPeriodCount = 6;
+                mPeriodRxData = new long[mPeriodCount];
+                mPeriodTxData = new long[mPeriodCount];
+
+                mPeriodStart = Calendar.getInstance();
+                mPeriodEnd = Calendar.getInstance();
+
+                mSharedPreferences = mContext.getSharedPreferences("ThrottleData",
+                        android.content.Context.MODE_PRIVATE);
+
+                zeroData(0);
+                retrieve();
+            }
+        }
+
+        void setNextPeriod(Calendar start, Calendar end) {
+            if (DBG) {
+                Slog.d(TAG, "setting next period to " + start.getTimeInMillis() +
+                        " --until-- " + end.getTimeInMillis());
+            }
+            // if we roll back in time to a previous period, toss out the current data
+            // if we roll forward to the next period, advance to the next
+
+            if (end.before(mPeriodStart)) {
+                if (DBG) {
+                    Slog.d(TAG, " old start was " + mPeriodStart.getTimeInMillis() + ", wiping");
+                }
+                synchronized (mParent) {
+                    mPeriodRxData[mCurrentPeriod] = 0;
+                    mPeriodTxData[mCurrentPeriod] = 0;
+                }
+            } else if(start.after(mPeriodEnd)) {
+                if (DBG) {
+                    Slog.d(TAG, " old end was " + mPeriodEnd.getTimeInMillis() + ", following");
+                }
+                synchronized (mParent) {
+                    ++mCurrentPeriod;
+                    if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
+                    mPeriodRxData[mCurrentPeriod] = 0;
+                    mPeriodTxData[mCurrentPeriod] = 0;
+                }
+            } else {
+                if (DBG) Slog.d(TAG, " we fit - ammending to last period");
+            }
+            setPeriodStart(start);
+            setPeriodEnd(end);
+            record();
+        }
+
+        public long getPeriodEnd() {
+            synchronized (mParent) {
+                return mPeriodEnd.getTimeInMillis();
+            }
+        }
+
+        private void setPeriodEnd(Calendar end) {
+            synchronized (mParent) {
+                mPeriodEnd = end;
+            }
+        }
+
+        public long getPeriodStart() {
+            synchronized (mParent) {
+                return mPeriodStart.getTimeInMillis();
+            }
+        }
+
+        private void setPeriodStart(Calendar start) {
+            synchronized (mParent) {
+                mPeriodStart = start;
+            }
+        }
+
+        public int getPeriodCount() {
+            synchronized (mParent) {
+                return mPeriodCount;
+            }
+        }
+
+        private void zeroData(int field) {
+            synchronized (mParent) {
+                for(int period = 0; period<mPeriodCount; period++) {
+                    mPeriodRxData[period] = 0;
+                    mPeriodTxData[period] = 0;
+                }
+                mCurrentPeriod = 0;
+            }
+
+        }
+
+        // if time moves backward accumulate all read/write that's lost into the now
+        // otherwise time moved forward.
+        void addData(long bytesRead, long bytesWritten) {
+            synchronized (mParent) {
+                mPeriodRxData[mCurrentPeriod] += bytesRead;
+                mPeriodTxData[mCurrentPeriod] += bytesWritten;
+            }
+            record();
+        }
+
+        private void record() {
+            // serialize into a secure setting
+
+            // 1 int mPeriodCount
+            // 13*6 long[PERIOD_COUNT] mPeriodRxData
+            // 13*6 long[PERIOD_COUNT] mPeriodTxData
+            // 1  int mCurrentPeriod
+            // 13 long periodStartMS
+            // 13 long periodEndMS
+            // 199 chars max
+            StringBuilder builder = new StringBuilder();
+            builder.append(mPeriodCount);
+            builder.append(":");
+            for(int i=0; i < mPeriodCount; i++) {
+                builder.append(mPeriodRxData[i]);
+                builder.append(":");
+            }
+            for(int i=0; i < mPeriodCount; i++) {
+                builder.append(mPeriodTxData[i]);
+                builder.append(":");
+            }
+            builder.append(mCurrentPeriod);
+            builder.append(":");
+            builder.append(mPeriodStart.getTimeInMillis());
+            builder.append(":");
+            builder.append(mPeriodEnd.getTimeInMillis());
+            builder.append(":");
+
+            SharedPreferences.Editor editor = mSharedPreferences.edit();
+
+            editor.putString("Data", builder.toString());
+            editor.commit();
+        }
+
+        private void retrieve() {
+            String data = mSharedPreferences.getString("Data", "");
+//            String data = Settings.Secure.getString(mContext.getContentResolver(),
+//                    Settings.Secure.THROTTLE_VALUE);
+            if (data == null || data.length() == 0) return;
+
+            synchronized (mParent) {
+                String[] parsed = data.split(":");
+                int parsedUsed = 0;
+                if (parsed.length < 6) return;
+
+                mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
+                if (parsed.length != 4 + (2 * mPeriodCount)) return;
+
+                mPeriodRxData = new long[mPeriodCount];
+                for(int i=0; i < mPeriodCount; i++) {
+                    mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
+                }
+                mPeriodTxData = new long[mPeriodCount];
+                for(int i=0; i < mPeriodCount; i++) {
+                    mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
+                }
+                mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
+                mPeriodStart = new GregorianCalendar();
+                mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+                mPeriodEnd = new GregorianCalendar();
+                mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+            }
+        }
+
+        long getPeriodRx(int which) {
+            if (DBG) { // TODO - remove
+                Slog.d(TAG, "reading slot "+ which +" with current =" + mCurrentPeriod);
+                for(int x = 0; x<mPeriodCount; x++) {
+                    Slog.d(TAG, "  " + x + " = " + mPeriodRxData[x]);
+                }
+            }
+            synchronized (mParent) {
+                if (which > mPeriodCount) return 0;
+                which = mCurrentPeriod - which;
+                if (which < 0) which += mPeriodCount;
+                return mPeriodRxData[which];
+            }
+        }
+        long getPeriodTx(int which) {
+            synchronized (mParent) {
+                if (which > mPeriodCount) return 0;
+                which = mCurrentPeriod - which;
+                if (which < 0) which += mPeriodCount;
+                return mPeriodTxData[which];
+            }
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump ThrottleService " +
+                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
+                    Binder.getCallingUid());
+            return;
+        }
+        pw.println();
+
+        pw.println("The threshold is " + mPolicyThreshold +
+                ", after which you experince throttling to " +
+                mPolicyThrottleValue + "kbps");
+        pw.println("Current period is " +
+                (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
+                "and ends in " + (mRecorder.getPeriodEnd() - System.currentTimeMillis()) / 1000 +
+                " seconds.");
+        pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
+        for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
+            pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
+                    mRecorder.getPeriodTx(i));
+        }
+    }
+}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3b655fa..bc26fa0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1369,7 +1369,7 @@
                         return;
                     }
                 } else {
-                    procs = service.mLruProcesses;
+                    procs = new ArrayList<ProcessRecord>(service.mLruProcesses);
                 }
             }
             dumpApplicationMemoryUsage(fd, pw, procs, "  ", args);
@@ -10202,7 +10202,7 @@
         return numPers;
     }
 
-    private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
+    static final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, List list, String prefix, String[] args) {
         final boolean isCheckinRequest = scanArgs(args, "--checkin");
         long uptime = SystemClock.uptimeMillis();
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 55840e2..465ff2e 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -818,7 +818,7 @@
 
         final ContentResolver cr = mContext.getContentResolver();
         if (Settings.System.getInt(cr,
-                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) 
+                Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
         {
             final String soundPath = Settings.System.getString(cr,
                 Settings.System.LOW_BATTERY_SOUND);
@@ -972,7 +972,8 @@
         int iconLevel = -1;
         int[] iconList;
 
-        if (!hasService()) {
+        // Display signal strength while in "emergency calls only" mode
+        if (!hasService() && !mServiceState.isEmergencyOnly()) {
             //Slog.d(TAG, "updateSignalStrength: no service");
             if (Settings.System.getInt(mContext.getContentResolver(),
                     Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 48a40fa..6c66559 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -113,6 +113,8 @@
     private String mOperatorNumeric;
     private boolean mIsManualNetworkSelection;
 
+    private boolean mIsEmergencyOnly;
+
     //***** CDMA
     private int mRadioTechnology;
     private boolean mCssIndicator;
@@ -170,6 +172,7 @@
         mCdmaDefaultRoamingIndicator = s.mCdmaDefaultRoamingIndicator;
         mCdmaEriIconIndex = s.mCdmaEriIconIndex;
         mCdmaEriIconMode = s.mCdmaEriIconMode;
+        mIsEmergencyOnly = s.mIsEmergencyOnly;
     }
 
     /**
@@ -190,6 +193,7 @@
         mCdmaDefaultRoamingIndicator = in.readInt();
         mCdmaEriIconIndex = in.readInt();
         mCdmaEriIconMode = in.readInt();
+        mIsEmergencyOnly = in.readInt() != 0;
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -207,6 +211,7 @@
         out.writeInt(mCdmaDefaultRoamingIndicator);
         out.writeInt(mCdmaEriIconIndex);
         out.writeInt(mCdmaEriIconMode);
+        out.writeInt(mIsEmergencyOnly ? 1 : 0);
     }
 
     public int describeContents() {
@@ -250,6 +255,13 @@
     /**
      * @hide
      */
+    public boolean isEmergencyOnly() {
+        return mIsEmergencyOnly;
+    }
+
+    /**
+     * @hide
+     */
     public int getCdmaRoamingIndicator(){
         return this.mCdmaRoamingIndicator;
     }
@@ -330,7 +342,8 @@
                 + ((null == mOperatorAlphaShort) ? 0 : mOperatorAlphaShort.hashCode())
                 + ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode())
                 + mCdmaRoamingIndicator
-                + mCdmaDefaultRoamingIndicator);
+                + mCdmaDefaultRoamingIndicator
+                + (mIsEmergencyOnly ? 1 : 0));
     }
 
     @Override
@@ -359,7 +372,8 @@
                 && equalsHandlesNulls(mSystemId, s.mSystemId)
                 && equalsHandlesNulls(mCdmaRoamingIndicator, s.mCdmaRoamingIndicator)
                 && equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
-                        s.mCdmaDefaultRoamingIndicator));
+                        s.mCdmaDefaultRoamingIndicator)
+                && mIsEmergencyOnly == s.mIsEmergencyOnly);
     }
 
     @Override
@@ -418,7 +432,8 @@
                 + " " + mNetworkId
                 + " " + mSystemId
                 + "RoamInd: " + mCdmaRoamingIndicator
-                + "DefRoamInd: " + mCdmaDefaultRoamingIndicator);
+                + "DefRoamInd: " + mCdmaDefaultRoamingIndicator
+                + "EmergOnly: " + mIsEmergencyOnly);
     }
 
     public void setStateOutOfService() {
@@ -436,6 +451,7 @@
         mCdmaDefaultRoamingIndicator = -1;
         mCdmaEriIconIndex = -1;
         mCdmaEriIconMode = -1;
+        mIsEmergencyOnly = false;
     }
 
     // TODO - can't this be combined with the above func..
@@ -454,6 +470,7 @@
         mCdmaDefaultRoamingIndicator = -1;
         mCdmaEriIconIndex = -1;
         mCdmaEriIconMode = -1;
+        mIsEmergencyOnly = false;
     }
 
     public void setState(int state) {
@@ -464,6 +481,14 @@
         mRoaming = roaming;
     }
 
+
+    /**
+     * @hide
+     */
+    public void setEmergencyOnly(boolean emergencyOnly) {
+        mIsEmergencyOnly = emergencyOnly;
+    }
+
     /**
      * @hide
      */
@@ -542,6 +567,7 @@
         mSystemId = m.getInt("systemId");
         mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator");
         mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
+        mIsEmergencyOnly = m.getBoolean("emergencyOnly");
     }
 
     /**
@@ -563,6 +589,7 @@
         m.putInt("systemId", mSystemId);
         m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator);
         m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
+        m.putBoolean("emergencyOnly", Boolean.valueOf(mIsEmergencyOnly));
     }
 
     //***** CDMA
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index e4fcf6c..50b8eba 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -102,7 +102,6 @@
      * Mark when service state is in emergency call only mode
      */
     private boolean mEmergencyOnly = false;
-    private boolean mNewEmergencyOnly = false;
 
     private RegistrantList gprsAttachedRegistrants = new RegistrantList();
     private RegistrantList gprsDetachedRegistrants = new RegistrantList();
@@ -591,8 +590,8 @@
         if (rule != curSpnRule
                 || !TextUtils.equals(spn, curSpn)
                 || !TextUtils.equals(plmn, curPlmn)) {
-            boolean showSpn = mEmergencyOnly
-                || (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN;
+            boolean showSpn = !mEmergencyOnly
+                && (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN;
             boolean showPlmn =
                 (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN;
 
@@ -672,9 +671,9 @@
                     newSS.setState (regCodeToServiceState(regState));
 
                     if (regState == 10 || regState == 12 || regState == 13 || regState == 14) {
-                        mNewEmergencyOnly = true;
+                        mEmergencyOnly = true;
                     } else {
-                        mNewEmergencyOnly = false;
+                        mEmergencyOnly = false;
                     }
 
                     // LAC and CID are -1 if not avail
@@ -741,6 +740,7 @@
                 roaming = false;
             }
             newSS.setRoaming(roaming);
+            newSS.setEmergencyOnly(mEmergencyOnly);
             pollStateDone();
         }
     }
@@ -886,8 +886,6 @@
 
         boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
 
-        boolean hasEmergencyOnlyChanged = mNewEmergencyOnly != mEmergencyOnly;
-
         // Add an event log when connection state changes
         if (ss.getState() != newSS.getState() || gprsState != newGPRSState) {
             EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE,
@@ -905,8 +903,6 @@
         cellLoc = newCellLoc;
         newCellLoc = tcl;
 
-        mEmergencyOnly = mNewEmergencyOnly;
-
         // Add an event log when network type switched
         // TODO: we may add filtering to reduce the event logged,
         // i.e. check preferred network setting, only switch to 2G, etc
@@ -937,6 +933,8 @@
         if (hasChanged) {
             String operatorNumeric;
 
+            updateSpnDisplay();
+
             phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
                 ss.getOperatorAlphaLong());
 
@@ -1005,10 +1003,6 @@
             phone.notifyServiceStateChanged(ss);
         }
 
-        if (hasChanged || hasEmergencyOnlyChanged) {
-            updateSpnDisplay();
-        }
-
         if (hasGprsAttached) {
             gprsAttachedRegistrants.notifyRegistrants();
         }