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