Merge "Init car mode when phone is booted in a dock."
diff --git a/common/java/com/android/common/speech/Recognition.java b/common/java/com/android/common/speech/Recognition.java
index 6f164a9..bf60c9a 100644
--- a/common/java/com/android/common/speech/Recognition.java
+++ b/common/java/com/android/common/speech/Recognition.java
@@ -19,7 +19,8 @@
/**
* Utilities for voice recognition implementations.
*
- * @see android.app.RecognitionService
+ * @see android.speech.RecognitionService
+ * @see android.speech.RecognizerIntent
*/
public class Recognition {
@@ -30,7 +31,39 @@
* is set by anyone but the system process, it should be overridden by the voice search
* implementation.
*/
- public final static String EXTRA_CALLING_PACKAGE = "calling_package";
+ public static final String EXTRA_CALLING_PACKAGE = "calling_package";
+
+ /**
+ * The key to the extra in the Bundle returned by
+ * android.speech.RecognizerIntent#ACTION_GET_LANGUAGE_DETAILS
+ * which is an ArrayList of CharSequences which are hints that can be shown to
+ * the user for voice actions currently supported by voice search for the user's current
+ * language preference for voice search (i.e., the one defined in the extra
+ * android.speech.RecognizerIntent#EXTRA_LANGUAGE_PREFERENCE).
+ *
+ * If this is paired with EXTRA_HINT_CONTEXT, should return a set of hints that are
+ * appropriate for the provided context.
+ *
+ * The CharSequences are SpannedStrings and will contain segments wrapped in
+ * <annotation action="true"></annotation>. This is to indicate the section of the text
+ * which represents the voice action, to be highlighted in the UI if so desired.
+ */
+ public static final String EXTRA_HINT_STRINGS = "android.speech.extra.HINT_STRINGS";
+
+ /**
+ * The key to an extra to be included in the request intent for
+ * android.speech.RecognizerIntent#ACTION_GET_LANGUAGE_DETAILS.
+ * Should be an int of one of the values defined below. If an
+ * unknown int value is provided, it should be ignored.
+ */
+ public static final String EXTRA_HINT_CONTEXT = "android.speech.extra.HINT_CONTEXT";
+
+ /**
+ * A set of values for EXTRA_HINT_CONTEXT.
+ */
+ public static final int HINT_CONTEXT_UNKNOWN = 0;
+ public static final int HINT_CONTEXT_VOICE_SEARCH_HELP = 1;
+ public static final int HINT_CONTEXT_CAR_HOME = 2;
private Recognition() { } // don't instantiate
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 6a02a58..cb6aab6 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -313,7 +313,6 @@
mLaunchComponent = null;
mAppSearchData = null;
mSearchable = null;
- mActivityContext = null;
mUserQuery = null;
}
@@ -411,7 +410,7 @@
updateSearchAppIcon();
updateSearchBadge();
updateQueryHint();
- updateVoiceButton();
+ updateVoiceButton(TextUtils.isEmpty(mUserQuery));
// In order to properly configure the input method (if one is being used), we
// need to let it know if we'll be providing suggestions. Although it would be
@@ -560,10 +559,13 @@
/**
* 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() {
+ private void updateVoiceButton(boolean empty) {
int visibility = View.GONE;
- if (mSearchable.getVoiceSearchEnabled()) {
+ if (mSearchable.getVoiceSearchEnabled() && empty) {
Intent testIntent = null;
if (mSearchable.getVoiceSearchLaunchWebSearch()) {
testIntent = mVoiceWebSearchIntent;
@@ -666,6 +668,7 @@
// The user changed the query, remember it.
mUserQuery = s == null ? "" : s.toString();
}
+ updateVoiceButton(TextUtils.isEmpty(s));
}
public void afterTextChanged(Editable s) {
@@ -746,9 +749,6 @@
return;
}
SearchableInfo searchable = mSearchable;
- // First stop the existing search before starting voice search, or else we'll end
- // up showing the search dialog again once we return to the app.
- cancel();
try {
if (searchable.getVoiceSearchLaunchWebSearch()) {
getContext().startActivity(mVoiceWebSearchIntent);
@@ -762,6 +762,7 @@
// voice search before showing the button. But just in case...
Log.w(LOG_TAG, "Could not find voice search activity");
}
+ dismiss();
}
};
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f6f5235..679206d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7336,6 +7336,7 @@
* Sets the background color for this view.
* @param color the color of the background
*/
+ @RemotableViewMethod
public void setBackgroundColor(int color) {
setBackgroundDrawable(new ColorDrawable(color));
}
@@ -7346,6 +7347,7 @@
* @param resid The identifier of the resource.
* @attr ref android.R.styleable#View_background
*/
+ @RemotableViewMethod
public void setBackgroundResource(int resid) {
if (resid != 0 && resid == mBackgroundResource) {
return;
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 94bedde..84e34bc 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -150,8 +150,13 @@
}
boolean exactMatch(Cookie in) {
+ // An exact match means that domain, path, and name are equal. If
+ // both values are null, the cookies match. If both values are
+ // non-null, the cookies match. If one value is null and the other
+ // is non-null, the cookies do not match (i.e. "foo=;" and "foo;")
+ boolean valuesMatch = !((value == null) ^ (in.value == null));
return domain.equals(in.domain) && path.equals(in.path) &&
- name.equals(in.name);
+ name.equals(in.name) && valuesMatch;
}
boolean domainMatch(String urlHost) {
@@ -206,17 +211,29 @@
// As Set is not modified if the two objects are same, we do want to
// assign different value for each cookie.
int diff = cookie2.path.length() - cookie1.path.length();
- if (diff == 0) {
- diff = cookie2.domain.length() - cookie1.domain.length();
- if (diff == 0) {
- diff = cookie2.name.hashCode() - cookie1.name.hashCode();
- if (diff == 0) {
- Log.w(LOGTAG, "Found two cookies with the same value." +
- "cookie1=" + cookie1 + " , cookie2=" + cookie2);
- }
- }
+ if (diff != 0) return diff;
+
+ diff = cookie2.domain.length() - cookie1.domain.length();
+ if (diff != 0) return diff;
+
+ diff = cookie2.name.hashCode() - cookie1.name.hashCode();
+ if (diff != 0) return diff;
+
+ // If cookie2 has a null value, it should come later in
+ // the list.
+ if (cookie2.value == null) {
+ return -1;
+ } else if (cookie1.value == null) {
+ // Now we know that cookie2 does not have a null value, if
+ // cookie1 has a null value, place it later in the list.
+ return 1;
}
- return diff;
+
+ // cookie1 and cookie2 both have non-null values so we emit a
+ // warning and treat them as the same.
+ Log.w(LOGTAG, "Found two cookies with the same value."
+ + "cookie1=" + cookie1 + " , cookie2=" + cookie2);
+ return 0;
}
}
@@ -459,8 +476,10 @@
}
ret.append(cookie.name);
- ret.append(EQUAL);
- ret.append(cookie.value);
+ if (cookie.value != null) {
+ ret.append(EQUAL);
+ ret.append(cookie.value);
+ }
}
if (ret.length() > 0) {
@@ -634,7 +653,10 @@
byteCount += cookie.domain.length()
+ cookie.path.length()
+ cookie.name.length()
- + cookie.value.length() + 14;
+ + (cookie.value != null
+ ? cookie.value.length()
+ : 0)
+ + 14;
count++;
}
} else {
@@ -779,38 +801,45 @@
*/
int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
int equalIndex = cookieString.indexOf(EQUAL, index);
- if (equalIndex == -1) {
- // bad format, force return
- break;
- }
- if (semicolonIndex > -1 && semicolonIndex < equalIndex) {
- // empty cookie, like "; path=/", return
- break;
- }
cookie = new Cookie(host, path);
- cookie.name = cookieString.substring(index, equalIndex);
- if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
- index = cookieString.indexOf(QUOTATION, equalIndex + 2);
- if (index == -1) {
- // bad format, force return
- break;
+
+ // Cookies like "testcookie; path=/;" are valid and used
+ // (lovefilm.se). Check for equal as in the string "testcookie"
+ // Check for equalIndex == -1 as in the string "testcookie;"
+ if (semicolonIndex <= equalIndex || equalIndex == -1) {
+ // Fix up the index in case we have a string like "testcookie"
+ if (semicolonIndex == -1) {
+ semicolonIndex = length;
}
- }
- semicolonIndex = cookieString.indexOf(SEMICOLON, index);
- if (semicolonIndex == -1) {
- semicolonIndex = length;
- }
- if (semicolonIndex - equalIndex > MAX_COOKIE_LENGTH) {
- // cookie is too big, trim it
- cookie.value = cookieString.substring(equalIndex + 1,
- equalIndex + MAX_COOKIE_LENGTH);
- } else if (equalIndex + 1 == semicolonIndex
- || semicolonIndex < equalIndex) {
- // these are unusual case like foo=; and foo; path=/
- cookie.value = "";
+ cookie.name = cookieString.substring(index, semicolonIndex);
+ cookie.value = null;
} else {
- cookie.value = cookieString.substring(equalIndex + 1,
- semicolonIndex);
+ cookie.name = cookieString.substring(index, equalIndex);
+ if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
+ index = cookieString.indexOf(QUOTATION, equalIndex + 2);
+ if (index == -1) {
+ // bad format, force return
+ break;
+ }
+ }
+ // Get the semicolon index again in case it was contained within
+ // the quotations.
+ semicolonIndex = cookieString.indexOf(SEMICOLON, index);
+ if (semicolonIndex == -1) {
+ semicolonIndex = length;
+ }
+ if (semicolonIndex - equalIndex > MAX_COOKIE_LENGTH) {
+ // cookie is too big, trim it
+ cookie.value = cookieString.substring(equalIndex + 1,
+ equalIndex + 1 + MAX_COOKIE_LENGTH);
+ } else if (equalIndex + 1 == semicolonIndex
+ || semicolonIndex < equalIndex) {
+ // this is an unusual case like foo=;
+ cookie.value = "";
+ } else {
+ cookie.value = cookieString.substring(equalIndex + 1,
+ semicolonIndex);
+ }
}
// get attributes
index = semicolonIndex;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 67543aa..b13fc75 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -213,7 +213,6 @@
static private final boolean AUTO_REDRAW_HACK = false;
// true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
private boolean mAutoRedraw;
- private int mRootLayer; // C++ pointer to the root layer
static final String LOGTAG = "webview";
@@ -618,6 +617,12 @@
private static final int SNAP_Y = 4; // may be combined with SNAP_LOCK
private boolean mSnapPositive;
+ // keep these in sync with their counterparts in WebView.cpp
+ private static final int DRAW_EXTRAS_NONE = 0;
+ private static final int DRAW_EXTRAS_FIND = 1;
+ private static final int DRAW_EXTRAS_SELECTION = 2;
+ private static final int DRAW_EXTRAS_CURSOR_RING = 3;
+
// Used to match key downs and key ups
private boolean mGotKeyDown;
@@ -1306,6 +1311,7 @@
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
+ mInvActualScale = 1 / scale;
mTextWrapScale = b.getFloat("textwrapScale", scale);
mInZoomOverview = b.getBoolean("overview");
invalidate();
@@ -3116,7 +3122,7 @@
int mScrollY;
int mWidth;
int mHeight;
- float mScale;
+ float mInvScale;
}
private Metrics getViewMetrics() {
@@ -3125,23 +3131,21 @@
metrics.mScrollY = computeVerticalScrollOffset();
metrics.mWidth = getWidth();
metrics.mHeight = getHeight() - getVisibleTitleHeight();
- metrics.mScale = mActualScale;
+ metrics.mInvScale = mInvActualScale;
return metrics;
}
- private void drawLayers(Canvas canvas) {
- if (mRootLayer != 0) {
- // Currently for each draw we compute the animation values;
- // We may in the future decide to do that independently.
- if (nativeEvaluateLayersAnimations(mRootLayer)) {
- // If we have unfinished (or unstarted) animations,
- // we ask for a repaint.
- invalidate();
- }
-
- // We can now draw the layers.
- nativeDrawLayers(mRootLayer, canvas);
+ private void drawExtras(Canvas canvas, int extras) {
+ if (mNativeClass == 0) return;
+ // Currently for each draw we compute the animation values;
+ // We may in the future decide to do that independently.
+ if (nativeEvaluateLayersAnimations()) {
+ // If we have unfinished (or unstarted) animations,
+ // we ask for a repaint.
+ invalidate();
}
+
+ nativeDrawExtras(canvas, extras);
}
private void drawCoreAndCursorRing(Canvas canvas, int color,
@@ -3149,7 +3153,7 @@
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
canvas.drawPicture(mHistoryPicture);
- drawLayers(canvas);
+ drawExtras(canvas, DRAW_EXTRAS_NONE);
return;
}
@@ -3228,27 +3232,29 @@
mWebViewCore.drawContentPicture(canvas, color,
(animateZoom || mPreviewZoomOnly), animateScroll);
- boolean cursorIsInLayer = nativeCursorIsInLayer();
- if (drawCursorRing && !cursorIsInLayer) {
- nativeDrawCursorRing(canvas);
- }
- // When the FindDialog is up, only draw the matches if we are not in
- // the process of scrolling them into view.
- if (mFindIsUp && !animateScroll) {
- nativeDrawMatches(canvas);
- }
- drawLayers(canvas);
-
if (mNativeClass == 0) return;
- if (mShiftIsPressed && !(animateZoom || mPreviewZoomOnly)) {
- if (mTouchSelection || mExtendSelection) {
- nativeDrawSelectionRegion(canvas);
+ // decide which adornments to draw
+ int extras = DRAW_EXTRAS_NONE;
+ if (mFindIsUp) {
+ // When the FindDialog is up, only draw the matches if we are not in
+ // the process of scrolling them into view.
+ if (!animateScroll) {
+ extras = DRAW_EXTRAS_FIND;
}
- if (!mTouchSelection) {
- nativeDrawSelectionPointer(canvas, mInvActualScale, mSelectX,
- mSelectY - getTitleHeight(), mExtendSelection);
+ } else if (mShiftIsPressed) {
+ if (!animateZoom && !mPreviewZoomOnly) {
+ extras = DRAW_EXTRAS_SELECTION;
+ nativeSetSelectionRegion(mTouchSelection || mExtendSelection);
+ nativeSetSelectionPointer(!mTouchSelection, mInvActualScale,
+ mSelectX, mSelectY - getTitleHeight(),
+ mExtendSelection);
}
} else if (drawCursorRing) {
+ extras = DRAW_EXTRAS_CURSOR_RING;
+ }
+ drawExtras(canvas, extras);
+
+ if (extras == DRAW_EXTRAS_CURSOR_RING) {
if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mTouchMode = TOUCH_SHORTPRESS_MODE;
HitTestResult hitTest = getHitTestResult();
@@ -3259,7 +3265,6 @@
LONG_PRESS_TIMEOUT);
}
}
- if (cursorIsInLayer) nativeDrawCursorRing(canvas);
}
if (mFocusSizeChanged) {
mFocusSizeChanged = false;
@@ -3364,6 +3369,7 @@
if (isTextView) {
rebuildWebTextView();
if (inEditingMode()) {
+ mWebTextView.setDefaultSelection();
imm.showSoftInput(mWebTextView, 0);
if (zoom) {
didUpdateTextViewBounds(true);
@@ -3681,6 +3687,7 @@
// might be. Check it, and if so, hand over to the WebTextView.
rebuildWebTextView();
if (inEditingMode()) {
+ mWebTextView.setDefaultSelection();
return mWebTextView.dispatchKeyEvent(event);
}
}
@@ -6001,12 +6008,7 @@
break;
}
case SET_ROOT_LAYER_MSG_ID: {
- int oldLayer = mRootLayer;
- mRootLayer = msg.arg1;
- nativeSetRootLayer(mRootLayer);
- if (oldLayer > 0) {
- nativeDestroyLayer(oldLayer);
- }
+ nativeSetRootLayer(msg.arg1);
invalidate();
break;
}
@@ -6766,7 +6768,6 @@
/* package */ native boolean nativeCursorMatchesFocus();
private native boolean nativeCursorIntersects(Rect visibleRect);
private native boolean nativeCursorIsAnchor();
- private native boolean nativeCursorIsInLayer();
private native boolean nativeCursorIsTextInput();
private native Point nativeCursorPosition();
private native String nativeCursorText();
@@ -6777,14 +6778,8 @@
private native boolean nativeCursorWantsKeyEvents();
private native void nativeDebugDump();
private native void nativeDestroy();
- private native void nativeDrawCursorRing(Canvas content);
- private native void nativeDestroyLayer(int layer);
- private native boolean nativeEvaluateLayersAnimations(int layer);
- private native void nativeDrawLayers(int layer, Canvas canvas);
- private native void nativeDrawMatches(Canvas canvas);
- private native void nativeDrawSelectionPointer(Canvas content,
- float scale, int x, int y, boolean extendSelection);
- private native void nativeDrawSelectionRegion(Canvas content);
+ private native boolean nativeEvaluateLayersAnimations();
+ private native void nativeDrawExtras(Canvas canvas, int extra);
private native void nativeDumpDisplayTree(String urlOrNull);
private native int nativeFindAll(String findLower, String findUpper);
private native void nativeFindNext(boolean forward);
@@ -6831,6 +6826,9 @@
private native void nativeSetFollowedLink(boolean followed);
private native void nativeSetHeightCanMeasure(boolean measure);
private native void nativeSetRootLayer(int layer);
+ private native void nativeSetSelectionPointer(boolean set,
+ float scale, int x, int y, boolean extendSelection);
+ private native void nativeSetSelectionRegion(boolean set);
private native int nativeTextGeneration();
// Never call this version except by updateCachedTextfield(String) -
// we always want to pass in our generation number.
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 4bd3a82..bd07e1f 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -632,6 +632,8 @@
final boolean baselineAligned = mBaselineAligned;
final boolean useLargestChild = mUseLargestChild;
+
+ final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
int largestChildWidth = Integer.MIN_VALUE;
@@ -658,7 +660,13 @@
// Optimization: don't bother measuring children who are going to use
// leftover space. These views will get measured again down below if
// there is any leftover space.
- mTotalLength += lp.leftMargin + lp.rightMargin;
+ if (isExactly) {
+ mTotalLength += lp.leftMargin + lp.rightMargin;
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength +
+ lp.leftMargin + lp.rightMargin);
+ }
// Baseline alignment requires to measure widgets to obtain the
// baseline offset (in particular for TextViews). The following
@@ -694,8 +702,14 @@
}
final int childWidth = child.getMeasuredWidth();
- mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
- getNextLocationOffset(child);
+ if (isExactly) {
+ mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
+ lp.rightMargin + getNextLocationOffset(child));
+ }
if (useLargestChild) {
largestChildWidth = Math.max(childWidth, largestChildWidth);
@@ -780,8 +794,14 @@
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
child.getLayoutParams();
- mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
- getNextLocationOffset(child);
+ if (isExactly) {
+ mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
+ lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
+ }
}
}
@@ -851,8 +871,14 @@
}
}
- mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
- getNextLocationOffset(child);
+ if (isExactly) {
+ mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
+ lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
+ }
boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
lp.height == LayoutParams.MATCH_PARENT;
diff --git a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
index cd6a9a1..274082c 100644
--- a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
+++ b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
@@ -50,6 +50,11 @@
public static final String PATH = "syncstate";
+ private static final String QUERY_COUNT_SYNC_STATE_ROWS =
+ "SELECT count(*)"
+ + " FROM " + SYNC_STATE_TABLE
+ + " WHERE " + SyncStateContract.Columns._ID + "=?";
+
public void createDatabase(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_TABLE);
db.execSQL("CREATE TABLE " + SYNC_STATE_TABLE + " ("
@@ -96,11 +101,17 @@
return db.update(SYNC_STATE_TABLE, values, selection, selectionArgs);
}
- public void update(SQLiteDatabase db, long rowId, Object data) {
+ public int update(SQLiteDatabase db, long rowId, Object data) {
+ if (DatabaseUtils.longForQuery(db, QUERY_COUNT_SYNC_STATE_ROWS,
+ new String[]{Long.toString(rowId)}) < 1) {
+ return 0;
+ }
db.execSQL("UPDATE " + SYNC_STATE_TABLE
+ " SET " + SyncStateContract.Columns.DATA + "=?"
+ " WHERE " + SyncStateContract.Columns._ID + "=" + rowId,
new Object[]{data});
+ // assume a row was modified since we know it exists
+ return 1;
}
public void onAccountsChanged(SQLiteDatabase db, Account[] accounts) {
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index ab3b3d3..baed020 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -356,25 +356,19 @@
<p>There are several alternatives for iterating through an array:</p>
-<pre>public class Foo {
- int mSplat;
-}
-public class ArrayBenchmark {
- Foo[] mArray = new Foo[27];
- {
- for (int i = 0; i < mArray.length; ++i) {
- mArray[i] = new Foo();
- }
+<pre> static class Foo {
+ int mSplat;
}
+ Foo[] mArray = ...
- public static void zero() {
+ public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
- public static void one() {
+ public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
@@ -384,13 +378,13 @@
}
}
- public static void two() {
+ public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
-}</pre>
+</pre>
<p><strong>zero()</strong> is slowest, because the JIT can't yet optimize away
the cost of getting the array length once for every iteration through the
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
index 42b6508..7b866c7 100644
--- a/libs/audioflinger/AudioPolicyManagerBase.cpp
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -82,8 +82,8 @@
// keep track of SCO device address
mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
#ifdef WITH_A2DP
- if ((mA2dpDeviceAddress == mScoDeviceAddress) &&
- (mPhoneState != AudioSystem::MODE_NORMAL)) {
+ if (mA2dpOutput != 0 &&
+ mPhoneState != AudioSystem::MODE_NORMAL) {
mpClientInterface->suspendOutput(mA2dpOutput);
}
#endif
@@ -116,8 +116,8 @@
if (AudioSystem::isBluetoothScoDevice(device)) {
mScoDeviceAddress = "";
#ifdef WITH_A2DP
- if ((mA2dpDeviceAddress == mScoDeviceAddress) &&
- (mPhoneState != AudioSystem::MODE_NORMAL)) {
+ if (mA2dpOutput != 0 &&
+ mPhoneState != AudioSystem::MODE_NORMAL) {
mpClientInterface->restoreOutput(mA2dpOutput);
}
#endif
@@ -275,10 +275,8 @@
newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
checkOutputForAllStrategies(newDevice);
- // suspend A2DP output if SCO device address is the same as A2DP device address.
- // no need to check that a SCO device is actually connected as mScoDeviceAddress == ""
- // if none is connected and the test below will fail.
- if (mA2dpDeviceAddress == mScoDeviceAddress) {
+ // suspend A2DP output if a SCO device is present.
+ if (mA2dpOutput != 0 && mScoDeviceAddress != "") {
if (oldState == AudioSystem::MODE_NORMAL) {
mpClientInterface->suspendOutput(mA2dpOutput);
} else if (state == AudioSystem::MODE_NORMAL) {
@@ -1191,7 +1189,7 @@
}
AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
- if (mA2dpDeviceAddress == mScoDeviceAddress) {
+ if (mScoDeviceAddress != "") {
// It is normal to suspend twice if we are both in call,
// and have the hardware audio output routed to BT SCO
if (mPhoneState != AudioSystem::MODE_NORMAL) {
@@ -1556,9 +1554,9 @@
usleep(outputDesc->mLatency*2*1000);
}
#ifdef WITH_A2DP
- // suspend A2D output if SCO device is selected
+ // suspend A2DP output if SCO device is selected
if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) {
- if (mA2dpOutput && mScoDeviceAddress == mA2dpDeviceAddress) {
+ if (mA2dpOutput != 0) {
mpClientInterface->suspendOutput(mA2dpOutput);
}
}
@@ -1573,7 +1571,7 @@
#ifdef WITH_A2DP
// if disconnecting SCO device, restore A2DP output
if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)prevDevice)) {
- if (mA2dpOutput && mScoDeviceAddress == mA2dpDeviceAddress) {
+ if (mA2dpOutput != 0) {
LOGV("restore A2DP output");
mpClientInterface->restoreOutput(mA2dpOutput);
}
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 35b5675..2f5cfa3 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -45,6 +45,9 @@
#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_WRITE_TO_FILE 1
+#define SYNTHPLAYSTATE_IS_STOPPED 0
+#define SYNTHPLAYSTATE_IS_PLAYING 1
+
using namespace android;
// ----------------------------------------------------------------------------
@@ -154,6 +157,8 @@
TtsEngine* mNativeSynthInterface;
void* mEngineLibHandle;
AudioTrack* mAudioOut;
+ int8_t mPlayState;
+ Mutex mPlayLock;
AudioSystem::stream_type mStreamType;
uint32_t mSampleRate;
uint32_t mAudFormat;
@@ -166,6 +171,7 @@
mNativeSynthInterface = NULL;
mEngineLibHandle = NULL;
mAudioOut = NULL;
+ mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
mStreamType = DEFAULT_TTS_STREAM_TYPE;
mSampleRate = DEFAULT_TTS_RATE;
mAudFormat = DEFAULT_TTS_FORMAT;
@@ -223,6 +229,7 @@
if (minBufCount < 2) minBufCount = 2;
int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
+ mPlayLock.lock();
mAudioOut = new AudioTrack(mStreamType, rate, format,
(channel == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
minFrameCount > 4096 ? minFrameCount : 4096,
@@ -237,6 +244,7 @@
mAudioOut->setVolume(1.0f, 1.0f);
LOGV("AudioTrack ready");
}
+ mPlayLock.unlock();
}
};
@@ -288,6 +296,12 @@
if (bufferSize > 0) {
prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel);
if (pJniData->mAudioOut) {
+ pJniData->mPlayLock.lock();
+ if(pJniData->mAudioOut->stopped()
+ && (pJniData->mPlayState == SYNTHPLAYSTATE_IS_PLAYING)) {
+ pJniData->mAudioOut->start();
+ }
+ pJniData->mPlayLock.unlock();
if (bUseFilter) {
applyFilter((int16_t*)wav, bufferSize/2);
}
@@ -711,9 +725,9 @@
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- if (pSynthData->mAudioOut) {
- pSynthData->mAudioOut->start();
- }
+ pSynthData->mPlayLock.lock();
+ pSynthData->mPlayState = SYNTHPLAYSTATE_IS_PLAYING;
+ pSynthData->mPlayLock.unlock();
afterSynthData_t* pForAfter = new (afterSynthData_t);
pForAfter->jniStorage = jniData;
@@ -744,9 +758,13 @@
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
+ pSynthData->mPlayLock.lock();
+ pSynthData->mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
if (pSynthData->mAudioOut) {
pSynthData->mAudioOut->stop();
}
+ pSynthData->mPlayLock.unlock();
+
if (pSynthData->mNativeSynthInterface) {
result = pSynthData->mNativeSynthInterface->stop();
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index ac98054..6ceb0f9 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -81,6 +81,30 @@
};
static void fillIgnoreResultList() {
+ // This first block of tests are for HTML5 features, for which Android
+ // should pass all tests. They are skipped only temporarily.
+ // TODO: Fix these failing tests and remove them from this list.
+ ignoreResultList.add("fast/dom/Geolocation/callback-exception.html"); // exception output incorrect with V8
+ ignoreResultList.add("http/tests/appcache/auth.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/deferred-events.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/deferred-events-delete-while-raising.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/destroyed-frame.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/detached-iframe.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/different-scheme.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/disabled.html"); // not found
+ ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky
+ ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
+ ignoreResultList.add("http/tests/appcache/local-content.html"); // text diff
+ ignoreResultList.add("http/tests/appcache/max-size.html"); // no layoutTestController.setAppCacheMaximumSize
+ ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
+ ignoreResultList.add("http/tests/appcache/whitelist-wildcard.html"); // file not found
+ ignoreResultList.add("storage/database-lock-after-reload.html"); // failure
+ ignoreResultList.add("storage/domstorage/localstorage/string-conversion.html"); // false failure due to whitespace diff in output with V8
+ ignoreResultList.add("storage/domstorage/sessionstorage/string-conversion.html"); // false failure due to whitespace diff in output with V8
+ ignoreResultList.add("storage/statement-error-callback.html"); // expected line number diff in V8 only
+ ignoreResultList.add("storage/transaction-error-callback.html"); // expected line number diff in V8 only
+ ignoreResultList.add("storage/transaction-callback-exception-crash.html"); // expected line number diff in V8 only
+
ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index f8c5c38..ae4bd14 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -224,9 +224,9 @@
ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
"minSdkVersion");
if (minSdkIndex >= 0) {
- String8 minSdkString = String8(
- block.getAttributeStringValue(minSdkIndex, &len));
- bundle->setMinSdkVersion(minSdkString.string());
+ const uint16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len);
+ const char* minSdk8 = strdup(String8(minSdk16).string());
+ bundle->setMinSdkVersion(minSdk8);
}
}
}