Merge change 8966 into donut

* changes:
  Add tests for android.net.vpn.
diff --git a/api/current.xml b/api/current.xml
index 5350b3e..e0ea966 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -32173,39 +32173,6 @@
  visibility="public"
 >
 </field>
-<field name="ACTION_TTS_CHECK_TTS_DATA"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.CHECK_TTS_DATA&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_TTS_INSTALL_TTS_DATA"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.INSTALL_TTS_DATA&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="ACTION_TTS_QUEUE_PROCESSING_COMPLETED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.TTS_QUEUE_PROCESSING_COMPLETED&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ACTION_UID_REMOVED"
  type="java.lang.String"
  transient="false"
@@ -79989,6 +79956,19 @@
  visibility="public"
 >
 </method>
+<method name="setReferenceCounted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="refCounted" type="boolean">
+</parameter>
+</method>
 </class>
 <class name="WifiManager.WifiLock"
  extends="java.lang.Object"
@@ -111721,7 +111701,18 @@
 <parameter name="filename" type="java.lang.String">
 </parameter>
 </method>
-<field name="TTS_ERROR"
+<field name="ACTION_TTS_QUEUE_PROCESSING_COMPLETED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR"
  type="int"
  transient="false"
  volatile="false"
@@ -111732,7 +111723,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_LANG_AVAILABLE"
+<field name="LANG_AVAILABLE"
  type="int"
  transient="false"
  volatile="false"
@@ -111743,7 +111734,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_LANG_COUNTRY_AVAILABLE"
+<field name="LANG_COUNTRY_AVAILABLE"
  type="int"
  transient="false"
  volatile="false"
@@ -111754,7 +111745,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_LANG_COUNTRY_VAR_AVAILABLE"
+<field name="LANG_COUNTRY_VAR_AVAILABLE"
  type="int"
  transient="false"
  volatile="false"
@@ -111765,7 +111756,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_LANG_MISSING_DATA"
+<field name="LANG_MISSING_DATA"
  type="int"
  transient="false"
  volatile="false"
@@ -111776,7 +111767,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_LANG_NOT_SUPPORTED"
+<field name="LANG_NOT_SUPPORTED"
  type="int"
  transient="false"
  volatile="false"
@@ -111787,7 +111778,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_QUEUE_ADD"
+<field name="QUEUE_ADD"
  type="int"
  transient="false"
  volatile="false"
@@ -111798,7 +111789,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_QUEUE_FLUSH"
+<field name="QUEUE_FLUSH"
  type="int"
  transient="false"
  volatile="false"
@@ -111809,7 +111800,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_SUCCESS"
+<field name="SUCCESS"
  type="int"
  transient="false"
  volatile="false"
@@ -111837,6 +111828,28 @@
  visibility="public"
 >
 </constructor>
+<field name="ACTION_CHECK_TTS_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.tts.engine.CHECK_TTS_DATA&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_INSTALL_TTS_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.tts.engine.INSTALL_TTS_DATA&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CHECK_VOICE_DATA_BAD_DATA"
  type="int"
  transient="false"
@@ -111892,7 +111905,7 @@
  visibility="public"
 >
 </field>
-<field name="TTS_DEFAULT_STREAM"
+<field name="DEFAULT_STREAM"
  type="int"
  transient="false"
  volatile="false"
@@ -111903,29 +111916,7 @@
  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"
+<field name="EXTRA_VOICE_DATA_FILES"
  type="java.lang.String"
  transient="false"
  volatile="false"
@@ -111936,7 +111927,7 @@
  visibility="public"
 >
 </field>
-<field name="VOICE_DATA_FILES_INFO"
+<field name="EXTRA_VOICE_DATA_FILES_INFO"
  type="java.lang.String"
  transient="false"
  volatile="false"
@@ -111947,7 +111938,7 @@
  visibility="public"
 >
 </field>
-<field name="VOICE_DATA_ROOT_DIRECTORY"
+<field name="EXTRA_VOICE_DATA_ROOT_DIRECTORY"
  type="java.lang.String"
  transient="false"
  volatile="false"
@@ -111958,6 +111949,28 @@
  visibility="public"
 >
 </field>
+<field name="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="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>
 </class>
 <interface name="TextToSpeech.OnInitListener"
  abstract="true"
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3aeac53..447512a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1085,6 +1085,7 @@
             reply.writeInt(result);
             return true;
         }
+        
         case KILL_APPLICATION_WITH_UID_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
@@ -1093,6 +1094,14 @@
             reply.writeNoException();
             return true;
         }
+        
+        case CLOSE_SYSTEM_DIALOGS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String reason = data.readString();
+            closeSystemDialogs(reason);
+            reply.writeNoException();
+            return true;
+        }
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -2376,6 +2385,7 @@
         data.recycle();
         return result;
     }
+    
     public void killApplicationWithUid(String pkg, int uid) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2387,6 +2397,17 @@
         data.recycle();
         reply.recycle();
     }
+    
+    public void closeSystemDialogs(String reason) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(reason);
+        mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
         
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b1b5282..f6ef549 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -268,7 +268,9 @@
             throws RemoteException;
 
     public void killApplicationWithUid(String pkg, int uid) throws RemoteException;
-        
+    
+    public void closeSystemDialogs(String reason) throws RemoteException;
+    
     /*
      * Private non-Binder interfaces
      */
@@ -424,4 +426,5 @@
     int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
     int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
     int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
+    int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
 }
diff --git a/core/java/android/app/IActivityWatcher.aidl b/core/java/android/app/IActivityWatcher.aidl
index 5d36e3f..6737545 100644
--- a/core/java/android/app/IActivityWatcher.aidl
+++ b/core/java/android/app/IActivityWatcher.aidl
@@ -23,4 +23,5 @@
  */
 oneway interface IActivityWatcher {
     void activityResuming(int activityId);
+    void closingSystemDialogs(String reason);
 }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index e991bc6..fcfbd17 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1297,6 +1297,9 @@
             if (mGlobalSearchMode) {
                 launchGlobalSearchIntent(intent);
             } else {
+                // If the intent was created from a suggestion, it will always have an explicit
+                // component here.
+                Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
                 getContext().startActivity(intent);
                 // If the search switches to a different activity,
                 // SearchDialogWrapper#performActivityResuming
@@ -1338,7 +1341,6 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         setBrowserApplicationId(intent);
 
-        if (DBG) Log.d(LOG_TAG, "Launching intent " + intent.toURI() + " as " + packageName);
         startActivityInPackage(intent, packageName);
     }
 
@@ -1379,6 +1381,7 @@
             String resultWho = null;
             int requestCode = -1;
             boolean onlyIfNeeded = false;
+            Log.i(LOG_TAG, "Starting (uid " + uid + ", " + packageName + ") " + intent.toURI());
             int result = ActivityManagerNative.getDefault().startActivityInPackage(
                     uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded);
             checkStartActivityResult(result, intent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 29ec71e..c62d66b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1683,53 +1683,7 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_REBOOT =
             "android.intent.action.REBOOT";
-    /**
-     * Broadcast Action: Triggers the platform Text-To-Speech engine to
-     * start the activity that installs the resource files on the device
-     * that are required for TTS to be operational. Since the installation
-     * of the data can be interrupted or declined by the user, the application
-     * shouldn't expect successful installation upon return from that intent,
-     * and if need be, should check installation status with 
-     * {@link #ACTION_TTS_CHECK_TTS_DATA}.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_TTS_INSTALL_TTS_DATA =
-            "android.intent.action.INSTALL_TTS_DATA";
 
-    /**
-     * Broadcast Action: Starts the activity from the platform Text-To-Speech
-     * engine to verify the proper installation and availability of the
-     * resource files on the system. Upon completion, the activity will
-     * return one of the following codes: 
-     * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_PASS},
-     * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_FAIL},
-     * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_BAD_DATA},
-     * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_MISSING_DATA}, or
-     * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_MISSING_VOLUME}.
-     * <p> Moreover, the data received in the activity result will contain the following
-     * fields:
-     * <ul>
-     *   <li>{@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_ROOT_DIRECTORY} which
-     *       indicates the path to the location of the resource files</li>,
-     *   <li>{@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_FILES} which contains
-     *       the list of all the resource files</li>,
-     *   <li>and {@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_FILES_INFO} which
-     *       contains, for each resource file, the description of the language covered by
-     *       the file in the xxx-YYY format, where xxx is the 3-letter ISO language code,
-     *       and YYY is the 3-letter ISO country code.</li>
-     * </ul>
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_TTS_CHECK_TTS_DATA =
-            "android.intent.action.CHECK_TTS_DATA";
-
-    /**
-     * Broadcast Action: The TextToSpeech synthesizer has completed processing 
-     * all of the text in the speech queue.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
-            "android.intent.action.TTS_QUEUE_PROCESSING_COMPLETED";
 
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 7d03801..afe219c 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -151,34 +151,20 @@
                 int presentation, int callType, long start, int duration) {
             final ContentResolver resolver = context.getContentResolver();
 
-            // TODO(Moto): Which is correct: original code, this only changes the
-            // number if the number is empty and never changes the caller info name.
-        if (false) {
-            if (TextUtils.isEmpty(number)) {
-                if (presentation == Connection.PRESENTATION_RESTRICTED) {
-                    number = CallerInfo.PRIVATE_NUMBER;
-                } else if (presentation == Connection.PRESENTATION_PAYPHONE) {
-                    number = CallerInfo.PAYPHONE_NUMBER;
-                } else {
-                    number = CallerInfo.UNKNOWN_NUMBER;
-                }
-            }
-        } else {
-            // NEWCODE: From Motorola
-
-            //If this is a private number then set the number to Private, otherwise check
-            //if the number field is empty and set the number to Unavailable
+            // If this is a private number then set the number to Private, otherwise check
+            // if the number field is empty and set the number to Unavailable
             if (presentation == Connection.PRESENTATION_RESTRICTED) {
                 number = CallerInfo.PRIVATE_NUMBER;
-                ci.name = "";
+                if (ci != null) ci.name = "";
             } else if (presentation == Connection.PRESENTATION_PAYPHONE) {
                 number = CallerInfo.PAYPHONE_NUMBER;
-                ci.name = "";
-            } else if (TextUtils.isEmpty(number) || presentation == Connection.PRESENTATION_UNKNOWN) {
+                if (ci != null) ci.name = "";
+            } else if (TextUtils.isEmpty(number)
+                    || presentation == Connection.PRESENTATION_UNKNOWN) {
                 number = CallerInfo.UNKNOWN_NUMBER;
-                ci.name = "";
+                if (ci != null) ci.name = "";
             }
-        }
+
             ContentValues values = new ContentValues(5);
 
             values.put(NUMBER, number);
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
index b8a9875..49718cb 100644
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -63,6 +63,8 @@
     private static final int MSG_STOP_SEARCH = 2;
     // arg1 is activity id
     private static final int MSG_ACTIVITY_RESUMING = 3;
+    // obj is the reason
+    private static final int MSG_CLOSING_SYSTEM_DIALOGS = 4;
 
     private static final String KEY_INITIAL_QUERY = "q";
     private static final String KEY_LAUNCH_ACTIVITY = "a";
@@ -127,8 +129,7 @@
     private void registerBroadcastReceiver() {
         if (!mReceiverRegistered) {
             IntentFilter filter = new IntentFilter(
-                    Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+                    Intent.ACTION_CONFIGURATION_CHANGED);
             mContext.registerReceiver(mBroadcastReceiver, filter, null,
                     mSearchUiThread);
             mReceiverRegistered = true;
@@ -149,12 +150,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                if (!"search".equals(intent.getStringExtra("reason"))) {
-                    if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-                    performStopSearch();
-                }
-            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+            if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
                 performOnConfigurationChanged();
             }
@@ -219,6 +215,18 @@
         mSearchUiThread.sendMessage(msg);
     }
 
+    /**
+     * Handles closing of system windows/dialogs
+     * Can be called from any thread.
+     */
+    public void closingSystemDialogs(String reason) {
+        if (DBG) debug("closingSystemDialogs(reason=" + reason + ")");
+        Message msg = Message.obtain();
+        msg.what = MSG_CLOSING_SYSTEM_DIALOGS;
+        msg.obj = reason;
+        mSearchUiThread.sendMessage(msg);
+    }
+
     //
     // Implementation methods that run on the search UI thread
     //
@@ -244,6 +252,9 @@
                 case MSG_ACTIVITY_RESUMING:
                     performActivityResuming(msg.arg1);
                     break;
+                case MSG_CLOSING_SYSTEM_DIALOGS:
+                    performClosingSystemDialogs((String)msg.obj);
+                    break;
             }
         }
 
@@ -330,6 +341,19 @@
     }
 
     /**
+     * Updates due to system dialogs being closed
+     * This must be called on the search UI thread.
+     */
+    void performClosingSystemDialogs(String reason) {
+        if (DBG) debug("performClosingSystemDialogs(): mStartedIdent="
+                + mStartedIdent + ", reason: " + reason);
+        if (!"search".equals(reason)) {
+            if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+            performStopSearch();
+        }
+    }
+
+    /**
      * Must be called from the search UI thread.
      */
     void performOnConfigurationChanged() {
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index fdeb8f9..afed4a4 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -138,6 +138,11 @@
             if (mSearchDialog == null) return;
             mSearchDialog.activityResuming(activityId);
         }
+        public void closingSystemDialogs(String reason) {
+            if (DBG) Log.i("foo", "********************** closing dialogs: " + reason);
+            if (mSearchDialog == null) return;
+            mSearchDialog.closingSystemDialogs(reason);
+        }
     };
     
     /**
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 8f8d976..b033c6a 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -18,6 +18,8 @@
 import android.speech.tts.ITts;
 import android.speech.tts.ITtsCallback;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -41,51 +43,60 @@
     /**
      * Denotes a successful operation.
      */
-    public static final int TTS_SUCCESS                = 0;
+    public static final int SUCCESS                = 0;
     /**
      * Denotes a generic operation failure.
      */
-    public static final int TTS_ERROR                  = -1;
+    public static final int ERROR                  = -1;
 
     /**
      * Queue mode where all entries in the playback queue (media to be played
      * and text to be synthesized) are dropped and replaced by the new entry.
      */
-    public static final int TTS_QUEUE_FLUSH = 0;
+    public static final int QUEUE_FLUSH = 0;
     /**
      * Queue mode where the new entry is added at the end of the playback queue.
      */
-    public static final int TTS_QUEUE_ADD = 1;
+    public static final int QUEUE_ADD = 1;
 
 
     /**
      * Denotes the language is available exactly as specified by the locale
      */
-    public static final int TTS_LANG_COUNTRY_VAR_AVAILABLE = 2;
+    public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
 
 
     /**
      * Denotes the language is available for the language and country specified 
      * by the locale, but not the variant.
      */
-    public static final int TTS_LANG_COUNTRY_AVAILABLE = 1;
+    public static final int LANG_COUNTRY_AVAILABLE = 1;
 
 
     /**
      * Denotes the language is available for the language by the locale, 
      * but not the country and variant.
      */
-    public static final int TTS_LANG_AVAILABLE = 0;
+    public static final int LANG_AVAILABLE = 0;
 
     /**
      * Denotes the language data is missing.
      */
-    public static final int TTS_LANG_MISSING_DATA = -1;
+    public static final int LANG_MISSING_DATA = -1;
 
     /**
      * Denotes the language is not supported by the current TTS engine.
      */
-    public static final int TTS_LANG_NOT_SUPPORTED = -2;
+    public static final int LANG_NOT_SUPPORTED = -2;
+
+
+    /**
+     * Broadcast Action: The TextToSpeech synthesizer has completed processing
+     * of all the text in the speech queue.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
+            "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
 
 
     /**
@@ -119,126 +130,167 @@
         /**
          * {@hide}
          */
-        public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
+        public static final int DEFAULT_RATE = 100; // 1x
         /**
          * {@hide}
          */
-        public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
+        public static final int DEFAULT_PITCH = 100;// 1x
         /**
          * {@hide}
          */
-        public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
+        public static final int USE_DEFAULTS = 0; // false
         /**
          * {@hide}
          */
-        public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico";
+        public static final String DEFAULT_SYNTH = "com.svox.pico";
 
         // default values for rendering
-        public static final int TTS_DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
+        public static final int 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.
+         * text-to-speech engine with the {@link #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.
+         * text-to-speech engine with the {@link #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.
+         * the text-to-speech engine with the {@link #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.
+         * by the text-to-speech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
          */
         public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
         /**
          * 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.
+         * used by the text-to-speech engine with the {@link #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
+        // intents to ask engine to install data or check its data
         /**
-         * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+         * Broadcast Action: Triggers the platform Text-To-Speech engine to
+         * start the activity that installs the resource files on the device
+         * that are required for TTS to be operational. Since the installation
+         * of the data can be interrupted or declined by the user, the application
+         * shouldn't expect successful installation upon return from that intent,
+         * and if need be, should check installation status with
+         * {@link #ACTION_CHECK_TTS_DATA}.
+         */
+        @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+        public static final String ACTION_INSTALL_TTS_DATA =
+                "android.speech.tts.engine.INSTALL_TTS_DATA";
+
+        /**
+         * Broadcast Action: Starts the activity from the platform Text-To-Speech
+         * engine to verify the proper installation and availability of the
+         * resource files on the system. Upon completion, the activity will
+         * return one of the following codes:
+         * {@link #CHECK_VOICE_DATA_PASS},
+         * {@link #CHECK_VOICE_DATA_FAIL},
+         * {@link #CHECK_VOICE_DATA_BAD_DATA},
+         * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or
+         * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}.
+         * <p> Moreover, the data received in the activity result will contain the following
+         * fields:
+         * <ul>
+         *   <li>{@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which
+         *       indicates the path to the location of the resource files</li>,
+         *   <li>{@link #EXTRA_VOICE_DATA_FILES} which contains
+         *       the list of all the resource files</li>,
+         *   <li>and {@link #EXTRA_VOICE_DATA_FILES_INFO} which
+         *       contains, for each resource file, the description of the language covered by
+         *       the file in the xxx-YYY format, where xxx is the 3-letter ISO language code,
+         *       and YYY is the 3-letter ISO country code.</li>
+         * </ul>
+         */
+        @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+        public static final String ACTION_CHECK_TTS_DATA =
+                "android.speech.tts.engine.CHECK_TTS_DATA";
+
+        // extras for a TTS engine's check data activity
+        /**
+         * Extra information received with the {@link #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";
+        public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
         /**
-         * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+         * Extra information received with the {@link #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";
+        public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
         /**
-         * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where
+         * Extra information received with the {@link #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";
+        public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
 
         // 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";
+        public static final String KEY_PARAM_RATE = "rate";
         /**
          * {@hide}
          */
-        public static final String TTS_KEY_PARAM_LANGUAGE = "language";
+        public static final String KEY_PARAM_LANGUAGE = "language";
         /**
          * {@hide}
          */
-        public static final String TTS_KEY_PARAM_COUNTRY = "country";
+        public static final String KEY_PARAM_COUNTRY = "country";
         /**
          * {@hide}
          */
-        public static final String TTS_KEY_PARAM_VARIANT = "variant";
+        public static final String 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";
+        public static final String 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";
+        public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
 
         // key positions in the array of cached parameters
         /**
          * {@hide}
          */
-        protected static final int TTS_PARAM_POSITION_RATE = 0;
+        protected static final int PARAM_POSITION_RATE = 0;
         /**
          * {@hide}
          */
-        protected static final int TTS_PARAM_POSITION_LANGUAGE = 2;
+        protected static final int PARAM_POSITION_LANGUAGE = 2;
         /**
          * {@hide}
          */
-        protected static final int TTS_PARAM_POSITION_COUNTRY = 4;
+        protected static final int PARAM_POSITION_COUNTRY = 4;
         /**
          * {@hide}
          */
-        protected static final int TTS_PARAM_POSITION_VARIANT = 6;
+        protected static final int PARAM_POSITION_VARIANT = 6;
         /**
          * {@hide}
          */
-        protected static final int TTS_PARAM_POSITION_STREAM = 8;
+        protected static final int PARAM_POSITION_STREAM = 8;
         /**
          * {@hide}
          */
-        protected static final int TTS_PARAM_POSITION_UTTERANCE_ID = 10;
+        protected static final int PARAM_POSITION_UTTERANCE_ID = 10;
         /**
          * {@hide}
          */
-        protected static final int TTS_NB_CACHED_PARAMS = 6;
+        protected static final int NB_CACHED_PARAMS = 6;
     }
 
     /**
@@ -273,25 +325,25 @@
         mPackageName = mContext.getPackageName();
         mInitListener = listener;
 
-        mCachedParams = new String[2*Engine.TTS_NB_CACHED_PARAMS]; // store key and value
-        mCachedParams[Engine.TTS_PARAM_POSITION_RATE] = Engine.TTS_KEY_PARAM_RATE;
-        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE] = Engine.TTS_KEY_PARAM_LANGUAGE;
-        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY] = Engine.TTS_KEY_PARAM_COUNTRY;
-        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT] = Engine.TTS_KEY_PARAM_VARIANT;
-        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM] = Engine.TTS_KEY_PARAM_STREAM;
-        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID] = Engine.TTS_KEY_PARAM_UTTERANCE_ID;
+        mCachedParams = new String[2*Engine.NB_CACHED_PARAMS]; // store key and value
+        mCachedParams[Engine.PARAM_POSITION_RATE] = Engine.KEY_PARAM_RATE;
+        mCachedParams[Engine.PARAM_POSITION_LANGUAGE] = Engine.KEY_PARAM_LANGUAGE;
+        mCachedParams[Engine.PARAM_POSITION_COUNTRY] = Engine.KEY_PARAM_COUNTRY;
+        mCachedParams[Engine.PARAM_POSITION_VARIANT] = Engine.KEY_PARAM_VARIANT;
+        mCachedParams[Engine.PARAM_POSITION_STREAM] = Engine.KEY_PARAM_STREAM;
+        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID] = Engine.KEY_PARAM_UTTERANCE_ID;
 
-        mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] =
-                String.valueOf(Engine.FALLBACK_TTS_DEFAULT_RATE);
+        mCachedParams[Engine.PARAM_POSITION_RATE + 1] =
+                String.valueOf(Engine.DEFAULT_RATE);
         // initialize the language cached parameters with the current Locale
         Locale defaultLoc = Locale.getDefault();
-        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language();
-        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country();
-        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant();
+        mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language();
+        mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country();
+        mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant();
 
-        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] =
-                String.valueOf(Engine.TTS_DEFAULT_STREAM);
-        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = "";
+        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
+                String.valueOf(Engine.DEFAULT_STREAM);
+        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = "";
 
         initTts();
     }
@@ -308,7 +360,7 @@
                     mStarted = true;
                     if (mInitListener != null) {
                         // TODO manage failures and missing resources
-                        mInitListener.onInit(TTS_SUCCESS);
+                        mInitListener.onInit(SUCCESS);
                     }
                 }
             }
@@ -349,8 +401,7 @@
     /**
      * Adds a mapping between a string of text and a sound resource in a
      * package.
-     *
-     * @see #TTS.speak(String text, int queueMode, String[] params)
+     * @see #speak(String, int, HashMap)
      *
      * @param text
      *            Example: <b><code>"south_south_east"</code></b><br/>
@@ -371,16 +422,16 @@
      * @param resourceId
      *            Example: <b><code>R.raw.south_south_east</code></b>
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int addSpeech(String text, String packagename, int resourceId) {
         synchronized(mStartLock) {
             if (!mStarted) {
-                return TTS_ERROR;
+                return ERROR;
             }
             try {
                 mITts.addSpeech(mPackageName, text, packagename, resourceId);
-                return TTS_SUCCESS;
+                return SUCCESS;
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 Log.e("TextToSpeech.java - addSpeech", "RemoteException");
@@ -400,7 +451,7 @@
                 mStarted = false;
                 initTts();
             }
-            return TTS_ERROR;
+            return ERROR;
         }
     }
 
@@ -415,16 +466,16 @@
      *            The full path to the sound file (for example:
      *            "/sdcard/mysounds/hello.wav")
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int addSpeech(String text, String filename) {
         synchronized (mStartLock) {
             if (!mStarted) {
-                return TTS_ERROR;
+                return ERROR;
             }
             try {
                 mITts.addSpeechFile(mPackageName, text, filename);
-                return TTS_SUCCESS;
+                return SUCCESS;
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 Log.e("TextToSpeech.java - addSpeech", "RemoteException");
@@ -444,7 +495,7 @@
                 mStarted = false;
                 initTts();
             }
-            return TTS_ERROR;
+            return ERROR;
         }
     }
 
@@ -453,7 +504,7 @@
      * Adds a mapping between a string of text and a sound resource in a
      * package.
      *
-     * @see #TTS.playEarcon(String earcon, int queueMode, String[] params)
+     * @see #playEarcon(String, int, HashMap)
      *
      * @param earcon The name of the earcon
      *            Example: <b><code>"[tick]"</code></b><br/>
@@ -474,16 +525,16 @@
      * @param resourceId
      *            Example: <b><code>R.raw.tick_snd</code></b>
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int addEarcon(String earcon, String packagename, int resourceId) {
         synchronized(mStartLock) {
             if (!mStarted) {
-                return TTS_ERROR;
+                return ERROR;
             }
             try {
                 mITts.addEarcon(mPackageName, earcon, packagename, resourceId);
-                return TTS_SUCCESS;
+                return SUCCESS;
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 Log.e("TextToSpeech.java - addEarcon", "RemoteException");
@@ -503,7 +554,7 @@
                 mStarted = false;
                 initTts();
             }
-            return TTS_ERROR;
+            return ERROR;
         }
     }
 
@@ -518,16 +569,16 @@
      *            The full path to the sound file (for example:
      *            "/sdcard/mysounds/tick.wav")
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int addEarcon(String earcon, String filename) {
         synchronized (mStartLock) {
             if (!mStarted) {
-                return TTS_ERROR;
+                return ERROR;
             }
             try {
                 mITts.addEarconFile(mPackageName, earcon, filename);
-                return TTS_SUCCESS;
+                return SUCCESS;
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 Log.e("TextToSpeech.java - addEarcon", "RemoteException");
@@ -547,7 +598,7 @@
                 mStarted = false;
                 initTts();
             }
-            return TTS_ERROR;
+            return ERROR;
         }
     }
 
@@ -563,29 +614,29 @@
      *            The string of text to be spoken.
      * @param queueMode
      *            The queuing strategy to use.
-     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
+     *            See QUEUE_ADD and QUEUE_FLUSH.
      * @param params
      *            The hashmap of speech parameters to be used.
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int speak(String text, int queueMode, HashMap<String,String> params)
     {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             Log.i("TTS received: ", text);
             if (!mStarted) {
                 return result;
             }
             try {
                 if ((params != null) && (!params.isEmpty())) {
-                    String extra = params.get(Engine.TTS_KEY_PARAM_STREAM);
+                    String extra = params.get(Engine.KEY_PARAM_STREAM);
                     if (extra != null) {
-                        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = extra;
+                        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra;
                     }
-                    extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                    extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
                     if (extra != null) {
-                        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra;
+                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
                     }
                 }
                 result = mITts.speak(mPackageName, text, queueMode, mCachedParams);
@@ -621,28 +672,28 @@
      * @param earcon
      *            The earcon that should be played
      * @param queueMode
-     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
+     *            See QUEUE_ADD and QUEUE_FLUSH.
      * @param params
      *            The hashmap of parameters to be used.
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int playEarcon(String earcon, int queueMode,
             HashMap<String,String> params) {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
             try {
                 if ((params != null) && (!params.isEmpty())) {
-                    String extra = params.get(Engine.TTS_KEY_PARAM_STREAM);
+                    String extra = params.get(Engine.KEY_PARAM_STREAM);
                     if (extra != null) {
-                        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = extra;
+                        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra;
                     }
-                    extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                    extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
                     if (extra != null) {
-                        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra;
+                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
                     }
                 }
                 result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
@@ -678,21 +729,21 @@
      * @param durationInMs
      *            A long that indicates how long the silence should last.
      * @param queueMode
-     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
+     *            See QUEUE_ADD and QUEUE_FLUSH.
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int playSilence(long durationInMs, int queueMode, HashMap<String,String> params) {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
             try {
                 if ((params != null) && (!params.isEmpty())) {
-                    String extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                    String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
                     if (extra != null) {
-                        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra;
+                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
                     }
                 }
                 result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams);
@@ -760,11 +811,11 @@
     /**
      * Stops speech from the TTS.
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int stop() {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
@@ -808,24 +859,24 @@
      *            lower values slow down the speech (0.5 is half the normal speech rate),
      *            greater values accelerate it (2 is twice the normal speech rate).
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int setSpeechRate(float speechRate) {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
             try {
                 if (speechRate > 0) {
                     int rate = (int)(speechRate*100);
-                    mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = String.valueOf(rate);
+                    mCachedParams[Engine.PARAM_POSITION_RATE + 1] = String.valueOf(rate);
                     // the rate is not set here, instead it is cached so it will be associated
                     // with all upcoming utterances.
                     if (speechRate > 0.0f) {
-                        result = TTS_SUCCESS;
+                        result = SUCCESS;
                     } else {
-                        result = TTS_ERROR;
+                        result = ERROR;
                     }
                 }
             } catch (NullPointerException e) {
@@ -860,11 +911,11 @@
      *            lower values lower the tone of the synthesized voice,
      *            greater values increase it.
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int setPitch(float pitch) {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
@@ -907,27 +958,27 @@
      * @param loc
      *            The locale describing the language to be used.
      *
-     * @return code indicating the support status for the locale. See {@link #TTS_LANG_AVAILABLE},
-     *         {@link #TTS_LANG_COUNTRY_AVAILABLE}, {@link #TTS_LANG_COUNTRY_VAR_AVAILABLE},
-     *         {@link #TTS_LANG_MISSING_DATA} and {@link #TTS_LANG_NOT_SUPPORTED}.
+     * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
+     *         {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
+     *         {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
      */
     public int setLanguage(Locale loc) {
         synchronized (mStartLock) {
-            int result = TTS_LANG_NOT_SUPPORTED;
+            int result = LANG_NOT_SUPPORTED;
             if (!mStarted) {
                 return result;
             }
             try {
-                mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language();
-                mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country();
-                mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = loc.getVariant();
+                mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language();
+                mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country();
+                mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = loc.getVariant();
                 // the language is not set here, instead it is cached so it will be associated
                 // with all upcoming utterances. But we still need to report the language support,
                 // which is achieved by calling isLanguageAvailable()
                 result = mITts.isLanguageAvailable(
-                        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1],
-                        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1],
-                        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] );
+                        mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1],
+                        mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1],
+                        mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] );
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 Log.e("TextToSpeech.java - setLanguage", "RemoteException");
@@ -999,13 +1050,13 @@
      * @param loc
      *            The Locale describing the language to be used.
      *
-     * @return code indicating the support status for the locale. See {@link #TTS_LANG_AVAILABLE},
-     *         {@link #TTS_LANG_COUNTRY_AVAILABLE}, {@link #TTS_LANG_COUNTRY_VAR_AVAILABLE},
-     *         {@link #TTS_LANG_MISSING_DATA} and {@link #TTS_LANG_NOT_SUPPORTED}.
+     * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
+     *         {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
+     *         {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
      */
     public int isLanguageAvailable(Locale loc) {
         synchronized (mStartLock) {
-            int result = TTS_LANG_NOT_SUPPORTED;
+            int result = LANG_NOT_SUPPORTED;
             if (!mStarted) {
                 return result;
             }
@@ -1048,25 +1099,25 @@
      *            The string that gives the full output filename; it should be
      *            something like "/sdcard/myappsounds/mysound.wav".
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int synthesizeToFile(String text, HashMap<String,String> params,
             String filename) {
         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
             try {
                 if ((params != null) && (!params.isEmpty())) {
                     // no need to read the stream type here
-                    String extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID);
+                    String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
                     if (extra != null) {
-                        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra;
+                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
                     }
                 }
                 if (mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename)){
-                    result = TTS_SUCCESS;
+                    result = SUCCESS;
                 }
             } catch (RemoteException e) {
                 // TTS died; restart it.
@@ -1099,9 +1150,9 @@
      * if they are not persistent between calls to the service.
      */
     private void resetCachedParams() {
-        mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] =
-                String.valueOf(Engine.TTS_DEFAULT_STREAM);
-        mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID+ 1] = "";
+        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
+                String.valueOf(Engine.DEFAULT_STREAM);
+        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID+ 1] = "";
     }
 
     /**
@@ -1110,12 +1161,12 @@
      * @param listener
      *            The OnUtteranceCompletedListener
      *
-     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
+     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
     public int setOnUtteranceCompletedListener(

             final OnUtteranceCompletedListener listener) {

         synchronized (mStartLock) {
-            int result = TTS_ERROR;
+            int result = ERROR;
             if (!mStarted) {
                 return result;
             }
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index a26bfa2..47f5c6c 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -277,7 +277,7 @@
         if (child.getLayoutParams() == null) {
             final LinearLayout.LayoutParams lp = new LayoutParams(
                     0,
-                    ViewGroup.LayoutParams.WRAP_CONTENT, 1);
+                    ViewGroup.LayoutParams.FILL_PARENT, 1.0f);
             lp.setMargins(0, 0, 0, 0);
             child.setLayoutParams(lp);
         }
@@ -289,10 +289,10 @@
         // If we have dividers between the tabs and we already have at least one
         // tab, then add a divider before adding the next tab.
         if (mDividerDrawable != null && getTabCount() > 0) {
-            View divider = new View(mContext);
+            ImageView divider = new ImageView(mContext);
             final LinearLayout.LayoutParams lp = new LayoutParams(
                     mDividerDrawable.getIntrinsicWidth(),
-                    mDividerDrawable.getIntrinsicHeight());
+                    LayoutParams.FILL_PARENT);
             lp.setMargins(0, 0, 0, 0);
             divider.setLayoutParams(lp);
             divider.setBackgroundDrawable(mDividerDrawable);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 6832862..1b99d32 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -194,7 +194,7 @@
     private boolean isDefaultEnforced() {
         return (android.provider.Settings.Secure.getInt(mResolver,
                     android.provider.Settings.Secure.TTS_USE_DEFAULTS,
-                    TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS)
+                    TextToSpeech.Engine.USE_DEFAULTS)
                 == 1 );
     }
 
@@ -202,7 +202,7 @@
     private int getDefaultRate() {
         return android.provider.Settings.Secure.getInt(mResolver,
                 android.provider.Settings.Secure.TTS_DEFAULT_RATE,
-                TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE);
+                TextToSpeech.Engine.DEFAULT_RATE);
     }
 
 
@@ -346,7 +346,7 @@
      */
     private int speak(String callingApp, String text, int queueMode, ArrayList<String> params) {
         Log.v("TtsService", "TTS service received " + text);
-        if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
+        if (queueMode == TextToSpeech.QUEUE_FLUSH) {
             stop(callingApp);
         } else if (queueMode == 2) {
             stopAll(callingApp);
@@ -355,7 +355,7 @@
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
-        return TextToSpeech.TTS_SUCCESS;
+        return TextToSpeech.SUCCESS;
     }
 
     /**
@@ -372,7 +372,7 @@
      */
     private int playEarcon(String callingApp, String earcon, int queueMode,
             ArrayList<String> params) {
-        if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
+        if (queueMode == TextToSpeech.QUEUE_FLUSH) {
             stop(callingApp);
         } else if (queueMode == 2) {
             stopAll(callingApp);
@@ -381,14 +381,14 @@
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
-        return TextToSpeech.TTS_SUCCESS;
+        return TextToSpeech.SUCCESS;
     }
 
     /**
      * 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;
+        int result = TextToSpeech.ERROR;
         boolean speechQueueAvailable = false;
         try{
             speechQueueAvailable =
@@ -414,7 +414,7 @@
                     mIsSpeaking = false;
                     mCurrentSpeechItem = null;
                 } else {
-                    result = TextToSpeech.TTS_SUCCESS;
+                    result = TextToSpeech.SUCCESS;
                 }
                 Log.i("TtsService", "Stopped");
             }
@@ -437,7 +437,7 @@
      * Stops all speech output and removes any utterances still in the queue globally.
      */
     private int stopAll(String callingApp) {
-        int result = TextToSpeech.TTS_ERROR;
+        int result = TextToSpeech.ERROR;
         boolean speechQueueAvailable = false;
         try{
             speechQueueAvailable =
@@ -463,7 +463,7 @@
                     mIsSpeaking = false;
                     mCurrentSpeechItem = null;
                 } else {
-                    result = TextToSpeech.TTS_SUCCESS;
+                    result = TextToSpeech.SUCCESS;
                 }
                 Log.i("TtsService", "Stopped all");
             }
@@ -487,7 +487,7 @@
         if (params != null){
             for (int i = 0; i < params.size() - 1; i = i + 2){
             String param = params.get(i);
-                if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){
+                if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
                     utteranceId = params.get(i+1);
                 }
             }
@@ -500,14 +500,14 @@
 
     private int playSilence(String callingApp, long duration, int queueMode,
             ArrayList<String> params) {
-        if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) {
+        if (queueMode == TextToSpeech.QUEUE_FLUSH) {
             stop(callingApp);
         }
         mSpeechQueue.add(new SpeechItem(callingApp, duration, params));
         if (!mIsSpeaking) {
             processSpeechQueue();
         }
-        return TextToSpeech.TTS_SUCCESS;
+        return TextToSpeech.SUCCESS;
     }
 
     private void silence(final SpeechItem speechItem) {
@@ -517,7 +517,7 @@
                 if (speechItem.mParams != null){
                     for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
                         String param = speechItem.mParams.get(i);
-                        if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){
+                        if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
                             utteranceId = speechItem.mParams.get(i+1);
                         }
                     }
@@ -562,17 +562,17 @@
                         for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
                             String param = speechItem.mParams.get(i);
                             if (param != null) {
-                                if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)) {
+                                if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
                                     speechRate = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
                                     language = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
                                     country = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
                                     variant = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
                                     utteranceId = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM)) {
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM)) {
                                     try {
                                         streamType
                                                 = Integer.parseInt(speechItem.mParams.get(i + 1));
@@ -638,15 +638,15 @@
                         for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
                             String param = speechItem.mParams.get(i);
                             if (param != null) {
-                                if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)) {
+                                if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
                                     speechRate = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
                                     language = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
                                     country = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
                                     variant = speechItem.mParams.get(i+1);
-                                } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){
+                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
                                     utteranceId = speechItem.mParams.get(i+1);
                                 }
                             }
@@ -698,7 +698,7 @@
     }
 
     private void broadcastTtsQueueProcessingCompleted(){
-        Intent i = new Intent(Intent.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
+        Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
         sendBroadcast(i);
     }
 
@@ -843,7 +843,7 @@
         }
         for (int i = 0; i < paramList.size() - 1; i = i + 2) {
             String param = paramList.get(i);
-            if ((param != null) && (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM))) {
+            if ((param != null) && (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM))) {
                 try {
                     streamType = Integer.parseInt(paramList.get(i + 1));
                 } catch (NumberFormatException e) {
@@ -910,18 +910,18 @@
             if (cb != null) {
                 mCallbacks.register(cb);
                 mCallbacksMap.put(packageName, cb);
-                return TextToSpeech.TTS_SUCCESS;
+                return TextToSpeech.SUCCESS;
             }
-            return TextToSpeech.TTS_ERROR;
+            return TextToSpeech.ERROR;
         }
 
         public int unregisterCallback(String packageName, ITtsCallback cb) {
             if (cb != null) {
                 mCallbacksMap.remove(packageName);
                 mCallbacks.unregister(cb);
-                return TextToSpeech.TTS_SUCCESS;
+                return TextToSpeech.SUCCESS;
             }
-            return TextToSpeech.TTS_ERROR;
+            return TextToSpeech.ERROR;
         }
 
         /**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5ea59ca..51ee41a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4760,6 +4760,34 @@
         }
     }
 
+    public void closeSystemDialogs(String reason) {
+        Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        if (reason != null) {
+            intent.putExtra("reason", reason);
+        }
+        
+        final int uid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (this) {
+            int i = mWatchers.beginBroadcast();
+            while (i > 0) {
+                i--;
+                IActivityWatcher w = mWatchers.getBroadcastItem(i);
+                if (w != null) {
+                    try {
+                        w.closingSystemDialogs(reason);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+            mWatchers.finishBroadcast();
+            
+            broadcastIntentLocked(null, null, intent, null,
+                    null, 0, null, null, null, false, false, -1, uid);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+    
     private void restartPackageLocked(final String packageName, int uid) {
         uninstallPackageLocked(packageName, uid, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ba5c6e7..ed9af66 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -256,7 +256,7 @@
      * No phone module
      *
      */
-    public static final int PHONE_TYPE_NONE = 0;
+    public static final int PHONE_TYPE_NONE = RILConstants.NO_PHONE;
 
     /**
      * GSM phone
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 7834018..1f4ce3d 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -68,8 +68,9 @@
     int CDMA_CELL_BROADCAST_SMS_DISABLED = 1;
     int CDMA_CELL_BROADCAST_SMS_ENABLED  = 0;
 
-    int CDMA_PHONE = 0;
+    int NO_PHONE = 0;
     int GSM_PHONE = 1;
+    int CDMA_PHONE = 2;
 
     int CDM_TTY_MODE_DISABLED = 0;
     int CDM_TTY_MODE_ENABLED = 1;
diff --git a/tests/CoreTests/android/core/CryptoTest.java b/tests/CoreTests/android/core/CryptoTest.java
index f00d49f..e6e50ec 100644
--- a/tests/CoreTests/android/core/CryptoTest.java
+++ b/tests/CoreTests/android/core/CryptoTest.java
@@ -22,7 +22,6 @@
 import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest;
 import org.bouncycastle.crypto.Digest;
 import org.bouncycastle.crypto.ExtendedDigest;
-import org.bouncycastle.crypto.digests.MD2Digest;
 import org.bouncycastle.crypto.digests.MD4Digest;
 import org.bouncycastle.crypto.digests.MD5Digest;
 import org.bouncycastle.crypto.digests.SHA1Digest;
@@ -93,16 +92,6 @@
         
         // Assert.assertTrue("New hash should be faster", newTime < oldTime);
     }
-
-    /**
-     * Tests the MD2 implementation.
-     */
-    @LargeTest
-    public void testMD2() {
-        Digest oldDigest = new MD2Digest();
-        Digest newDigest = OpenSSLMessageDigest.getInstance("MD2");
-        doTestMessageDigest(oldDigest, newDigest);
-    }
     
     /**
      * Tests the MD4 implementation.
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1f73bec..74f4284 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -870,7 +870,10 @@
      * Create a new MulticastLock
      *
      * @param tag a tag for the MulticastLock to identify it in debugging
-     *            messages.
+     *            messages.  This string is never shown to the user under
+     *            normal conditions, but should be descriptive enough to
+     *            identify your application and the specific MulticastLock
+     *            within it, if it holds multiple MulticastLocks.
      *
      * @return a new, unacquired MulticastLock with the given tag.
      *
@@ -886,26 +889,36 @@
      * addressed to this device.  Acquring a MulticastLock will
      * cause the stack to receive packets addressed to multicast
      * addresses.  Processing these extra packets can cause a noticable
-     * battery drain and should be disabled when not needed
+     * battery drain and should be disabled when not needed.
      */
     public class MulticastLock {
         private String mTag;
         private final IBinder mBinder;
+        private int mRefCount;
+        private boolean mRefCounted;
         private boolean mHeld;
 
         private MulticastLock(String tag) {
             mTag = tag;
             mBinder = new Binder();
+            mRefCount = 0;
+            mRefCounted = true;
             mHeld = false;
         }
 
         /**
          * Locks Wifi Multicast on until {@link #release} is called.
          *
-         * The first call to {@code acquire} will lock the Multicast on
-         * but subsequent calls will be ignored.  Only one call to
-         * {@link #release} will be required, regardless of the number of
-         * times that {@code acquire} is called.
+         * If this MulticastLock is reference-counted each call to
+         * {@code acquire} will increment the reference count, and the
+         * wifi interface will receive multicast packets as long as the
+         * reference count is above zero.
+         *
+         * If this MulticastLock is not reference-counted, the first call to
+         * {@code acquire} will turn on the multicast packets, but subsequent
+         * calls will be ignored.  Only one call to {@link #release} will
+         * be required, regardless of the number of times that {@code acquire}
+         * is called.
          *
          * Note that other applications may also lock Wifi Multicast on.
          * Only they can relinquish their lock.
@@ -915,7 +928,7 @@
          */
         public void acquire() {
             synchronized (mBinder) {
-                if (!mHeld) {
+                if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
                     try {
                         mService.acquireMulticastLock(mBinder, mTag);
                         synchronized (WifiManager.this) {
@@ -926,9 +939,9 @@
                             }
                             mActiveLockCount++;
                         }
-                        mHeld = true;
                     } catch (RemoteException ignore) {
                     }
+                    mHeld = true;
                 }
             }
         }
@@ -937,6 +950,18 @@
          * Unlocks Wifi Multicast, restoring the filter of packets
          * not addressed specifically to this device and saving power.
          *
+         * If this MulticastLock is reference-counted, each call to
+         * {@code release} will decrement the reference count, and the
+         * multicast packets will only stop being received when the reference
+         * count reaches zero.  If the reference count goes below zero (that
+         * is, if {@code release} is called a greater number of times than
+         * {@link #acquire}), an exception is thrown.
+         *
+         * If this MulticastLock is not reference-counted, the first call to
+         * {@code release} (after the radio was multicast locked using
+         * {@linke #acquire}) will unlock the multicast, and subsequent calls
+         * will be ignored.
+         *
          * Note that if any other Wifi Multicast Locks are still outstanding
          * this {@code release} call will not have an immediate effect.  Only
          * when all applications have released all their Multicast Locks will
@@ -947,20 +972,43 @@
          */
         public void release() {
             synchronized (mBinder) {
-                if (mHeld) {
+                if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
                     try {
                         mService.releaseMulticastLock();
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                        mHeld = false;
                     } catch (RemoteException ignore) {
                     }
+                    mHeld = false;
+                }
+                if (mRefCount < 0) {
+                    throw new RuntimeException("MulticastLock under-locked "
+                            + mTag);
                 }
             }
         }
 
         /**
+         * Controls whether this is a reference-counted or non-reference-
+         * counted MulticastLock.
+         *
+         * Reference-counted MulticastLocks keep track of the number of calls
+         * to {@link #acquire} and {@link #release}, and only stop the
+         * reception of multicast packets when every call to {@link #acquire}
+         * has been balanced with a call to {@link #release}.  Non-reference-
+         * counted MulticastLocks allow the reception of multicast packets
+         * whenever {@link #acquire} is called and stop accepting multicast
+         * packets whenever {@link #release} is called.
+         *
+         * @param refCounted true if this MulticastLock should keep a reference
+         * count
+         */
+        public void setReferenceCounted(boolean refCounted) {
+            mRefCounted = refCounted;
+        }
+
+        /**
          * Checks whether this MulticastLock is currently held.
          *
          * @return true if this MulticastLock is held, false otherwise
@@ -972,17 +1020,23 @@
         }
 
         public String toString() {
-            String s1, s2;
+            String s1, s2, s3;
             synchronized (mBinder) {
                 s1 = Integer.toHexString(System.identityHashCode(this));
                 s2 = mHeld ? "held; " : "";
-                return "MulticastLock{ " + s1 + "; " + s2 + " }";
+                if (mRefCounted) {
+                    s3 = "refcounted: refcount = " + mRefCount;
+                } else {
+                    s3 = "not refcounted";
+                }
+                return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
             }
         }
 
         @Override
         protected void finalize() throws Throwable {
             super.finalize();
+            setReferenceCounted(false);
             release();
         }
     }