Merge change 7961 into donut

* changes:
  Bluetooth at command tracking.
diff --git a/api/current.xml b/api/current.xml
index 779d122..e9eecdd 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -23732,6 +23732,28 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_DATA_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;intent_extra_data_key&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INTENT_ACTION_WEB_SEARCH_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.search.action.WEB_SEARCH_SETTINGS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="MENU_KEY"
  type="char"
  transient="false"
@@ -23765,6 +23787,17 @@
  visibility="public"
 >
 </field>
+<field name="SHORTCUT_MIME_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;vnd.android.cursor.item/vnd.android.search.suggest&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SUGGEST_COLUMN_FORMAT"
  type="java.lang.String"
  transient="false"
@@ -23831,6 +23864,17 @@
  visibility="public"
 >
 </field>
+<field name="SUGGEST_COLUMN_INTENT_EXTRA_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;suggest_intent_extra_data&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SUGGEST_COLUMN_QUERY"
  type="java.lang.String"
  transient="false"
@@ -23842,6 +23886,28 @@
  visibility="public"
 >
 </field>
+<field name="SUGGEST_COLUMN_SHORTCUT_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;suggest_shortcut_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;suggest_spinner_while_refreshing&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SUGGEST_COLUMN_TEXT_1"
  type="java.lang.String"
  transient="false"
@@ -23875,6 +23941,17 @@
  visibility="public"
 >
 </field>
+<field name="SUGGEST_NEVER_MAKE_SHORTCUT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;_-1&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SUGGEST_URI_PATH_QUERY"
  type="java.lang.String"
  transient="false"
@@ -23886,6 +23963,17 @@
  visibility="public"
 >
 </field>
+<field name="SUGGEST_URI_PATH_SHORTCUT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;search_suggest_shortcut&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="USER_QUERY"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index 84a6085..bd72544 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -37,4 +37,5 @@
             ISearchManagerCallback searchManagerCallback,
             int ident);
     void stopSearch();
+    boolean isVisible();
 }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 906361c..27c6376 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -354,7 +354,6 @@
             }
             show();
         }
-
         updateUI();
         
         return true;
@@ -490,6 +489,7 @@
      */
     private void updateUI() {
         if (mSearchable != null) {
+            mDecor.setVisibility(View.VISIBLE);
             updateSearchAutoComplete();
             updateSearchButton();
             updateSearchAppIcon();
@@ -994,7 +994,7 @@
     };
 
     @Override
-    public void dismiss() {
+    public void hide() {
         if (!isShowing()) return;
 
         // We made sure the IME was displayed, so also make sure it is closed
@@ -1005,10 +1005,10 @@
             imm.hideSoftInputFromWindow(
                     getWindow().getDecorView().getWindowToken(), 0);
         }
-        
-        super.dismiss();
+
+        super.hide();
     }
-    
+
     /**
      * React to the user typing while in the suggestions list. First, check for action
      * keys. If not handled, try refocusing regular characters into the EditText. 
@@ -1234,8 +1234,8 @@
     }
 
     /**
-     * Launches an intent and dismisses the search dialog (unless the intent
-     * is one of the special intents that modifies the state of the search dialog).
+     * Launches an intent, including any special intent handling.  Doesn't dismiss the dialog
+     * since that will be handled in {@link SearchDialogWrapper#performActivityResuming}
      */
     private void launchIntent(Intent intent) {
         if (intent == null) {
@@ -1244,8 +1244,15 @@
         if (handleSpecialIntent(intent)){
             return;
         }
-        dismiss();
+        Log.d(LOG_TAG, "launching " + intent);
         getContext().startActivity(intent);
+
+        // in global search mode, SearchDialogWrapper#performActivityResuming will handle hiding
+        // the dialog when the next activity starts, but for in-app search, we still need to
+        // dismiss the dialog.
+        if (!mGlobalSearchMode) {
+            dismiss();
+        }
     }
     
     /**
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index b795a54..78335ad 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1188,8 +1188,6 @@
     /**
      * Intent extra data key: This key will be used for the extra populated by the
      * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
-     *
-     * {@hide}
      */
     public final static String EXTRA_DATA_KEY = "intent_extra_data_key";
 
@@ -1269,16 +1267,12 @@
      * result indicates the shortcut refers to a no longer valid sugggestion.
      *
      * @see #SUGGEST_COLUMN_SHORTCUT_ID
-     * 
-     * @hide pending API council approval
      */
     public final static String SUGGEST_URI_PATH_SHORTCUT = "search_suggest_shortcut";
     
     /**
      * MIME type for shortcut validation.  You'll use this in your suggestions content provider
      * in the getType() function.
-     *
-     * @hide pending API council approval
      */
     public final static String SHORTCUT_MIME_TYPE = 
             "vnd.android.cursor.item/vnd.android.search.suggest";
@@ -1389,9 +1383,7 @@
      * this element exists at the given row, this is the data that will be used when
      * forming the suggestion's intent. If not provided, the Intent's extra data field will be null.
      * This column allows suggestions to provide additional arbitrary data which will be included as
-     * an extra under the key EXTRA_DATA_KEY.
-     *
-     * @hide Pending API council approval.
+     * an extra under the key {@link #EXTRA_DATA_KEY}.
      */
     public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
     /**
@@ -1425,8 +1417,6 @@
      * {@link #SUGGEST_NEVER_MAKE_SHORTCUT}, the result will not be stored as a shortcut.
      * Otherwise, the shortcut id will be used to check back for validation via
      * {@link #SUGGEST_URI_PATH_SHORTCUT}.
-     *
-     * @hide Pending API council approval.
      */
     public final static String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id";
 
@@ -1443,8 +1433,6 @@
      * Column name for suggestions cursor. <i>Optional.</i> This column is used to specify
      * that a spinner should be shown in lieu of an icon2 while the shortcut of this suggestion
      * is being refreshed.
-     * 
-     * @hide Pending API council approval.
      */
     public final static String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING =
             "suggest_spinner_while_refreshing";
@@ -1452,8 +1440,6 @@
     /**
      * Column value for suggestion column {@link #SUGGEST_COLUMN_SHORTCUT_ID} when a suggestion
      * should not be stored as a shortcut in global search.
-     *
-     * @hide Pending API council approval.
      */
     public final static String SUGGEST_NEVER_MAKE_SHORTCUT = "_-1";
 
@@ -1500,8 +1486,6 @@
      * Intent action for starting a web search provider's settings activity.
      * Web search providers should handle this intent if they have provider-specific
      * settings to implement.
-     * 
-     * @hide Pending API council approval.
      */
     public final static String INTENT_ACTION_WEB_SEARCH_SETTINGS
             = "android.search.action.WEB_SEARCH_SETTINGS";
@@ -1534,7 +1518,6 @@
     private int mIdent;
     
     // package private since they are used by the inner class SearchManagerCallback
-    /* package */ boolean mIsShowing = false;
     /* package */ final Handler mHandler;
     /* package */ OnDismissListener mDismissListener = null;
     /* package */ OnCancelListener mCancelListener = null;
@@ -1600,12 +1583,9 @@
                             ComponentName launchActivity,
                             Bundle appSearchData,
                             boolean globalSearch) {
-        if (DBG) debug("startSearch(), mIsShowing=" + mIsShowing);
-        if (mIsShowing) return;
         if (mIdent == 0) throw new IllegalArgumentException(
                 "Called from outside of an Activity context");
         try {
-            mIsShowing = true;
             // activate the search manager and start it up!
             mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
                     globalSearch, mSearchManagerCallback, mIdent);
@@ -1626,15 +1606,10 @@
      * @see #startSearch
      */
     public void stopSearch() {
-        if (DBG) debug("stopSearch(), mIsShowing=" + mIsShowing);
-        if (!mIsShowing) return;
+        if (DBG) debug("stopSearch()");
         try {
             mService.stopSearch();
-            // onDismiss will also clear this, but we do it here too since onDismiss() is
-            // called asynchronously.
-            mIsShowing = false;
         } catch (RemoteException ex) {
-            Log.e(TAG, "stopSearch() failed: " + ex);
         }
     }
 
@@ -1648,8 +1623,13 @@
      * @hide
      */
     public boolean isVisible() {
-        if (DBG) debug("isVisible(), mIsShowing=" + mIsShowing);
-        return mIsShowing;
+        if (DBG) debug("isVisible()");
+        try {
+            return mService.isVisible();
+        } catch (RemoteException e) {
+            Log.e(TAG, "isVisible() failed: " + e);
+            return false;
+        }
     }
 
     /**
@@ -1701,7 +1681,6 @@
         private final Runnable mFireOnDismiss = new Runnable() {
             public void run() {
                 if (DBG) debug("mFireOnDismiss");
-                mIsShowing = false;
                 if (mDismissListener != null) {
                     mDismissListener.onDismiss();
                 }
@@ -1711,7 +1690,6 @@
         private final Runnable mFireOnCancel = new Runnable() {
             public void run() {
                 if (DBG) debug("mFireOnCancel");
-                // doesn't need to clear mIsShowing since onDismiss() always gets called too
                 if (mCancelListener != null) {
                     mCancelListener.onCancel();
                 }
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index 9c760d9..9f609a3 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -369,30 +369,33 @@
                 // An existing server item has changed
                 // If serverSyncVersion is null, there is no edit URL;
                 // server won't let this change be written.
-                // Just hold onto it, I guess, in case the server permissions
-                // change later.
-                if (serverSyncVersion != null) {
-                    boolean recordChanged = (localSyncVersion == null) ||
-                            !serverSyncVersion.equals(localSyncVersion);
-                    if (recordChanged) {
-                        if (localSyncDirty) {
-                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                                Log.v(TAG, "remote record " + serverSyncId
-                                        + " conflicts with local _sync_id " + localSyncID
-                                        + ", local _id " + localRowId);
-                            }
-                            conflict = true;
-                        } else {
-                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                                Log.v(TAG,
-                                        "remote record " +
-                                                serverSyncId +
-                                                " updates local _sync_id " +
-                                                localSyncID + ", local _id " +
-                                                localRowId);
-                            }
-                            update = true;
+                boolean recordChanged = (localSyncVersion == null) ||
+                        (serverSyncVersion == null) ||
+                        !serverSyncVersion.equals(localSyncVersion);
+                if (recordChanged) {
+                    if (localSyncDirty) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "remote record " + serverSyncId
+                                    + " conflicts with local _sync_id " + localSyncID
+                                    + ", local _id " + localRowId);
                         }
+                        conflict = true;
+                    } else {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG,
+                                    "remote record " +
+                                            serverSyncId +
+                                            " updates local _sync_id " +
+                                            localSyncID + ", local _id " +
+                                            localRowId);
+                        }
+                        update = true;
+                    }
+                } else {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG,
+                                "Skipping update: localSyncVersion: " + localSyncVersion +
+                                ", serverSyncVersion: " + serverSyncVersion);
                     }
                 }
             } else {
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
index 70c7d73..d3ef5de 100644
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -45,8 +45,6 @@
     private static final String TAG = "SearchManagerService";
     private static final boolean DBG = false;
 
-    private static final String DISABLE_SEARCH_PROPERTY = "dev.disablesearchdialog";
-
     private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
     private static final int SEARCH_UI_THREAD_PRIORITY =
         android.os.Process.THREAD_PRIORITY_DEFAULT;
@@ -88,12 +86,11 @@
     
     // Identity of currently resumed activity.
     private int mResumedIdent = 0;
-    
-    // Allows disabling of search dialog for stress testing runs
-    private final boolean mDisabledOnBoot;
 
     // True if we have registered our receivers.
     private boolean mReceiverRegistered;
+
+    private volatile boolean mVisible = false;
     
     /**
      * Creates a new search dialog wrapper and a search UI thread. The search dialog itself will
@@ -104,8 +101,6 @@
     public SearchDialogWrapper(Context context) {
         mContext = context;
 
-        mDisabledOnBoot = !TextUtils.isEmpty(SystemProperties.get(DISABLE_SEARCH_PROPERTY));
-
         // Create the search UI thread
         HandlerThread t = new HandlerThread(SEARCH_UI_THREAD_NAME, SEARCH_UI_THREAD_PRIORITY);
         t.start();
@@ -115,6 +110,10 @@
         mSearchUiThread.sendEmptyMessage(MSG_INIT);
     }
 
+    public boolean isVisible() {
+        return mVisible;
+    }
+
     /**
      * Initializes the search UI.
      * Must be called from the search UI thread.
@@ -151,8 +150,10 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-                performStopSearch();
+                if (!"search".equals(intent.getStringExtra("reason"))) {
+                    if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+                    performStopSearch();
+                }
             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
                 performOnConfigurationChanged();
@@ -205,7 +206,7 @@
      * Can be called from any thread.
      */
     public void activityResuming(int ident) {
-        if (DBG) debug("startSearch()");
+        if (DBG) debug("activityResuming(ident=" + ident + ")");
         Message msg = Message.obtain();
         msg.what = MSG_ACTIVITY_RESUMING;
         msg.arg1 = ident;
@@ -256,20 +257,6 @@
 
     }
 
-    void updateDialogVisibility() {
-        if (mStartedIdent != 0) {
-            // mResumedIdent == 0 means we have just booted and the user
-            // hasn't yet gone anywhere.
-            if (mResumedIdent == 0 || mStartedIdent == mResumedIdent) {
-                if (DBG) Log.v(TAG, "******************* DIALOG: show");
-                mSearchDialog.show();
-            } else {
-                if (DBG) Log.v(TAG, "******************* DIALOG: hide");
-                mSearchDialog.hide();
-            }
-        }
-    }
-    
     /**
      * Actually launches the search UI.
      * This must be called on the search UI thread.
@@ -283,19 +270,20 @@
             int ident) {
         if (DBG) debug("performStartSearch()");
 
-        if (mDisabledOnBoot) {
-            Log.d(TAG, "ignoring start search request because " + DISABLE_SEARCH_PROPERTY
-                    + " system property is set.");
-            return;
-        }
-
         registerBroadcastReceiver();
         mCallback = searchManagerCallback;
+
+        // clean up any hidden dialog that we were waiting to resume
+        if (mStartedIdent != 0) {
+            mSearchDialog.dismiss();
+        }
+
         mStartedIdent = ident;
         if (DBG) Log.v(TAG, "******************* DIALOG: start");
+
         mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
                 globalSearch);
-        updateDialogVisibility();
+        mVisible = true;
     }
 
     /**
@@ -306,6 +294,7 @@
         if (DBG) debug("performStopSearch()");
         if (DBG) Log.v(TAG, "******************* DIALOG: cancel");
         mSearchDialog.cancel();
+        mVisible = false;
         mStartedIdent = 0;
     }
 
@@ -317,7 +306,21 @@
         if (DBG) debug("performResumingActivity(): mStartedIdent="
                 + mStartedIdent + ", resuming: " + ident);
         this.mResumedIdent = ident;
-        updateDialogVisibility();
+        if (mStartedIdent != 0) {
+            if (mStartedIdent == mResumedIdent) {
+                // we are resuming into the activity where we previously hid the dialog, bring it
+                // back
+                if (DBG) Log.v(TAG, "******************* DIALOG: show");
+                mSearchDialog.show();
+                mVisible = true;
+            } else {
+                // resuming into some other activity; hide ourselves in case we ever come back
+                // so we can show ourselves quickly again
+                if (DBG) Log.v(TAG, "******************* DIALOG: hide");
+                mSearchDialog.hide();
+                mVisible = false;
+            }
+        }
     }
 
     /**
@@ -333,27 +336,38 @@
      */
     public void onDismiss(DialogInterface dialog) {
         if (DBG) debug("onDismiss()");
-        if (mCallback != null) {
-            try {
-                // should be safe to do on the search UI thread, since it's a oneway interface
-                mCallback.onDismiss();
-            } catch (DeadObjectException ex) {
-                // The process that hosted the callback has died, do nothing
-            } catch (RemoteException ex) {
-                Log.e(TAG, "onDismiss() failed: " + ex);
-            }
-            // we don't need the callback anymore, release it
-            mCallback = null;
-        }
+        mStartedIdent = 0;
+        mVisible = false;
+        callOnDismiss();
+
+        // we don't need the callback anymore, release it
+        mCallback = null;
         unregisterBroadcastReceiver();
     }
 
+
     /**
      * Called by {@link SearchDialog} when the user or activity cancels search.
      * Whenever this method is called, {@link #onDismiss} is always called afterwards.
      */
     public void onCancel(DialogInterface dialog) {
         if (DBG) debug("onCancel()");
+        callOnCancel();
+    }
+
+    private void callOnDismiss() {
+        if (mCallback == null) return;
+        try {
+            // should be safe to do on the search UI thread, since it's a oneway interface
+            mCallback.onDismiss();
+        } catch (DeadObjectException ex) {
+            // The process that hosted the callback has died, do nothing
+        } catch (RemoteException ex) {
+            Log.e(TAG, "onDismiss() failed: " + ex);
+        }
+    }
+
+    private void callOnCancel() {
         if (mCallback != null) {
             try {
                 // should be safe to do on the search UI thread, since it's a oneway interface
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index 7629912..fdeb8f9 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -238,4 +238,8 @@
         getSearchDialog().stopSearch();
     }
 
+    public boolean isVisible() {
+        return mSearchDialog != null && mSearchDialog.isVisible();
+    }
+
 }
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 4794fe1..4e0a87c 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -820,14 +820,14 @@
                 if (speechRate > 0) {
                     int rate = (int)(speechRate*100);
                     mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = String.valueOf(rate);
-                    result = mITts.setSpeechRate(mPackageName, 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;
+                    } else {
+                        result = TTS_ERROR;
+                    }
                 }
-            } catch (RemoteException e) {
-                // TTS died; restart it.
-                Log.e("TextToSpeech.java - setSpeechRate", "RemoteException");
-                e.printStackTrace();
-                mStarted = false;
-                initTts();
             } catch (NullPointerException e) {
                 // TTS died; restart it.
                 Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException");
@@ -907,7 +907,9 @@
      * @param loc
      *            The locale describing the language to be used.
      *
-     * @return Code indicating the support status for the locale. See the TTS_LANG_ codes.
+     * @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}.
      */
     public int setLanguage(Locale loc) {
         synchronized (mStartLock) {
@@ -919,7 +921,10 @@
                 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();
-                result = mITts.setLanguage(mPackageName,
+                // the language is not set here, instead it is cached so it will be associated
+                // with all upcoming utterances. But we still need to change 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] );
@@ -994,8 +999,9 @@
      * @param loc
      *            The Locale describing the language to be used.
      *
-     * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
-     *         TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE.
+     * @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}.
      */
     public int isLanguageAvailable(Locale loc) {
         synchronized (mStartLock) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 0df587f..4bc00de 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1296,11 +1296,8 @@
             }
         }
 
-        // Max height available on the screen for a popup. If this AutoCompleteTextView has
-        // the dropDownAlwaysVisible attribute, and the input method is not currently required,
-        // we then we ask for the height ignoring any bottom decorations like the input method.
-        // Otherwise we respect the input method.
-        boolean ignoreBottomDecorations = mDropDownAlwaysVisible &&
+        // Max height available on the screen for a popup.
+        boolean ignoreBottomDecorations =
                 mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
         final int maxHeight = mPopup.getMaxAvailableHeight(
                 getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 68e3fb7..82067be 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -59,6 +59,9 @@
 // ----------------------------------------------------------------------------
 static fields_t javaTTSFields;
 
+// TODO move to synth member once we have multiple simultaneous engines running
+static Mutex engineMutex;
+
 // ----------------------------------------------------------------------------
 class SynthProxyJniStorage {
     public :
@@ -194,7 +197,6 @@
         if (bufferSize > 0) {
             prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
             if (pJniData->mAudioOut) {
-                pJniData->mAudioOut->start();
                 pJniData->mAudioOut->write(wav, bufferSize);
                 memset(wav, 0, bufferSize);
                 //LOGV("AudioTrack wrote: %d bytes", bufferSize);
@@ -331,6 +333,8 @@
         return result;
     }
 
+    Mutex::Autolock l(engineMutex);
+
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     const char *langNativeString = env->GetStringUTFChars(language, 0);
     const char *countryNativeString = env->GetStringUTFChars(country, 0);
@@ -390,6 +394,8 @@
     char buffer [bufSize];
     sprintf(buffer, "%d", speechRate);
 
+    Mutex::Autolock l(engineMutex);
+
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     LOGI("setting speech rate to %d", speechRate);
 
@@ -412,6 +418,8 @@
         return result;
     }
 
+    Mutex::Autolock l(engineMutex);
+
     int bufSize = 10;
     char buffer [bufSize];
     sprintf(buffer, "%d", pitch);
@@ -444,6 +452,8 @@
         return result;
     }
 
+    Mutex::Autolock l(engineMutex);
+
     // Retrieve audio parameters before writing the file header
     AudioSystem::audio_format encoding = DEFAULT_TTS_FORMAT;
     uint32_t rate = DEFAULT_TTS_RATE;
@@ -546,10 +556,12 @@
         return result;
     }
 
+    Mutex::Autolock l(engineMutex);
+
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
 
     if (pSynthData->mAudioOut) {
-        pSynthData->mAudioOut->stop();
+        pSynthData->mAudioOut->start();
     }
 
     afterSynthData_t* pForAfter = new (afterSynthData_t);
@@ -600,6 +612,8 @@
         return;
     }
 
+    Mutex::Autolock l(engineMutex);
+
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     if (pSynthData->mNativeSynthInterface) {
         pSynthData->mNativeSynthInterface->shutdown();
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 28801f8..9a4c97d 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -546,7 +546,7 @@
                     if (!synthAvailable) {
                         Thread.sleep(100);
                         Thread synth = (new Thread(new SynthThread()));
-                        synth.setPriority(Thread.MIN_PRIORITY);
+                        //synth.setPriority(Thread.MIN_PRIORITY);
                         synth.start();
                         return;
                     }
@@ -608,7 +608,7 @@
             }
         }
         Thread synth = (new Thread(new SynthThread()));
-        synth.setPriority(Thread.MIN_PRIORITY);
+        //synth.setPriority(Thread.MIN_PRIORITY);
         synth.start();
     }
 
@@ -623,7 +623,7 @@
                     if (!synthAvailable) {
                         Thread.sleep(100);
                         Thread synth = (new Thread(new SynthThread()));
-                        synth.setPriority(Thread.MIN_PRIORITY);
+                        //synth.setPriority(Thread.MIN_PRIORITY);
                         synth.start();
                         return;
                     }
@@ -677,7 +677,7 @@
             }
         }
         Thread synth = (new Thread(new SynthThread()));
-        synth.setPriority(Thread.MIN_PRIORITY);
+        //synth.setPriority(Thread.MIN_PRIORITY);
         synth.start();
     }
 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 5425709..2937ed0 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -27,6 +27,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -1857,7 +1858,7 @@
         // is running.
         if (!mDisplayFrozen) {
             Animation a;
-            if ((lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+            if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
                 a = new FadeInOutAnimation(enter);
                 if (DEBUG_ANIM) Log.v(TAG,
                         "applying FadeInOutAnimation for a window in compatibility mode");
@@ -5871,7 +5872,9 @@
 
             if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
                 container.intersect(mCompatibleScreenFrame);
-                display.intersect(mCompatibleScreenFrame);
+                if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
+                    display.intersect(mCompatibleScreenFrame);
+                }
             }
 
             final int pw = container.right - container.left;
@@ -6588,12 +6591,17 @@
                 return false;
             }
             final Rect frame = shownFrame ? mShownFrame : mFrame;
-            if (frame.left <= 0 && frame.top <= 0
-                    && frame.right >= screenWidth
-                    && frame.bottom >= screenHeight) {
-                return true;
+
+            if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+                return frame.left <= mCompatibleScreenFrame.left &&
+                        frame.top <= mCompatibleScreenFrame.top &&
+                        frame.right >= mCompatibleScreenFrame.right &&
+                        frame.bottom >= mCompatibleScreenFrame.bottom;
+            } else {
+                return frame.left <= 0 && frame.top <= 0
+                        && frame.right >= screenWidth
+                        && frame.bottom >= screenHeight;
             }
-            return false;
         }
 
         /**
@@ -6610,16 +6618,13 @@
                  (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
                  // only if it's visible
                  mHasDrawn && mViewVisibility == View.VISIBLE &&
-                 // and only if the application wanted to fill the screen
-                 mAttrs.width == mAttrs.FILL_PARENT &&
-                 mAttrs.height == mAttrs.FILL_PARENT &&
-                 // and only if the window is not hidden
-                 mFrame.left == mCompatibleScreenFrame.left &&
+                 // and only if the application fills the compatible screen
+                 mFrame.left <= mCompatibleScreenFrame.left &&
+                 mFrame.top <= mCompatibleScreenFrame.top &&
+                 mFrame.right >= mCompatibleScreenFrame.right &&
+                 mFrame.bottom >= mCompatibleScreenFrame.bottom &&
                  // and starting window do not need background filler
-                 mAttrs.type != mAttrs.TYPE_APPLICATION_STARTING &&
-                 // and only if the screen is bigger
-                 ((mFrame.right - mFrame.right) < screenWidth ||
-                         (mFrame.bottom - mFrame.top) < screenHeight);
+                 mAttrs.type != mAttrs.TYPE_APPLICATION_STARTING;
         }
 
         boolean isFullscreen(int screenWidth, int screenHeight) {
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 55d4d64..845f547 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -48,6 +48,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.WRITE_GSERVICES" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
 
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java b/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java
new file mode 100755
index 0000000..7dc1314
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/VpnTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.net.vpn.L2tpIpsecProfile;
+import android.net.vpn.VpnType;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Unit test class to test VPN api
+ * Use the below command to run the vpn unit test only
+ * runtest vpntest or
+ * adb shell am instrument -e class 'com.android.unit_tests.VpnTest'
+ *   -w com.android.unit_tests/android.test.InstrumentationTestRunner
+ */
+public class VpnTest extends AndroidTestCase {
+
+    @Override
+    public void setUp() {
+    }
+
+    @Override
+    public void tearDown() {
+    }
+
+    @SmallTest
+    public void testGetType() {
+        L2tpIpsecProfile li = new L2tpIpsecProfile();
+        assertTrue(VpnType.L2TP_IPSEC== li.getType());
+    }
+}