Merge "Begin hooking up SurfaceConfig."
diff --git a/api/current.xml b/api/current.xml
index fde5d21..d517325 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -198458,6 +198458,17 @@
  visibility="public"
 >
 </field>
+<field name="SHOW_AS_ACTION_WITH_TEXT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </interface>
 <interface name="MenuItem.OnMenuItemClickListener"
  abstract="true"
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 2fadb82..d78c68a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -320,6 +320,13 @@
     private native void nSetMatrix(int renderer, int matrix);
 
     @Override
+    public int getNativeMatrix() {
+        return nGetMatrix(mRenderer);
+    }
+
+    private native int nGetMatrix(int renderer);    
+
+    @Override
     public void getMatrix(Matrix matrix) {
         nGetMatrix(mRenderer, matrix.native_instance);
     }
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 8b9d659..99da43b 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -45,6 +45,12 @@
      * A good rule of thumb is to have no more than 2 items set to always show at a time.
      */
     public static final int SHOW_AS_ACTION_ALWAYS = 2;
+
+    /**
+     * When this item is in the action bar, always show it with a text label even if
+     * it also has an icon specified.
+     */
+    public static final int SHOW_AS_ACTION_WITH_TEXT = 4;
     
     /**
      * Interface definition for a callback to be invoked when a menu item is
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index cfd6754..361b27e 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -20,15 +20,23 @@
 
 import com.android.internal.R;
 
+import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
+import android.speech.RecognizerIntent;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -66,6 +74,7 @@
     private View mSubmitButton;
     private View mCloseButton;
     private View mSearchEditFrame;
+    private View mVoiceButton;
     private AutoCompleteTextView mQueryTextView;
     private boolean mSubmitButtonEnabled;
     private CharSequence mQueryHint;
@@ -74,6 +83,10 @@
 
     private SearchableInfo mSearchable;
 
+    // For voice searching
+    private final Intent mVoiceWebSearchIntent;
+    private final Intent mVoiceAppSearchIntent;
+
     // A weak map of drawables we've gotten from other packages, so we don't load them
     // more than once.
     private final WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache =
@@ -162,10 +175,13 @@
         mSearchEditFrame = findViewById(R.id.search_edit_frame);
         mSubmitButton = findViewById(R.id.search_go_btn);
         mCloseButton = findViewById(R.id.search_close_btn);
+        mVoiceButton = findViewById(R.id.search_voice_btn);
 
         mSearchButton.setOnClickListener(mOnClickListener);
         mCloseButton.setOnClickListener(mOnClickListener);
         mSubmitButton.setOnClickListener(mOnClickListener);
+        mVoiceButton.setOnClickListener(mOnClickListener);
+
         mQueryTextView.addTextChangedListener(mTextWatcher);
         mQueryTextView.setOnEditorActionListener(mOnEditorActionListener);
         mQueryTextView.setOnItemClickListener(mOnItemClickListener);
@@ -184,6 +200,15 @@
         setIconifiedByDefault(a.getBoolean(R.styleable.SearchView_iconifiedByDefault, true));
         a.recycle();
 
+        // Save voice intent for later queries/launching
+        mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+        mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
+                RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
+
+        mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+        mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
         updateViewsVisibility(mIconifiedByDefault);
     }
 
@@ -206,12 +231,8 @@
     /** @hide */
     @Override
     public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
-        if (mClearingFocus) return false;
-        boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect);
-        if (result && !isIconified()) {
-            setImeVisibility(true);
-        }
-        return result;
+        if (mClearingFocus || isIconified()) return false;
+        return mQueryTextView.requestFocus(direction, previouslyFocusedRect);
     }
 
     /** @hide */
@@ -299,6 +320,7 @@
      * @param iconified whether the search field should be iconified by default
      */
     public void setIconifiedByDefault(boolean iconified) {
+        if (mIconifiedByDefault == iconified) return;
         mIconifiedByDefault = iconified;
         updateViewsVisibility(iconified);
         setImeVisibility(!iconified);
@@ -349,8 +371,8 @@
      * button is not required.
      */
     public void setSubmitButtonEnabled(boolean enabled) {
-        mSubmitButton.setVisibility(enabled ? VISIBLE : GONE);
         mSubmitButtonEnabled = enabled;
+        updateViewsVisibility(isIconified());
     }
 
     /**
@@ -424,6 +446,7 @@
         mSearchButton.setVisibility(visCollapsed);
         mSubmitButton.setVisibility(mSubmitButtonEnabled && hasText ? visExpanded : GONE);
         mSearchEditFrame.setVisibility(visExpanded);
+        updateVoiceButton(!hasText);
     }
 
     private void setImeVisibility(boolean visible) {
@@ -458,6 +481,8 @@
                 onCloseClicked();
             } else if (v == mSubmitButton) {
                 onSubmitQuery();
+            } else if (v == mVoiceButton) {
+                onVoiceClicked();
             }
         }
     };
@@ -525,6 +550,34 @@
         }
     }
 
+    /**
+     * Update the visibility of the voice button.  There are actually two voice search modes,
+     * either of which will activate the button.
+     * @param empty whether the search query text field is empty. If it is, then the other
+     * criteria apply to make the voice button visible. Otherwise the voice button will not
+     * be visible - i.e., if the user has typed a query, remove the voice button.
+     */
+    private void updateVoiceButton(boolean empty) {
+        int visibility = View.GONE;
+        if (mSearchable != null && mSearchable.getVoiceSearchEnabled() && empty
+                && !isIconified()) {
+            Intent testIntent = null;
+            if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+                testIntent = mVoiceWebSearchIntent;
+            } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+                testIntent = mVoiceAppSearchIntent;
+            }
+            if (testIntent != null) {
+                ResolveInfo ri = getContext().getPackageManager().resolveActivity(testIntent,
+                        PackageManager.MATCH_DEFAULT_ONLY);
+                if (ri != null) {
+                    visibility = View.VISIBLE;
+                }
+            }
+        }
+        mVoiceButton.setVisibility(visibility);
+    }
+
     private final OnEditorActionListener mOnEditorActionListener = new OnEditorActionListener() {
 
         /**
@@ -542,8 +595,10 @@
         if (isSubmitButtonEnabled()) {
             mSubmitButton.setVisibility(hasText ? VISIBLE : GONE);
         }
-        if (mOnQueryChangeListener != null)
+        updateVoiceButton(!hasText);
+        if (mOnQueryChangeListener != null) {
             mOnQueryChangeListener.onQueryTextChanged(newText.toString());
+        }
     }
 
     private void onSubmitQuery() {
@@ -555,21 +610,27 @@
                     launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
                     setImeVisibility(false);
                 }
+                dismissSuggestions();
             }
         }
     }
 
+    private void dismissSuggestions() {
+        mQueryTextView.dismissDropDown();
+    }
+
     private void onCloseClicked() {
         if (mOnCloseListener == null || !mOnCloseListener.onClose()) {
             CharSequence text = mQueryTextView.getText();
             if (TextUtils.isEmpty(text)) {
                 // query field already empty, hide the keyboard and remove focus
-                mQueryTextView.clearFocus();
+                clearFocus();
                 setImeVisibility(false);
             } else {
                 mQueryTextView.setText("");
             }
             updateViewsVisibility(mIconifiedByDefault);
+            if (mIconifiedByDefault) setImeVisibility(false);
         }
     }
 
@@ -579,6 +640,29 @@
         setImeVisibility(true);
     }
 
+    private void onVoiceClicked() {
+        // guard against possible race conditions
+        if (mSearchable == null) {
+            return;
+        }
+        SearchableInfo searchable = mSearchable;
+        try {
+            if (searchable.getVoiceSearchLaunchWebSearch()) {
+                Intent webSearchIntent = createVoiceWebSearchIntent(mVoiceWebSearchIntent,
+                        searchable);
+                getContext().startActivity(webSearchIntent);
+            } else if (searchable.getVoiceSearchLaunchRecognizer()) {
+                Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent,
+                        searchable);
+                getContext().startActivity(appSearchIntent);
+            }
+        } catch (ActivityNotFoundException e) {
+            // Should not happen, since we check the availability of
+            // voice search before showing the button. But just in case...
+            Log.w(LOG_TAG, "Could not find voice search activity");
+        }
+    }
+
     private final OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
 
         /**
@@ -590,6 +674,7 @@
             if (mOnSuggestionListener == null
                     || !mOnSuggestionListener.onSuggestionClicked(position)) {
                 launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
+                dismissSuggestions();
             }
         }
     };
@@ -742,6 +827,79 @@
     }
 
     /**
+     * Create and return an Intent that can launch the voice search activity for web search.
+     */
+    private Intent createVoiceWebSearchIntent(Intent baseIntent, SearchableInfo searchable) {
+        Intent voiceIntent = new Intent(baseIntent);
+        ComponentName searchActivity = searchable.getSearchActivity();
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, searchActivity == null ? null
+                : searchActivity.flattenToShortString());
+        return voiceIntent;
+    }
+
+    /**
+     * Create and return an Intent that can launch the voice search activity, perform a specific
+     * voice transcription, and forward the results to the searchable activity.
+     *
+     * @param baseIntent The voice app search intent to start from
+     * @return A completely-configured intent ready to send to the voice search activity
+     */
+    private Intent createVoiceAppSearchIntent(Intent baseIntent, SearchableInfo searchable) {
+        ComponentName searchActivity = searchable.getSearchActivity();
+
+        // create the necessary intent to set up a search-and-forward operation
+        // in the voice search system.   We have to keep the bundle separate,
+        // because it becomes immutable once it enters the PendingIntent
+        Intent queryIntent = new Intent(Intent.ACTION_SEARCH);
+        queryIntent.setComponent(searchActivity);
+        PendingIntent pending = PendingIntent.getActivity(getContext(), 0, queryIntent,
+                PendingIntent.FLAG_ONE_SHOT);
+
+        // Now set up the bundle that will be inserted into the pending intent
+        // when it's time to do the search.  We always build it here (even if empty)
+        // because the voice search activity will always need to insert "QUERY" into
+        // it anyway.
+        Bundle queryExtras = new Bundle();
+
+        // Now build the intent to launch the voice search.  Add all necessary
+        // extras to launch the voice recognizer, and then all the necessary extras
+        // to forward the results to the searchable activity
+        Intent voiceIntent = new Intent(baseIntent);
+
+        // Add all of the configuration options supplied by the searchable's metadata
+        String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM;
+        String prompt = null;
+        String language = null;
+        int maxResults = 1;
+
+        Resources resources = getResources();
+        if (searchable.getVoiceLanguageModeId() != 0) {
+            languageModel = resources.getString(searchable.getVoiceLanguageModeId());
+        }
+        if (searchable.getVoicePromptTextId() != 0) {
+            prompt = resources.getString(searchable.getVoicePromptTextId());
+        }
+        if (searchable.getVoiceLanguageId() != 0) {
+            language = resources.getString(searchable.getVoiceLanguageId());
+        }
+        if (searchable.getVoiceMaxResults() != 0) {
+            maxResults = searchable.getVoiceMaxResults();
+        }
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, searchActivity == null ? null
+                : searchActivity.flattenToShortString());
+
+        // Add the values that configure forwarding the results
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras);
+
+        return voiceIntent;
+    }
+
+    /**
      * When a particular suggestion has been selected, perform the various lookups required
      * to use the suggestion.  This includes checking the cursor for suggestion-specific data,
      * and/or falling back to the XML for defaults;  It also creates REST style Uri data when
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 57fd251..9c80ef8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7708,28 +7708,36 @@
             if (canSelectText()) {
                 menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
                     setIcon(com.android.internal.R.drawable.ic_menu_select_all).
-                    setAlphabeticShortcut('a');
+                    setAlphabeticShortcut('a').
+                    setShowAsAction(
+                            MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
                 atLeastOne = true;
             }
 
             if (canCut()) {
                 menu.add(0, ID_CUT, 0, com.android.internal.R.string.cut).
                     setIcon(styledAttributes.getResourceId(R.styleable.Theme_actionModeCutDrawable, 0)).
-                    setAlphabeticShortcut('x');
+                    setAlphabeticShortcut('x').
+                    setShowAsAction(
+                            MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
                 atLeastOne = true;
             }
 
             if (canCopy()) {
                 menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
                     setIcon(styledAttributes.getResourceId(R.styleable.Theme_actionModeCopyDrawable, 0)).
-                    setAlphabeticShortcut('c');
+                    setAlphabeticShortcut('c').
+                    setShowAsAction(
+                            MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
                 atLeastOne = true;
             }
 
             if (canPaste()) {
                 menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
                         setIcon(styledAttributes.getResourceId(R.styleable.Theme_actionModePasteDrawable, 0)).
-                        setAlphabeticShortcut('v');
+                        setAlphabeticShortcut('v').
+                        setShowAsAction(
+                                MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
                 atLeastOne = true;
             }
 
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index f97bfb4..d5f69ba 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -21,13 +21,13 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.Button;
-import android.widget.FrameLayout;
 import android.widget.ImageButton;
+import android.widget.LinearLayout;
 
 /**
  * @hide
  */
-public class ActionMenuItemView extends FrameLayout
+public class ActionMenuItemView extends LinearLayout
         implements MenuView.ItemView, View.OnClickListener {
     private static final String TAG = "ActionMenuItemView";
 
@@ -65,8 +65,6 @@
     public void initialize(MenuItemImpl itemData, int menuType) {
         mItemData = itemData;
 
-        setClickable(true);
-        setFocusable(true);
         setIcon(itemData.getIcon());
         setTitle(itemData.getTitle()); // Title only takes effect if there is no icon
         setId(itemData.getItemId());
@@ -128,7 +126,7 @@
         // populate accessibility description with title
         setContentDescription(title);
 
-        if (mImageButton.getDrawable() == null) {
+        if (mImageButton.getDrawable() == null || mItemData.showsTextAsAction()) {
             mTextButton.setText(mTitle);
             mTextButton.setVisibility(VISIBLE);
         }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 42f9771..8eee360 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -38,6 +38,10 @@
 public final class MenuItemImpl implements MenuItem {
     private static final String TAG = "MenuItemImpl";
     
+    private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
+            SHOW_AS_ACTION_IF_ROOM |
+            SHOW_AS_ACTION_ALWAYS;
+
     private final int mId;
     private final int mGroup;
     private final int mCategoryOrder;
@@ -649,11 +653,11 @@
     }
     
     public boolean requestsActionButton() {
-        return mShowAsAction == SHOW_AS_ACTION_IF_ROOM;
+        return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
     }
     
     public boolean requiresActionButton() {
-        return mShowAsAction == SHOW_AS_ACTION_ALWAYS;
+        return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
     }
 
     public void setIsActionButton(boolean isActionButton) {
@@ -664,7 +668,23 @@
         }
     }
 
+    public boolean showsTextAsAction() {
+        return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT;
+    }
+
     public void setShowAsAction(int actionEnum) {
+        switch (actionEnum & SHOW_AS_ACTION_MASK) {
+            case SHOW_AS_ACTION_ALWAYS:
+            case SHOW_AS_ACTION_IF_ROOM:
+            case SHOW_AS_ACTION_NEVER:
+                // Looks good!
+                break;
+
+            default:
+                // Mutually exclusive options selected!
+                throw new IllegalArgumentException("SHOW_AS_ACTION_ALWAYS, SHOW_AS_ACTION_IF_ROOM,"
+                        + " and SHOW_AS_ACTION_NEVER are mutually exclusive.");
+        }
         mShowAsAction = actionEnum;
         mMenu.onItemActionRequestChanged(this);
     }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index dfa614c..cfa9a27 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -218,6 +218,11 @@
     renderer->setMatrix(matrix);
 }
 
+static const float* android_view_GLES20Canvas_getNativeMatrix(JNIEnv* env,
+        jobject canvas, OpenGLRenderer* renderer) {
+    return renderer->getMatrix();
+}
+
 static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject canvas,
         OpenGLRenderer* renderer, SkMatrix* matrix) {
     renderer->getMatrix(matrix);
@@ -468,6 +473,7 @@
     { "nScale",             "(IFF)V",          (void*) android_view_GLES20Canvas_scale },
 
     { "nSetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_setMatrix },
+    { "nGetMatrix",         "(I)I",            (void*) android_view_GLES20Canvas_getNativeMatrix },
     { "nGetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_getMatrix },
     { "nConcatMatrix",      "(II)V",           (void*) android_view_GLES20Canvas_concatMatrix },
 
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index c229b59..b60261e 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -23,14 +23,14 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
-    android:focusable="true"
-    android:descendantFocusability="afterDescendants">
+    >
 
     <!-- This is actually used for the badge icon *or* the badge label (or neither) -->
     <TextView
         android:id="@+id/search_badge"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_vertical"
         android:layout_marginBottom="2dip"
         android:drawablePadding="0dip"
         android:textAppearance="?android:attr/textAppearanceSmall"
@@ -41,7 +41,7 @@
     <ImageView
         android:id="@+id/search_button"
         android:layout_height="36dip"
-        android:layout_width="36dip"
+        android:layout_width="match_parent"
         android:layout_marginRight="7dip"
         android:layout_gravity="center_vertical"
         android:src="@android:drawable/ic_btn_search"
@@ -51,7 +51,7 @@
     <LinearLayout
         android:id="@+id/search_edit_frame"
         android:layout_width="300dp"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
         android:visibility="gone"
         android:orientation="horizontal"
         android:background="?android:attr/editTextBackground">
@@ -70,6 +70,7 @@
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
             android:layout_weight="1"
+            android:layout_gravity="bottom"
             android:paddingLeft="8dip"
             android:paddingRight="6dip"
             android:drawablePadding="2dip"
@@ -86,6 +87,7 @@
             android:popupBackground="@android:drawable/search_dropdown_background"
         />
 
+        <!-- TODO: Use the generic dialog close drawable -->
         <ImageView
             android:id="@+id/search_close_btn"
             android:layout_width="24dp"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1ea6fc4..ef6d6cb 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3590,10 +3590,22 @@
         <attr name="onClick" />
 
         <!-- How this item should display in the Action Bar, if present. -->
-        <attr name="showAsAction" format="enum">
-            <enum name="never" value="0" />
-            <enum name="ifRoom" value="1" />
-            <enum name="always" value="2" />
+        <attr name="showAsAction">
+            <!-- Never show this item in an action bar, show it in the overflow menu instead.
+                 Mutually exclusive with "ifRoom" and "always". -->
+            <flag name="never" value="0" />
+            <!-- Show this item in an action bar if there is room for it as determined
+                 by the system. Favor this option over "always" where possible.
+                 Mutually exclusive with "never" and "always". -->
+            <flag name="ifRoom" value="1" />
+            <!-- Always show this item in an actionbar, even if it would override
+                 the system's limits of how much stuff to put there. This may make
+                 your action bar look bad on some screens. In most cases you should
+                 use "ifRoom" instead. Mutually exclusive with "ifRoom" and "never". -->
+            <flag name="always" value="2" />
+            <!-- When this item is shown as an action in the action bar, show a text
+                 label with it even if it has an icon representation. -->
+            <flag name="withText" value="4" />
         </attr>
 
         <!-- An optional layout to be used as an action view.
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 952f2b5..07fe66c 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -447,6 +447,16 @@
     public void getMatrix(Matrix ctm) {
         native_getCTM(mNativeCanvas, ctm.native_instance);
     }
+
+    /**
+     * Returns a pointer to an internal 4x4 native matrix. The returned
+     * pointer is a pointer to an array of 16 floats.
+     * 
+     * @hide
+     */
+    public int getNativeMatrix() {
+        return 0;
+    }
     
     /**
      * Return a new matrix with a copy of the canvas' current transformation
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ffd0aed..92875b1 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -584,6 +584,10 @@
     mSnapshot->transform->load(*matrix);
 }
 
+const float* OpenGLRenderer::getMatrix() const {
+    return &mSnapshot->transform->data[0];
+}
+
 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
     mSnapshot->transform->copyTo(*matrix);
 }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 9900a27..f8828e2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -87,6 +87,7 @@
     virtual void rotate(float degrees);
     virtual void scale(float sx, float sy);
 
+    const float* getMatrix() const;
     void getMatrix(SkMatrix* matrix);
     virtual void setMatrix(SkMatrix* matrix);
     virtual void concatMatrix(SkMatrix* matrix);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index efd0e0a..7dd1909 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -45,8 +45,6 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.DetailedState;
 import android.net.LinkProperties;
-import android.net.ProxyProperties;
-import android.net.wifi.WifiConfiguration.Status;
 import android.os.Binder;
 import android.os.Message;
 import android.os.Parcelable;
@@ -60,7 +58,6 @@
 import android.os.Process;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -70,26 +67,18 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
-import android.content.ContentResolver;
 import android.content.Intent;
 import android.content.Context;
-import android.database.ContentObserver;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.HierarchicalState;
 import com.android.internal.util.HierarchicalStateMachine;
 
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
+
 import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
 
@@ -1511,8 +1500,8 @@
     }
 
     /**
-     * Send the tracker a notification that a connection to the supplicant
-     * daemon has been established.
+     * Send the tracker a notification that connection to the supplicant
+     * daemon is lost
      */
     void notifySupplicantLost() {
         sendMessage(SUP_DISCONNECTION_EVENT);
@@ -1944,16 +1933,18 @@
                     sendSupplicantConnectionChangedBroadcast(true);
                     transitionTo(mDriverSupReadyState);
                     break;
-                case CMD_STOP_SUPPLICANT:
-                    Log.d(TAG, "Stop supplicant received");
+                case SUP_DISCONNECTION_EVENT:
+                    Log.e(TAG, "Failed to setup control channel, restart supplicant");
                     WifiNative.stopSupplicant();
                     transitionTo(mDriverLoadedState);
+                    sendMessageAtFrontOfQueue(CMD_START_SUPPLICANT);
                     break;
-                    /* Fail soft ap when waiting for supplicant start */
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
                 case CMD_START_AP:
-                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
-                    setWifiApState(WIFI_AP_STATE_FAILED);
-                    break;
+                case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
@@ -1966,10 +1957,6 @@
                 case CMD_STOP_PACKET_FILTERING:
                     deferMessage(message);
                     break;
-                case CMD_STOP_AP:
-                case CMD_START_SUPPLICANT:
-                case CMD_UNLOAD_DRIVER:
-                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -1993,23 +1980,24 @@
             WifiConfiguration config;
             switch(message.what) {
                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
                     Log.d(TAG, "Stop supplicant received");
+                    WifiNative.closeSupplicantConnection();
                     WifiNative.stopSupplicant();
-                    //$FALL-THROUGH$
+                    handleNetworkDisconnect();
+                    sendSupplicantConnectionChangedBroadcast(false);
+                    mSupplicantStateTracker.resetSupplicantState();
+                    transitionTo(mDriverLoadedState);
+                    break;
                 case SUP_DISCONNECTION_EVENT:  /* Supplicant died */
                     EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    Log.e(TAG, "Supplicant died, restarting");
                     WifiNative.closeSupplicantConnection();
                     handleNetworkDisconnect();
                     sendSupplicantConnectionChangedBroadcast(false);
                     mSupplicantStateTracker.resetSupplicantState();
                     transitionTo(mDriverLoadedState);
-
-                    /* When supplicant dies, unload driver and enter failed state */
-                    //TODO: consider bringing up supplicant again
-                    if (message.what == SUP_DISCONNECTION_EVENT) {
-                        Log.d(TAG, "Supplicant died, unloading driver");
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
-                    }
+                    sendMessageAtFrontOfQueue(CMD_START_SUPPLICANT); /* restart */
                     break;
                 case CMD_START_DRIVER:
                     EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
@@ -2171,15 +2159,6 @@
                 transitionTo(mScanModeState);
             } else {
                 WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
-                /* If supplicant has already connected, before we could finish establishing
-                 * the control channel connection, we miss all the supplicant events.
-                 * Disconnect and reconnect when driver has started to ensure we receive
-                 * all supplicant events.
-                 *
-                 * TODO: This is a bit unclean, ideally the supplicant should never
-                 * connect until told to do so by the framework
-                 */
-                WifiNative.disconnectCommand();
                 WifiNative.reconnectCommand();
                 transitionTo(mConnectModeState);
             }
@@ -2564,7 +2543,6 @@
 
           switch(message.what) {
               case CMD_IP_CONFIG_SUCCESS:
-                  mReconnectCount = 0;
                   mLastSignalLevel = -1; // force update of signal strength
                   synchronized (mDhcpInfo) {
                       mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
@@ -2585,9 +2563,10 @@
                    * to a given network, disable the network
                    */
                   if (++mReconnectCount > getMaxDhcpRetries()) {
-                          Log.e(TAG, "Failed " +
-                                  mReconnectCount + " times, Disabling " + mLastNetworkId);
+                      Log.e(TAG, "Failed " +
+                              mReconnectCount + " times, Disabling " + mLastNetworkId);
                       WifiConfigStore.disableNetwork(mLastNetworkId);
+                      mReconnectCount = 0;
                   }
 
                   /* DHCP times out after about 30 seconds, we do a