Merge change 7402 into donut

* changes:
  Added fade-in out animation for compatible apps  (This CL only add this when the app on the top is in compatibility mode for now. I need some help to do the same   when the closing app is in compatibility mode) Refactored DimAnimator
diff --git a/api/current.xml b/api/current.xml
index a10109c..6a5680d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -111383,6 +111383,144 @@
 >
 </field>
 </class>
+<class name="TextToSpeech.Engine"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="TextToSpeech.Engine"
+ type="android.speech.tts.TextToSpeech.Engine"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="CHECK_VOICE_DATA_BAD_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_FAIL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_MISSING_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_MISSING_VOLUME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHECK_VOICE_DATA_PASS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTS_DEFAULT_STREAM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTS_KEY_PARAM_STREAM"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;streamType&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TTS_KEY_PARAM_UTTERANCE_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;utteranceId&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VOICE_DATA_FILES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;dataFiles&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VOICE_DATA_FILES_INFO"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;dataFilesInfo&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="VOICE_DATA_ROOT_DIRECTORY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;dataRoot&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <interface name="TextToSpeech.OnInitListener"
  abstract="true"
  static="true"
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 1330912..444f222 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.ComponentName;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -784,8 +785,17 @@
      * This hook is called when the user signals the desire to start a search.
      */
     public boolean onSearchRequested() {
-        // not during dialogs, no.
-        return false;
+        final SearchManager searchManager = (SearchManager) mContext
+                .getSystemService(Context.SEARCH_SERVICE);
+
+        // associate search with owner activity if possible (otherwise it will default to
+        // global search).
+        final ComponentName appName = mOwnerActivity == null ? null
+                : mOwnerActivity.getComponentName();
+        final boolean globalSearch = (appName == null);
+        searchManager.startSearch(null, false, appName, null, globalSearch);
+        dismiss();
+        return true;
     }
 
 
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 13eb034..1283b8f 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -337,16 +337,7 @@
         mActivityContext = mSearchable.getActivityContext(getContext());
         
         // show the dialog. this will call onStart().
-        if (!isShowing()) {
-            // First make sure the keyboard is showing (if needed), so that we get the right height
-            // for the dropdown to respect the IME.
-            if (getContext().getResources().getConfiguration().hardKeyboardHidden ==
-                Configuration.HARDKEYBOARDHIDDEN_YES) {
-                InputMethodManager inputManager = (InputMethodManager)
-                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-                        inputManager.showSoftInputUnchecked(0, null);
-            }
-            
+        if (!isShowing()) {            
             // The Dialog uses a ContextThemeWrapper for the context; use this to change the
             // theme out from underneath us, between the global search theme and the in-app
             // search theme. They are identical except that the global search theme does not
@@ -1535,7 +1526,22 @@
         @Override
         public void performCompletion() {
         }
-        
+
+        /**
+         * We override this method to be sure and show the soft keyboard if appropriate when
+         * the TextView has focus.
+         */
+        @Override
+        public void onWindowFocusChanged(boolean hasWindowFocus) {
+            super.onWindowFocusChanged(hasWindowFocus);
+
+            if (hasWindowFocus) {
+                InputMethodManager inputManager = (InputMethodManager)
+                        getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+                inputManager.showSoftInput(this, 0);
+            }
+        }
+                
         /**
          * We override this method so that we can allow a threshold of zero, which ACTV does not.
          */
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 8530c35..a2e0ba0a 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -57,6 +57,9 @@
      *
      * <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
      * the AppWidget meta-data file.
+     *
+     * <p class="note"><b>Note:</b> Updates requested with <code>updatePeriodMillis</code>
+     * will not be delivered more than once every 30 minutes.</p>
      */
     public int updatePeriodMillis;
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 8de938d..a9aa1ee 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -34,6 +34,7 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.util.LongSparseArray;
+import android.view.Display;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -87,6 +88,7 @@
     PluralRules mPluralRule;
     
     private final CompatibilityInfo mCompatibilityInfo;
+    private Display mDefaultDisplay;
 
     private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
         @Override
@@ -1915,6 +1917,24 @@
                 + Integer.toHexString(id));
     }
 
+    /**
+     * Returns the display adjusted for the Resources' metrics.
+     * @hide
+     */
+    public Display getDefaultDisplay(Display defaultDisplay) {
+        if (mDefaultDisplay == null) {
+            if (!mCompatibilityInfo.isScalingRequired() && mCompatibilityInfo.supportsScreen()) {
+                // the app supports the display. just use the default one.
+                mDefaultDisplay = defaultDisplay;
+            } else {
+                // display needs adjustment.
+                mDefaultDisplay = Display.createMetricsBasedDisplay(
+                        defaultDisplay.getDisplayId(), mMetrics);
+            }
+        }
+        return mDefaultDisplay;
+    }
+
     private TypedArray getCachedStyledAttributes(int len) {
         synchronized (mTmpValue) {
             TypedArray attrs = mCachedStyledAttributes;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6ed1ac8..bf6003e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2692,6 +2692,12 @@
         public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
 
         /**
+         * Controls if the protocol buffer version of the protocol will use a multipart request for
+         * attachment uploads. Value must be an integer where non-zero means true. Defaults to 0.
+         */
+        public static final String GMAIL_USE_MULTIPART_PROTOBUF = "gmail_use_multipart_protobuf";
+
+        /**
          * the transcoder URL for mobile devices.
          */
         public static final String TRANSCODER_URL = "mobile_transcoder_url";
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
index 67be6a6..70c7d73 100644
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -49,7 +49,7 @@
 
     private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
     private static final int SEARCH_UI_THREAD_PRIORITY =
-        android.os.Process.THREAD_PRIORITY_FOREGROUND;
+        android.os.Process.THREAD_PRIORITY_DEFAULT;
 
     // Takes no arguments
     private static final int MSG_INIT = 0;
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index a2e70b8..db9f8d852 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -113,43 +113,131 @@
     /**
      * Internal constants for the TTS functionality
      *
-     * {@hide}
      */
     public class Engine {
         // default values for a TTS engine when settings are not found in the provider
+        /**
+         * {@hide}
+         */
         public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
+        /**
+         * {@hide}
+         */
         public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
+        /**
+         * {@hide}
+         */
         public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
+        /**
+         * {@hide}
+         */
         public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
 
         // default values for rendering
         public static final int TTS_DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
 
         // return codes for a TTS engine's check data activity
+        /**
+         * Indicates success when checking the installation status of the resources used by the
+         * text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+         */
         public static final int CHECK_VOICE_DATA_PASS = 1;
+        /**
+         * Indicates failure when checking the installation status of the resources used by the
+         * text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+         */
         public static final int CHECK_VOICE_DATA_FAIL = 0;
+        /**
+         * Indicates erroneous data when checking the installation status of the resources used by
+         * the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+         */
         public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
+        /**
+         * Indicates missing resources when checking the installation status of the resources used
+         * by the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+         */
         public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
-        public static final int CHECK_VOICE_DATA_MISSING_DATA_NO_SDCARD = -3;
+        /**
+         * Indicates missing storage volume when checking the installation status of the resources
+         * used by the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent.
+         */
+        public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
 
         // return codes for a TTS engine's check data activity
+        /**
+         * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+         * the text-to-speech engine specifies the path to its resources.
+         */
         public static final String VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
+        /**
+         * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+         * the text-to-speech engine specifies the file names of its resources under the
+         * resource path.
+         */
         public static final String VOICE_DATA_FILES = "dataFiles";
+        /**
+         * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+         * the text-to-speech engine specifies the locale associated with each resource file.
+         */
         public static final String VOICE_DATA_FILES_INFO = "dataFilesInfo";
 
-        // keys for the parameters passed with speak commands
+        // keys for the parameters passed with speak commands. Hidden keys are used internally
+        // to maintain engine state for each TextToSpeech instance.
+        /**
+         * {@hide}
+         */
         public static final String TTS_KEY_PARAM_RATE = "rate";
+        /**
+         * {@hide}
+         */
         public static final String TTS_KEY_PARAM_LANGUAGE = "language";
+        /**
+         * {@hide}
+         */
         public static final String TTS_KEY_PARAM_COUNTRY = "country";
+        /**
+         * {@hide}
+         */
         public static final String TTS_KEY_PARAM_VARIANT = "variant";
+        /**
+         * Parameter key to specify the audio stream type to be used when speaking text
+         * or playing back a file.
+         */
         public static final String TTS_KEY_PARAM_STREAM = "streamType";
+        /**
+         * Parameter key to identify an utterance in the completion listener after text has been
+         * spoken, a file has been played back or a silence duration has elapsed.
+         */
         public static final String TTS_KEY_PARAM_UTTERANCE_ID = "utteranceId";
+
+        // key positions in the array of cached parameters
+        /**
+         * {@hide}
+         */
         protected static final int TTS_PARAM_POSITION_RATE = 0;
+        /**
+         * {@hide}
+         */
         protected static final int TTS_PARAM_POSITION_LANGUAGE = 2;
+        /**
+         * {@hide}
+         */
         protected static final int TTS_PARAM_POSITION_COUNTRY = 4;
+        /**
+         * {@hide}
+         */
         protected static final int TTS_PARAM_POSITION_VARIANT = 6;
+        /**
+         * {@hide}
+         */
         protected static final int TTS_PARAM_POSITION_STREAM = 8;
+        /**
+         * {@hide}
+         */
         protected static final int TTS_PARAM_POSITION_UTTERANCE_ID = 10;
+        /**
+         * {@hide}
+         */
         protected static final int TTS_NB_CACHED_PARAMS = 6;
     }
 
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 09ebeed5..5551f64 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -117,5 +117,32 @@
     
     private static final Object mStaticInit = new Object();
     private static boolean mInitialized = false;
+
+    /**
+     * Returns a display object which uses the metric's width/height instead.
+     * @hide
+     */
+    public static Display createMetricsBasedDisplay(int displayId, DisplayMetrics metrics) {
+        return new CompatibleDisplay(displayId, metrics);
+    }
+
+    private static class CompatibleDisplay extends Display {
+        private final DisplayMetrics mMetrics;
+
+        private CompatibleDisplay(int displayId, DisplayMetrics metrics) {
+            super(displayId);
+            mMetrics = metrics;
+        }
+
+        @Override
+        public int getWidth() {
+            return mMetrics.widthPixels;
+        }
+
+        @Override
+        public int getHeight() {
+            return mMetrics.heightPixels;
+        }
+    }
 }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d7457a0..576c8c1 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -358,6 +358,8 @@
     private class LocalWindowManager implements WindowManager {
         LocalWindowManager(WindowManager wm) {
             mWindowManager = wm;
+            mDefaultDisplay = mContext.getResources().getDefaultDisplay(
+                    mWindowManager.getDefaultDisplay());
         }
 
         public final void addView(View view, ViewGroup.LayoutParams params) {
@@ -420,10 +422,12 @@
         }
 
         public Display getDefaultDisplay() {
-            return mWindowManager.getDefaultDisplay();
+            return mDefaultDisplay;
         }
         
-        WindowManager mWindowManager;
+        private final WindowManager mWindowManager;
+
+        private final Display mDefaultDisplay;
     }
 
     /**
diff --git a/core/java/android/webkit/GearsPermissionsManager.java b/core/java/android/webkit/GearsPermissionsManager.java
index 876f3d7..e70e449 100644
--- a/core/java/android/webkit/GearsPermissionsManager.java
+++ b/core/java/android/webkit/GearsPermissionsManager.java
@@ -55,6 +55,8 @@
     // The Gears permissions db schema version table.
     private final static String GEARS_SCHEMA_VERSION_TABLE_NAME =
         "VersionInfo";
+    // The Gears permission value that denotes "allow access to location".
+    private static final int GEARS_ALLOW_LOCATION_ACCESS = 1;
     // The shared pref name.
     private static final String LAST_KNOWN_LOCATION_SETTING =
         "lastKnownLocationSystemSetting";
@@ -119,8 +121,14 @@
     }
 
     private void setGearsPermissionForGoogleDomains(int systemPermission) {
-        // Transform the system permission into a Gears permission
-        int gearsPermission = (systemPermission == 1 ? 1 : 2);
+        // Transform the system permission into a boolean flag. When this
+        // flag is true, it means the origins in gGearsWhiteList are added
+        // to the Gears location permission table with permission 1 (allowed).
+        // When the flag is false, the origins in gGearsWhiteList are removed
+        // from the Gears location permission table. Next time the user
+        // navigates to one of these origins, she will see the normal Gears
+        // permission prompt.
+        boolean addToGearsLocationTable = (systemPermission == 1 ? true : false);
         // Build the path to the Gears library.
 
         File file = new File(mGearsPath).getParentFile();
@@ -132,6 +140,13 @@
                 + GEARS_DATABASE_DIR + File.separator + GEARS_DATABASE_FILE);
         // Remember whether or not we need to create the LocationAccess table.
         boolean needToCreateTables = !file.exists();
+        // If the database file does not yet exist and the system location
+        // setting says that the Gears origins need to be removed from the
+        // location permission table, it means that we don't actually need
+        // to do anything at all.
+        if (needToCreateTables && !addToGearsLocationTable) {
+            return;
+        }
         // Try opening the Gears database.
         SQLiteDatabase permissions;
         try {
@@ -177,14 +192,21 @@
                         schema);
             }
 
-            ContentValues permissionValues = new ContentValues();
+            if (addToGearsLocationTable) {
+                ContentValues permissionValues = new ContentValues();
 
-            for (String url : sGearsWhiteList) {
-                permissionValues.put("Name", url);
-                permissionValues.put("Value", gearsPermission);
-                permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null,
-                        permissionValues);
-                permissionValues.clear();
+                for (String url : sGearsWhiteList) {
+                    permissionValues.put("Name", url);
+                    permissionValues.put("Value", GEARS_ALLOW_LOCATION_ACCESS);
+                    permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null,
+                            permissionValues);
+                    permissionValues.clear();
+                }
+            } else {
+                for (String url : sGearsWhiteList) {
+                    permissions.delete(GEARS_LOCATION_ACCESS_TABLE_NAME, "Name=?",
+                            new String[] { url });
+                }
             }
             // Commit the transaction.
             permissions.setTransactionSuccessful();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 39360cd..474fa82 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -38,6 +38,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Vector;
 import java.util.regex.Pattern;
@@ -72,7 +73,12 @@
     private static final int HTTP_NOT_FOUND = 404;
     private static final int HTTP_PROXY_AUTH = 407;
 
-    private static final String CERT_MIMETYPE = "application/x-x509-ca-cert";
+    private static HashSet<String> sCertificateMimeTypeMap;
+    static {
+        sCertificateMimeTypeMap = new HashSet<String>();
+        sCertificateMimeTypeMap.add("application/x-x509-ca-cert");
+        sCertificateMimeTypeMap.add("application/x-pkcs12");
+    }
 
     private static int sNativeLoaderCount;
 
@@ -318,7 +324,17 @@
             if (mMimeType.equalsIgnoreCase("text/plain") ||
                     mMimeType.equalsIgnoreCase("application/octet-stream")) {
 
-                String newMimeType = guessMimeTypeFromExtension();
+                // for attachment, use the filename in the Content-Disposition
+                // to guess the mimetype
+                String contentDisposition = headers.getContentDisposition();
+                String url = null;
+                if (contentDisposition != null) {
+                    url = URLUtil.parseContentDisposition(contentDisposition);
+                }
+                if (url == null) {
+                    url = mUrl;
+                }
+                String newMimeType = guessMimeTypeFromExtension(url);
                 if (newMimeType != null) {
                     mMimeType = newMimeType;
                 }
@@ -936,7 +952,7 @@
 
     // This commits the headers without checking the response status code.
     private void commitHeaders() {
-        if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+        if (mIsMainPageLoader && sCertificateMimeTypeMap.contains(mMimeType)) {
             // In the case of downloading certificate, we will save it to the
             // Keystore in commitLoad. Do not call webcore.
             return;
@@ -982,7 +998,7 @@
     private void commitLoad() {
         if (mCancelled) return;
 
-        if (mIsMainPageLoader && CERT_MIMETYPE.equals(mMimeType)) {
+        if (mIsMainPageLoader && sCertificateMimeTypeMap.contains(mMimeType)) {
             // In the case of downloading certificate, we will save it to the
             // Keystore and stop the current loading so that it will not
             // generate a new history page
@@ -1409,7 +1425,7 @@
             // of frames. If no content-type was specified, it is fine to
             // default to text/html.
             mMimeType = "text/html";
-            String newMimeType = guessMimeTypeFromExtension();
+            String newMimeType = guessMimeTypeFromExtension(mUrl);
             if (newMimeType != null) {
                 mMimeType =  newMimeType;
             }
@@ -1419,15 +1435,15 @@
     /**
      * guess MIME type based on the file extension.
      */
-    private String guessMimeTypeFromExtension() {
+    private String guessMimeTypeFromExtension(String url) {
         // PENDING: need to normalize url
         if (WebView.LOGV_ENABLED) {
-            Log.v(LOGTAG, "guessMimeTypeFromExtension: mURL = " + mUrl);
+            Log.v(LOGTAG, "guessMimeTypeFromExtension: url = " + url);
         }
 
         String mimeType =
                 MimeTypeMap.getSingleton().getMimeTypeFromExtension(
-                        MimeTypeMap.getFileExtensionFromUrl(mUrl));
+                        MimeTypeMap.getFileExtensionFromUrl(url));
 
         if (mimeType != null) {
             // XXX: Until the servers send us either correct xhtml or
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 85c2275..fdbc692 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -335,6 +335,7 @@
             sMimeTypeMap.loadEntry("application/x-object", "o", false);
             sMimeTypeMap.loadEntry("application/x-oz-application", "oza", 
                     false);
+            sMimeTypeMap.loadEntry("application/x-pkcs12", "p12", false);
             sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r", 
                     false);
             sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl", false);
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index d6ac3e9..9889fe9 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -348,7 +348,7 @@
      * This header provides a filename for content that is going to be
      * downloaded to the file system. We only support the attachment type.
      */
-    private static String parseContentDisposition(String contentDisposition) {
+    static String parseContentDisposition(String contentDisposition) {
         try {
             Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
             if (m.find()) {
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 7e55c78..bdecf62 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -85,7 +85,8 @@
     public final void filter(CharSequence constraint, FilterListener listener) {
         synchronized (mLock) {
             if (mThreadHandler == null) {
-                HandlerThread thread = new HandlerThread(THREAD_NAME);
+                HandlerThread thread = new HandlerThread(
+                        THREAD_NAME, android.os.Process.THREAD_PRIORITY_BACKGROUND);
                 thread.start();
                 mThreadHandler = new RequestHandler(thread.getLooper());
             }
diff --git a/core/res/res/values-he-rIL/donottranslate-cldr.xml b/core/res/res/values-he-rIL/donottranslate-cldr.xml
index e3feb1e..3378ed7 100644
--- a/core/res/res/values-he-rIL/donottranslate-cldr.xml
+++ b/core/res/res/values-he-rIL/donottranslate-cldr.xml
@@ -61,20 +61,20 @@
     <string name="day_of_week_long_friday">יום שישי</string>
     <string name="day_of_week_long_saturday">יום שבת</string>
 
-    <string name="day_of_week_medium_sunday">יום א'</string>
-    <string name="day_of_week_medium_monday">יום ב'</string>
-    <string name="day_of_week_medium_tuesday">יום ג'</string>
-    <string name="day_of_week_medium_wednesday">יום ד'</string>
-    <string name="day_of_week_medium_thursday">יום ה'</string>
-    <string name="day_of_week_medium_friday">יום ו'</string>
+    <string name="day_of_week_medium_sunday">יום א\'</string>
+    <string name="day_of_week_medium_monday">יום ב\'</string>
+    <string name="day_of_week_medium_tuesday">יום ג\'</string>
+    <string name="day_of_week_medium_wednesday">יום ד\'</string>
+    <string name="day_of_week_medium_thursday">יום ה\'</string>
+    <string name="day_of_week_medium_friday">יום ו\'</string>
     <string name="day_of_week_medium_saturday">שבת</string>
 
-    <string name="day_of_week_short_sunday">יום א'</string>
-    <string name="day_of_week_short_monday">יום ב'</string>
-    <string name="day_of_week_short_tuesday">יום ג'</string>
-    <string name="day_of_week_short_wednesday">יום ד'</string>
-    <string name="day_of_week_short_thursday">יום ה'</string>
-    <string name="day_of_week_short_friday">יום ו'</string>
+    <string name="day_of_week_short_sunday">יום א\'</string>
+    <string name="day_of_week_short_monday">יום ב\'</string>
+    <string name="day_of_week_short_tuesday">יום ג\'</string>
+    <string name="day_of_week_short_wednesday">יום ד\'</string>
+    <string name="day_of_week_short_thursday">יום ה\'</string>
+    <string name="day_of_week_short_friday">יום ו\'</string>
     <string name="day_of_week_short_saturday">שבת</string>
 
     <string name="day_of_week_shortest_sunday">א</string>
diff --git a/core/res/res/values-pt-rBR/donottranslate-cldr.xml b/core/res/res/values-pt-rBR/donottranslate-cldr.xml
index 4729055..1111658 100644
--- a/core/res/res/values-pt-rBR/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rBR/donottranslate-cldr.xml
@@ -95,7 +95,7 @@
     <string name="hour_minute_ampm">%-l:%M %p</string>
     <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
     <string name="twelve_hour_time_format">h:mm a</string>
-    <string name="twenty_four_hour_time_format">H'h'mm</string>
+    <string name="twenty_four_hour_time_format">H\'h\'mm</string>
     <string name="numeric_date">%d/%m/%Y</string>
     <string name="numeric_date_format">dd/MM/yyyy</string>
     <string name="numeric_date_template">"%s/%s/%s"</string>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index f38a2d0..197cb6e 100644
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -95,7 +95,7 @@
     <string name="hour_minute_ampm">%-l:%M %p</string>
     <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
     <string name="twelve_hour_time_format">h:mm a</string>
-    <string name="twenty_four_hour_time_format">H'h'mm</string>
+    <string name="twenty_four_hour_time_format">H\'h\'mm</string>
     <string name="numeric_date">%d/%m/%Y</string>
     <string name="numeric_date_format">dd/MM/yyyy</string>
     <string name="numeric_date_template">"%s/%s/%s"</string>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 4729055..1111658 100644
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -95,7 +95,7 @@
     <string name="hour_minute_ampm">%-l:%M %p</string>
     <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
     <string name="twelve_hour_time_format">h:mm a</string>
-    <string name="twenty_four_hour_time_format">H'h'mm</string>
+    <string name="twenty_four_hour_time_format">H\'h\'mm</string>
     <string name="numeric_date">%d/%m/%Y</string>
     <string name="numeric_date_format">dd/MM/yyyy</string>
     <string name="numeric_date_template">"%s/%s/%s"</string>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 72ff8b6..6f2d342 100644
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -133,8 +133,8 @@
     <string name="same_month_md1_time1_md2_time2">%3$s %2$s %5$s - %8$s %7$s %10$s</string>
     <string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s %3$s %2$s %5$s - %6$s %8$s %7$s %10$s</string>
     <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s %3$s %2$s %5$s - %6$s %8$s %7$s %10$s</string>
-    <string name="same_year_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - 'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
-    <string name="same_month_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - 'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
+    <string name="same_year_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - \'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
+    <string name="same_month_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - \'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
     <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s %2$s %4$s %5$s - %6$s, %8$s %7$s %9$s %10$s</string>
     <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s %2$s %4$s %5$s - %6$s, %8$s %7$s %9$s %10$s</string>
     <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s</string>
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index aea3f0b..649787e 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -23,7 +23,7 @@
 	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
 	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
 	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-	$(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/Silence.ogg \
+	$(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/notifications/Silence.ogg \
 	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
 	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
 	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk
index 8c8fc32..fc1e921 100644
--- a/data/sounds/OriginalAudio.mk
+++ b/data/sounds/OriginalAudio.mk
@@ -22,7 +22,7 @@
 	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
 	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
 	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-	$(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/Silence.ogg \
+	$(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/notifications/Silence.ogg \
 	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
 	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
 	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 4247483..64cdb5b 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -84,6 +84,7 @@
             mNbChannels = DEFAULT_TTS_NB_CHANNELS;
             mBufferSize = DEFAULT_TTS_BUFFERSIZE;
             mBuffer = new int8_t[mBufferSize];
+            memset(mBuffer, 0, mBufferSize);
         }
 
         ~SynthProxyJniStorage() {
@@ -194,6 +195,7 @@
             prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
             if (pJniData->mAudioOut) {
                 pJniData->mAudioOut->write(wav, bufferSize);
+                memset(wav, 0, bufferSize);
                 //LOGV("AudioTrack wrote: %d bytes", bufferSize);
             } else {
                 LOGE("Can't play, null audiotrack");
@@ -208,6 +210,7 @@
         }
         if (bufferSize > 0){
             fwrite(wav, 1, bufferSize, pForAfter->outputFile);
+            memset(wav, 0, bufferSize);
         }
     }
     // Future update:
@@ -473,6 +476,7 @@
 
     unsigned int unique_identifier;
 
+    memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
     result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
             pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
 
@@ -554,6 +558,7 @@
 
     if (pSynthData->mNativeSynthInterface) {
         const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
+        memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
         result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString,
                 pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
         env->ReleaseStringUTFChars(textJavaString, textNativeString);
@@ -575,12 +580,12 @@
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
 
-    if (pSynthData->mNativeSynthInterface) {
-        result = pSynthData->mNativeSynthInterface->stop();
-    }
     if (pSynthData->mAudioOut) {
         pSynthData->mAudioOut->stop();
     }
+    if (pSynthData->mNativeSynthInterface) {
+        result = pSynthData->mNativeSynthInterface->stop();
+    }
 
     return result;
 }
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 4d25183..7c4996e 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -340,6 +340,8 @@
         Log.i("TTS service received", text);
         if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
             stop(callingApp);
+        } else if (queueMode == 2) {
+            stopAll(callingApp);
         }
         mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT));
         if (!mIsSpeaking) {
@@ -364,6 +366,8 @@
             ArrayList<String> params) {
         if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
             stop(callingApp);
+        } else if (queueMode == 2) {
+            stopAll(callingApp);
         }
         mSpeechQueue.add(new SpeechItem(callingApp, earcon, params, SpeechItem.EARCON));
         if (!mIsSpeaking) {
@@ -373,7 +377,7 @@
     }
 
     /**
-     * Stops all speech output and removes any utterances still in the queue.
+     * Stops all speech output and removes any utterances still in the queue for the calling app.
      */
     private int stop(String callingApp) {
         int result = TextToSpeech.TTS_ERROR;
@@ -389,15 +393,20 @@
                         mSpeechQueue.remove(i);
                     }
                 }
-
-                result = nativeSynth.stop();
-                mIsSpeaking = false;
-                if (mPlayer != null) {
-                    try {
-                        mPlayer.stop();
-                    } catch (IllegalStateException e) {
-                        // Do nothing, the player is already stopped.
+                if ((mCurrentSpeechItem != null) &&
+                     mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
+                    result = nativeSynth.stop();
+                    if (mPlayer != null) {
+                        try {
+                            mPlayer.stop();
+                        } catch (IllegalStateException e) {
+                            // Do nothing, the player is already stopped.
+                        }
                     }
+                    mIsSpeaking = false;
+                    mCurrentSpeechItem = null;
+                } else {
+                    result = TextToSpeech.TTS_SUCCESS;
                 }
                 Log.i("TTS", "Stopped");
             }
@@ -407,7 +416,55 @@
         } finally {
             // This check is needed because finally will always run; even if the
             // method returns somewhere in the try block.
-            mCurrentSpeechItem = null;
+            if (speechQueueAvailable) {
+                speechQueueLock.unlock();
+            }
+            return result;
+        }
+    }
+
+
+
+    /**
+     * Stops all speech output and removes any utterances still in the queue globally.
+     */
+    private int stopAll(String callingApp) {
+        int result = TextToSpeech.TTS_ERROR;
+        boolean speechQueueAvailable = false;
+        try{
+            // If the queue is locked for more than 1 second,
+            // something has gone very wrong with processSpeechQueue.
+            speechQueueAvailable = speechQueueLock.tryLock(1000, TimeUnit.MILLISECONDS);
+            if (speechQueueAvailable) {
+                for (int i = mSpeechQueue.size() - 1; i > -1; i--){
+                    if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){
+                        mSpeechQueue.remove(i);
+                    }
+                }
+                if ((mCurrentSpeechItem != null) &&
+                    ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
+                      mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
+                    result = nativeSynth.stop();
+                    if (mPlayer != null) {
+                        try {
+                            mPlayer.stop();
+                        } catch (IllegalStateException e) {
+                            // Do nothing, the player is already stopped.
+                        }
+                    }
+                    mIsSpeaking = false;
+                    mCurrentSpeechItem = null;
+                } else {
+                    result = TextToSpeech.TTS_SUCCESS;
+                }
+                Log.i("TTS", "Stopped all");
+            }
+        } catch (InterruptedException e) {
+          Log.e("TTS stopAll", "tryLock interrupted");
+          e.printStackTrace();
+        } finally {
+            // This check is needed because finally will always run; even if the
+            // method returns somewhere in the try block.
             if (speechQueueAvailable) {
                 speechQueueLock.unlock();
             }
@@ -430,7 +487,6 @@
         if (utteranceId.length() > 0){
             dispatchUtteranceCompletedCallback(utteranceId, callingApp);
         }
-        mCurrentSpeechItem = null;
         processSpeechQueue();
     }
 
@@ -466,7 +522,6 @@
                     if (utteranceId.length() > 0){
                         dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
                     }
-                    mCurrentSpeechItem = null;
                     processSpeechQueue();
                 }
             }
@@ -531,13 +586,12 @@
                     // This check is needed because finally will always run;
                     // even if the
                     // method returns somewhere in the try block.
-                    if (synthAvailable) {
-                        synthesizerLock.unlock();
-                    }
                     if (utteranceId.length() > 0){
                         dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
                     }
-                    mCurrentSpeechItem = null;
+                    if (synthAvailable) {
+                        synthesizerLock.unlock();
+                    }
                     processSpeechQueue();
                 }
             }
@@ -595,13 +649,12 @@
                     // This check is needed because finally will always run;
                     // even if the
                     // method returns somewhere in the try block.
-                    if (synthAvailable) {
-                        synthesizerLock.unlock();
-                    }
                     if (utteranceId.length() > 0){
                         dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
                     }
-                    mCurrentSpeechItem = null;
+                    if (synthAvailable) {
+                        synthesizerLock.unlock();
+                    }
                     processSpeechQueue();
                 }
             }
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 131e156..78db6f9 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -68,6 +68,7 @@
 
     private static final String SETTINGS_FILENAME = "appwidgets.xml";
     private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
+    private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
 
     /*
      * When identifying a Host or Provider based on the calling process, use the uid field.
@@ -629,9 +630,12 @@
                 Binder.restoreCallingIdentity(token);
             }
             if (!alreadyRegistered) {
+                long period = p.info.updatePeriodMillis;
+                if (period < MIN_UPDATE_PERIOD) {
+                    period = MIN_UPDATE_PERIOD;
+                }
                 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        SystemClock.elapsedRealtime() + p.info.updatePeriodMillis,
-                        p.info.updatePeriodMillis, p.broadcast);
+                        SystemClock.elapsedRealtime() + period, period, p.broadcast);
             }
         }
     }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 01394ad..b4754b6 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -192,6 +192,7 @@
     WifiService(Context context, WifiStateTracker tracker) {
         mContext = context;
         mWifiStateTracker = tracker;
+        mWifiStateTracker.enableRssiPolling(true);
         mBatteryStats = BatteryStatsService.getService();
         
         /*
@@ -1560,9 +1561,11 @@
                 mAlarmManager.cancel(mIdleIntent);
                 mDeviceIdle = false;
                 mScreenOff = false;
+                mWifiStateTracker.enableRssiPolling(true);
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 Log.d(TAG, "ACTION_SCREEN_OFF");
                 mScreenOff = true;
+                mWifiStateTracker.enableRssiPolling(false);
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND the "stay on while plugged in" setting doesn't match the
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
index ecc8dfe..4e5f7a9 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
@@ -93,8 +93,8 @@
         Context appContext = si.getActivityContext(mContext);
         assertNotNull(appContext);
         MoreAsserts.assertNotEqual(appContext, mContext);
-        assertEquals("Android Search", appContext.getString(si.getHintId()));
-        assertEquals("Google", appContext.getString(si.getLabelId()));
+        assertEquals("Quick Search Box", appContext.getString(si.getHintId()));
+        assertEquals("Quick Search Box", appContext.getString(si.getLabelId()));
     }
     
     /**
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 63687b3..3aa31bf 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -239,6 +239,7 @@
     
     private boolean mIsScanModeActive;
     private boolean mIsScanModeSetDueToAHiddenNetwork;
+    private boolean mEnableRssiPolling;
 
     // Wi-Fi run states:
     private static final int RUN_STATE_STARTING = 1;
@@ -338,6 +339,7 @@
     private void setSupplicantState(SupplicantState state) {
         mWifiInfo.setSupplicantState(state);
         updateNetworkInfo();
+        checkPollTimer();
     }
 
     public SupplicantState getSupplicantState() {
@@ -352,6 +354,7 @@
     private void setSupplicantState(String stateName) {
         mWifiInfo.setSupplicantState(stateName);
         updateNetworkInfo();
+        checkPollTimer();
     }
 
     /**
@@ -540,8 +543,10 @@
      * Set the interval timer for polling connection information
      * that is not delivered asynchronously.
      */
-    private synchronized void setPollTimer () {
-        if (!hasMessages(EVENT_POLL_INTERVAL)) {
+    private synchronized void checkPollTimer() {
+        if (mEnableRssiPolling &&
+                mWifiInfo.getSupplicantState() == SupplicantState.COMPLETED &&
+                !hasMessages(EVENT_POLL_INTERVAL)) {
             sendEmptyMessageDelayed(EVENT_POLL_INTERVAL, POLL_STATUS_INTERVAL_MSECS);
         }
     }
@@ -637,6 +642,13 @@
         setBluetoothScanMode(isBluetoothPlaying);
     }
 
+    public void enableRssiPolling(boolean enable) {
+        if (mEnableRssiPolling != enable) {
+            mEnableRssiPolling = enable;
+            checkPollTimer();
+        }
+    }
+
     @Override
     public void releaseWakeLock() {
         if (mReleaseWakeLockCallback != null) {
@@ -1022,9 +1034,7 @@
             case EVENT_POLL_INTERVAL:
                 if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
                     requestPolledInfo(mWifiInfo);
-                    if (mWifiInfo.getSupplicantState() == SupplicantState.COMPLETED) {
-                        setPollTimer();
-                    }
+                    checkPollTimer();
                 }
                 break;
             
@@ -1163,7 +1173,7 @@
     }
 
     private void configureInterface() {
-        setPollTimer();
+        checkPollTimer();
         mLastSignalLevel = -1;
         if (!mUseStaticIp) {
             if (!mHaveIpAddress && !mObtainingIpAddress) {