Merge "MountService: Send ACTION_MEDIA_UNSHARED Intent a volume is no longer shared via UMS."
diff --git a/api/current.xml b/api/current.xml
index be38d49..1f7be9e 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -24473,6 +24473,17 @@
visibility="public"
>
</field>
+<field name="SUGGEST_COLUMN_TEXT_2_URL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""suggest_text_2_url""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SUGGEST_MIME_TYPE"
type="java.lang.String"
transient="false"
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index b54e53d..67f9629 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1355,6 +1355,16 @@
* a much smaller appearance.
*/
public final static String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> This is a URL that will be shown
+ * as the second line of text instead of {@link #SUGGEST_COLUMN_TEXT_2}. This is a separate
+ * column so that the search UI knows to display the text as a URL, e.g. by using a different
+ * color. If this column is absent, or has the value {@code null},
+ * {@link #SUGGEST_COLUMN_TEXT_2} will be used instead.
+ */
+ public final static String SUGGEST_COLUMN_TEXT_2_URL = "suggest_text_2_url";
+
/**
* Column name for suggestions cursor. <i>Optional.</i> If your cursor includes this column,
* then all suggestions will be provided in a format that includes space for two small icons,
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 57795d1..07e9793 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -16,6 +16,8 @@
package android.app;
+import com.android.internal.R;
+
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -23,16 +25,20 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.net.Uri;
-import android.text.Html;
+import android.text.Spannable;
+import android.text.SpannableString;
import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@@ -64,10 +70,13 @@
private SparseArray<Drawable.ConstantState> mBackgroundsCache;
private boolean mClosed = false;
+ // URL color
+ private ColorStateList mUrlColor;
+
// Cached column indexes, updated when the cursor changes.
- private int mFormatCol;
private int mText1Col;
private int mText2Col;
+ private int mText2UrlCol;
private int mIconName1Col;
private int mIconName2Col;
private int mBackgroundColorCol;
@@ -188,9 +197,9 @@
super.changeCursor(c);
if (c != null) {
- mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
+ mText2UrlCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
@@ -239,9 +248,20 @@
Drawable background = getItemBackground(backgroundColor);
view.setBackgroundDrawable(background);
- final boolean isHtml = mFormatCol > 0 && "html".equals(cursor.getString(mFormatCol));
- setViewText(cursor, views.mText1, mText1Col, isHtml);
- setViewText(cursor, views.mText2, mText2Col, isHtml);
+ if (views.mText1 != null) {
+ String text1 = getStringOrNull(cursor, mText1Col);
+ setViewText(views.mText1, text1);
+ }
+ if (views.mText2 != null) {
+ // First check TEXT_2_URL
+ CharSequence text2 = getStringOrNull(cursor, mText2UrlCol);
+ if (text2 != null) {
+ text2 = formatUrl(text2);
+ } else {
+ text2 = getStringOrNull(cursor, mText2Col);
+ }
+ setViewText(views.mText2, text2);
+ }
if (views.mIcon1 != null) {
setViewDrawable(views.mIcon1, getIcon1(cursor));
@@ -251,6 +271,21 @@
}
}
+ private CharSequence formatUrl(CharSequence url) {
+ if (mUrlColor == null) {
+ // Lazily get the URL color from the current theme.
+ TypedValue colorValue = new TypedValue();
+ mContext.getTheme().resolveAttribute(R.attr.textColorSearchUrl, colorValue, true);
+ mUrlColor = mContext.getResources().getColorStateList(colorValue.resourceId);
+ }
+
+ SpannableString text = new SpannableString(url);
+ text.setSpan(new TextAppearanceSpan(null, 0, 0, mUrlColor, null),
+ 0, url.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return text;
+ }
+
/**
* Gets a drawable with no color when selected or pressed, and the given color when
* neither selected nor pressed.
@@ -278,19 +313,7 @@
}
}
- private void setViewText(Cursor cursor, TextView v, int textCol, boolean isHtml) {
- if (v == null) {
- return;
- }
- CharSequence text = null;
- if (textCol >= 0) {
- String str = cursor.getString(textCol);
- if (isHtml && looksLikeHtml(str)) {
- text = Html.fromHtml(str);
- } else {
- text = str;
- }
- }
+ private void setViewText(TextView v, CharSequence text) {
// Set the text even if it's null, since we need to clear any previous text.
v.setText(text);
@@ -301,15 +324,6 @@
}
}
- private static boolean looksLikeHtml(String str) {
- if (TextUtils.isEmpty(str)) return false;
- for (int i = str.length() - 1; i >= 0; i--) {
- char c = str.charAt(i);
- if (c == '<' || c == '&') return true;
- }
- return false;
- }
-
private Drawable getIcon1(Cursor cursor) {
if (mIconName1Col < 0) {
return null;
@@ -617,6 +631,10 @@
*/
public static String getColumnString(Cursor cursor, String columnName) {
int col = cursor.getColumnIndex(columnName);
+ return getStringOrNull(cursor, col);
+ }
+
+ private static String getStringOrNull(Cursor cursor, int col) {
if (col == NONE) {
return null;
}
@@ -629,5 +647,4 @@
return null;
}
}
-
}
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 19ad946..748eb99 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -143,8 +143,7 @@
public void close() {
maybeUnregisterObserverProxy();
- mCursor.deactivate();
-
+ mCursor.close();
}
public int requery(IContentObserver observer, CursorWindow window) {
diff --git a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
new file mode 100644
index 0000000..8ac4c0f
--- /dev/null
+++ b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+/**
+ * An exception that indicates that garbage-collector is finalizing a database object
+ * that is not explicitly closed
+ * @hide
+ */
+public class DatabaseObjectNotClosedException extends RuntimeException
+{
+ private static final String s = "Application did not close the cursor or database object " +
+ "that was opened here";
+
+ public DatabaseObjectNotClosedException()
+ {
+ super(s);
+ }
+}
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 486ad20..4ccf6b0 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -56,7 +56,7 @@
/* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) {
mDatabase = db;
mSqlStmt = sql;
- mStackTrace = new Exception().fillInStackTrace();
+ mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
this.nHandle = db.mNativeHandle;
compile(sql, true);
}
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 96ed297..3f0fcb1 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -207,7 +207,7 @@
String editTable, SQLiteQuery query) {
// The AbstractCursor constructor needs to do some setup.
super();
- mStackTrace = new Exception().fillInStackTrace();
+ mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
mDatabase = db;
mDriver = driver;
mEditTable = editTable;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index d8ccf85..9fa9368 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1749,7 +1749,7 @@
mFlags = flags;
mPath = path;
mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
- mStackTrace = new Exception().fillInStackTrace();
+ mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
mFactory = factory;
dbopen(mPath, mFlags);
if (SQLiteDebug.DEBUG_SQL_CACHE) {
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index f735f3d..a67fd9a 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -59,7 +59,7 @@
private static SSLSocketFactory mSslSocketFactory = null;
static {
- // This intiialization happens in the zygote. It triggers some
+ // This initialization happens in the zygote. It triggers some
// lazy initialization that can will benefit later invocations of
// initializeEngine().
initializeEngine(null);
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index b28cf43..f363828 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -274,9 +274,11 @@
private void onDeviceRemoved(String deviceObjectPath) {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
- if (address != null)
+ if (address != null) {
mBluetoothService.getBondState().setBondState(address.toUpperCase(),
BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
+ mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
+ }
}
/*package*/ void onPropertyChanged(String[] propValues) {
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index db19bca..39edcad 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -822,8 +822,9 @@
break;
case 1: // TEXT_AREA
single = false;
- inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
| EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
+ | EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
imeOptions |= EditorInfo.IME_ACTION_NONE;
break;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 72791fb..0739735 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2480,20 +2480,30 @@
*/
public int findAll(String find) {
if (0 == mNativeClass) return 0; // client isn't initialized
- if (mFindIsUp == false) {
- recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
- false);
- mFindIsUp = true;
- }
- int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
+ int result = find != null ? nativeFindAll(find.toLowerCase(),
+ find.toUpperCase()) : 0;
invalidate();
mLastFind = find;
return result;
}
+ /**
+ * @hide
+ */
+ public void setFindIsUp(boolean isUp) {
+ mFindIsUp = isUp;
+ if (isUp) {
+ recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
+ false);
+ }
+ if (0 == mNativeClass) return; // client isn't initialized
+ nativeSetFindIsUp(isUp);
+ }
+
// Used to know whether the find dialog is open. Affects whether
// or not we draw the highlights for matches.
private boolean mFindIsUp;
+
private int mFindHeight;
// Keep track of the last string sent, so we can search again after an
// orientation change or the dismissal of the soft keyboard.
@@ -2553,14 +2563,21 @@
* Clear the highlighting surrounding text matches created by findAll.
*/
public void clearMatches() {
+ mLastFind = "";
if (mNativeClass == 0)
return;
- if (mFindIsUp) {
- recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
- false);
- mFindIsUp = false;
- }
- nativeSetFindIsUp();
+ nativeSetFindIsEmpty();
+ invalidate();
+ }
+
+ /**
+ * @hide
+ */
+ public void notifyFindDialogDismissed() {
+ clearMatches();
+ setFindIsUp(false);
+ recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
+ false);
// Now that the dialog has been removed, ensure that we scroll to a
// location that is not beyond the end of the page.
pinScrollTo(mScrollX, mScrollY, false, 0);
@@ -4477,12 +4494,12 @@
y = getViewHeightWithTitle() - 1;
}
- // pass the touch events from UI thread to WebCore thread
- if (mForwardTouchEvents
- && (action != MotionEvent.ACTION_MOVE || eventTime
- - mLastSentTouchTime > mCurrentTouchInterval)
- && (action == MotionEvent.ACTION_DOWN
- || mPreventDrag != PREVENT_DRAG_CANCEL)) {
+ // pass the touch events, except ACTION_MOVE which will be handled
+ // later, from UI thread to WebCore thread
+ if (mFullScreenHolder != null || (mForwardTouchEvents
+ && action != MotionEvent.ACTION_MOVE
+ && (action == MotionEvent.ACTION_DOWN || mPreventDrag
+ != PREVENT_DRAG_CANCEL))) {
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
ted.mX = viewToContentX((int) x + mScrollX);
@@ -4573,6 +4590,21 @@
if ((deltaX * deltaX + deltaY * deltaY) < mTouchSlopSquare) {
break;
}
+
+ // pass the first ACTION_MOVE from UI thread to WebCore
+ // thread after the distance is confirmed that it is a drag
+ if (mFullScreenHolder == null && mForwardTouchEvents
+ && mPreventDrag != PREVENT_DRAG_CANCEL) {
+ WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+ ted.mAction = action;
+ ted.mX = viewToContentX((int) x + mScrollX);
+ ted.mY = viewToContentY((int) y + mScrollY);
+ ted.mEventTime = eventTime;
+ ted.mMetaState = ev.getMetaState();
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
+ mLastSentTouchTime = eventTime;
+ }
+
if (mPreventDrag == PREVENT_DRAG_MAYBE_YES) {
// track mLastTouchTime as we may need to do fling at
// ACTION_UP
@@ -4629,6 +4661,20 @@
Toast.LENGTH_LONG).show();
}
}
+ } else {
+ // pass the touch events from UI thread to WebCore thread
+ if (mFullScreenHolder == null && mForwardTouchEvents
+ && eventTime - mLastSentTouchTime > mCurrentTouchInterval
+ && mPreventDrag != PREVENT_DRAG_CANCEL) {
+ WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+ ted.mAction = action;
+ ted.mX = viewToContentX((int) x + mScrollX);
+ ted.mY = viewToContentY((int) y + mScrollY);
+ ted.mEventTime = eventTime;
+ ted.mMetaState = ev.getMetaState();
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
+ mLastSentTouchTime = eventTime;
+ }
}
// do pan
@@ -6863,7 +6909,8 @@
private native void nativeRecordButtons(boolean focused,
boolean pressed, boolean invalidate);
private native void nativeSelectBestAt(Rect rect);
- private native void nativeSetFindIsUp();
+ private native void nativeSetFindIsEmpty();
+ private native void nativeSetFindIsUp(boolean isUp);
private native void nativeSetFollowedLink(boolean followed);
private native void nativeSetHeightCanMeasure(boolean measure);
private native void nativeSetRootLayer(int layer);
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 1730a68..8469c8b 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -418,6 +418,12 @@
*/
public void setFinalX(int newX) {
if (mScrollMode == MODE_DEFAULT) {
+ if (newX < mMinimumX) {
+ mMinimumX = newX;
+ }
+ if (newX > mMaximumX) {
+ mMaximumX = newX;
+ }
mDefaultScroller.setFinalX(newX);
}
}
@@ -431,6 +437,12 @@
*/
public void setFinalY(int newY) {
if (mScrollMode == MODE_DEFAULT) {
+ if (newY < mMinimumY) {
+ mMinimumY = newY;
+ }
+ if (newY > mMaximumY) {
+ mMaximumY = newY;
+ }
mDefaultScroller.setFinalY(newY);
}
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1b5b3e4..02961f0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -87,7 +87,7 @@
</string-array>
<!-- Regex array of allowable upstream ifaces for tethering - for example if you want
- tethering on your a new interface called "foo2" add "foo\\d" here -->
+ tethering on a new interface called "foo2" add <item>"foo\\d"</item> to the array -->
<string-array translatable="false" name="config_tether_upstream_regexs">
</string-array>
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 7511ec1..1f58a2c 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -26,6 +26,11 @@
/**
* Tests StaticLayout vertical metrics behavior.
+ *
+ * Requires disabling access checks in the vm since this calls package-private
+ * APIs.
+ *
+ * @Suppress
*/
public class StaticLayoutTest extends TestCase {
@@ -33,7 +38,7 @@
* Basic test showing expected behavior and relationship between font
* metrics and line metrics.
*/
- @SmallTest
+ //@SmallTest
public void testGetters1() {
LayoutBuilder b = builder();
FontMetricsInt fmi = b.paint.getFontMetricsInt();
@@ -59,7 +64,7 @@
* Basic test showing effect of includePad = true with 1 line.
* Top and bottom padding are affected, as is the line descent and height.
*/
- @SmallTest
+ //@SmallTest
public void testGetters2() {
LayoutBuilder b = builder()
.setIncludePad(true);
@@ -74,7 +79,7 @@
* Basic test showing effect of includePad = true wrapping to 2 lines.
* Ascent of top line and descent of bottom line are affected.
*/
- @SmallTest
+ //@SmallTest
public void testGetters3() {
LayoutBuilder b = builder()
.setIncludePad(true)
@@ -91,7 +96,7 @@
* Basic test showing effect of includePad = true wrapping to 3 lines.
* First line ascent is top, bottom line descent is bottom.
*/
- @SmallTest
+ //@SmallTest
public void testGetters4() {
LayoutBuilder b = builder()
.setText("This is a longer test")
@@ -111,7 +116,7 @@
* large text. See effect of leading. Currently, we don't expect there to
* even be non-zero leading.
*/
- @SmallTest
+ //@SmallTest
public void testGetters5() {
LayoutBuilder b = builder()
.setText("This is a longer test")
@@ -138,7 +143,7 @@
* Basic test showing effect of includePad = true, spacingAdd = 2, wrapping
* to 3 lines.
*/
- @SmallTest
+ //@SmallTest
public void testGetters6() {
int spacingAdd = 2; // int so expressions return int
LayoutBuilder b = builder()
@@ -159,7 +164,7 @@
* Basic test showing effect of includePad = true, spacingAdd = 2,
* spacingMult = 1.5, wrapping to 3 lines.
*/
- @SmallTest
+ //@SmallTest
public void testGetters7() {
LayoutBuilder b = builder()
.setText("This is a longer test")
@@ -181,7 +186,7 @@
* Basic test showing effect of includePad = true, spacingAdd = 0,
* spacingMult = 0.8 when wrapping to 3 lines.
*/
- @SmallTest
+ //@SmallTest
public void testGetters8() {
LayoutBuilder b = builder()
.setText("This is a longer test")
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index c4d4f99..57192a5 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -604,8 +604,11 @@
// figure out the kinds of events the device reports
- // See if this is a keyboard, and classify it.
- uint8_t key_bitmask[(KEY_MAX+1)/8];
+ // See if this is a keyboard, and classify it. Note that we only
+ // consider up through the function keys; we don't want to include
+ // ones after that (play cd etc) so we don't mistakenly consider a
+ // controller to be a keyboard.
+ uint8_t key_bitmask[(KEY_PLAYCD+1)/8];
memset(key_bitmask, 0, sizeof(key_bitmask));
LOGV("Getting keys...");
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
@@ -702,22 +705,20 @@
device->layoutMap->load(keylayoutFilename);
// tell the world about the devname (the descriptive name)
- int32_t publicID;
- if (!mHaveFirstKeyboard && !defaultKeymap) {
- publicID = 0;
+ if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
// the built-in keyboard has a well-known device ID of 0,
// this device better not go away.
mHaveFirstKeyboard = true;
mFirstKeyboardId = device->id;
+ property_set("hw.keyboards.0.devname", name);
} else {
- publicID = device->id;
// ensure mFirstKeyboardId is set to -something-.
if (mFirstKeyboardId == 0) {
mFirstKeyboardId = device->id;
}
}
char propName[100];
- sprintf(propName, "hw.keyboards.%u.devname", publicID);
+ sprintf(propName, "hw.keyboards.%u.devname", device->id);
property_set(propName, name);
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
@@ -734,8 +735,8 @@
device->classes |= CLASS_DPAD;
}
- LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
- publicID, device->id, name, propName, keylayoutFilename);
+ LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
+ device->id, name, propName, keylayoutFilename);
}
LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
@@ -808,18 +809,15 @@
device->next = mClosingDevices;
mClosingDevices = device;
- uint32_t publicID;
if (device->id == mFirstKeyboardId) {
LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
device->path.string(), mFirstKeyboardId);
mFirstKeyboardId = 0;
- publicID = 0;
- } else {
- publicID = device->id;
+ property_set("hw.keyboards.0.devname", NULL);
}
// clear the property
char propName[100];
- sprintf(propName, "hw.keyboards.%u.devname", publicID);
+ sprintf(propName, "hw.keyboards.%u.devname", device->id);
property_set(propName, NULL);
return 0;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 88e171d..a3bbb74 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -20,8 +20,11 @@
import com.android.mediaframeworktest.MediaNames;
import android.database.sqlite.SQLiteDatabase;
+import android.hardware.Camera;
+import android.hardware.Camera.PreviewCallback;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
+import android.os.Looper;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
@@ -42,6 +45,8 @@
import android.media.MediaMetadataRetriever;
import com.android.mediaframeworktest.MediaProfileReader;
+import android.hardware.Camera.PreviewCallback;
+
/**
* Junit / Instrumentation - performance measurement for media player and
* recorder
@@ -58,14 +63,24 @@
private static final String MEDIA_MEMORY_OUTPUT =
"/sdcard/mediaMemOutput.txt";
- //the tolerant memory leak
- private static final int MAX_ACCEPTED_MEMORY_LEAK_KB = 150;
-
private static int mStartMemory = 0;
private static int mEndMemory = 0;
private static int mStartPid = 0;
private static int mEndPid = 0;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback();
+ private final Object lock = new Object();
+ private final Object previewDone = new Object();
+ private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds.
+
+ //the tolerant memory leak
+ private static int ENCODER_LIMIT = 150;
+ private static int DECODER_LIMIT = 150;
+ private static int CAMERA_LIMIT = 80;
+
+ Camera mCamera;
public MediaPlayerPerformance() {
super("com.android.mediaframeworktest", MediaFrameworkTest.class);
@@ -178,6 +193,66 @@
Log.v(TAG, "Average duration = " + sum / testFile.length);
}
+ private void initializeMessageLooper() {
+ new Thread() {
+ @Override
+ public void run() {
+ Looper.prepare();
+ Log.v(TAG, "start loopRun");
+ mLooper = Looper.myLooper();
+ mCamera = Camera.open();
+ synchronized (lock) {
+ mInitialized = true;
+ lock.notify();
+ }
+ Looper.loop();
+ Log.v(TAG, "initializeMessageLooper: quit.");
+ }
+ }.start();
+ }
+
+ private void terminateMessageLooper() {
+ mLooper.quit();
+ mCamera.release();
+ }
+
+ private final class RawPreviewCallback implements PreviewCallback {
+ public void onPreviewFrame(byte[] rawData, Camera camera) {
+ synchronized (previewDone) {
+ previewDone.notify();
+ }
+ }
+ }
+
+ public void stressCameraPreview() {
+ try {
+ synchronized (lock) {
+ initializeMessageLooper();
+ try {
+ lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch (Exception e) {
+ Log.v(TAG, "runTestOnMethod: wait was interrupted.");
+ }
+ }
+ mCamera.setPreviewCallback(mRawPreviewCallback);
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.startPreview();
+ synchronized (previewDone) {
+ try {
+ previewDone.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ Log.v(TAG, "Preview Done");
+ } catch (Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
+ Thread.sleep(1000);
+ mCamera.stopPreview();
+ terminateMessageLooper();
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ }
// Note: This test is to assume the mediaserver's pid is 34
public void mediaStressPlayback(String testFilePath) {
@@ -314,8 +389,9 @@
return vsizevalue;
}
- public boolean validateMemoryResult (int startPid, int startMemory, Writer output) throws Exception {
- //Wait for 10 seconds to make sure the memory settle.
+ public boolean validateMemoryResult(int startPid, int startMemory, Writer output, int limit)
+ throws Exception {
+ // Wait for 10 seconds to make sure the memory settle.
Thread.sleep(10000);
mEndPid = getMediaserverPid();
int memDiff = mEndMemory - startMemory;
@@ -329,9 +405,8 @@
output.write("mediaserver died. Test failed\n");
return false;
}
- //memory leak greter than the tolerant
- if (memDiff > MAX_ACCEPTED_MEMORY_LEAK_KB )
- return false;
+ // memory leak greter than the tolerant
+ if (memDiff > limit) return false;
return true;
}
@@ -356,7 +431,7 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT);
output.close();
assertTrue("H263 playback memory test", memoryResult);
}
@@ -375,7 +450,7 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT);
output.close();
assertTrue("H264 playback memory test", memoryResult);
}
@@ -394,7 +469,7 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT);
output.close();
assertTrue("wmv playback memory test", memoryResult);
}
@@ -415,7 +490,7 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
output.close();
assertTrue("H263 record only memory test", memoryResult);
}
@@ -435,7 +510,7 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
output.close();
assertTrue("mpeg4 record only memory test", memoryResult);
}
@@ -456,7 +531,7 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
output.close();
assertTrue("H263 audio video record memory test", memoryResult);
}
@@ -475,8 +550,27 @@
getMemoryWriteToLog(output, i);
}
output.write("\n");
- memoryResult = validateMemoryResult(mStartPid, mStartMemory, output);
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, ENCODER_LIMIT);
output.close();
assertTrue("audio record only memory test", memoryResult);
}
+
+ // Test case 8: Capture the memory usage after every 20 camera preview
+ @LargeTest
+ public void testCameraPreviewMemoryUsage() throws Exception {
+ boolean memoryResult = false;
+ mStartPid = getMediaserverPid();
+
+ File cameraPreviewMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
+ Writer output = new BufferedWriter(new FileWriter(cameraPreviewMemoryOut, true));
+ output.write("Camera Preview Only\n");
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ stressCameraPreview();
+ getMemoryWriteToLog(output, i);
+ }
+ output.write("\n");
+ memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, CAMERA_LIMIT);
+ output.close();
+ assertTrue("camera preview memory test", memoryResult);
+ }
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 25ebee4..547a2a1 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -421,9 +421,19 @@
}
break;
case MSG_ENABLE_LOCATION_UPDATES:
- if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ boolean networkLocationEnabled;
+ try {
+ networkLocationEnabled =
+ mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+ } catch (Exception e) {
+ // we may get IllegalArgumentException if network location provider
+ // does not exist or is not yet installed.
+ networkLocationEnabled = false;
+ }
+ if (networkLocationEnabled) {
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
- LOCATION_UPDATE_MS, LOCATION_UPDATE_DISTANCE_METER, mLocationListener);
+ LOCATION_UPDATE_MS, LOCATION_UPDATE_DISTANCE_METER,
+ mLocationListener);
retrieveLocation();
if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) {
try {
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 1c18d6f..d5e94ec 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -22,6 +22,8 @@
import android.view.Surface;
import android.view.WindowManagerPolicy;
+import java.io.PrintWriter;
+
public class InputDevice {
static final boolean DEBUG_POINTERS = false;
static final boolean DEBUG_HACKS = false;
@@ -58,6 +60,7 @@
float yMoveScale;
MotionEvent currentMove = null;
boolean changed = false;
+ boolean everChanged = false;
long mDownTime = 0;
// The currently assigned pointer IDs, corresponding to the last data.
@@ -103,6 +106,56 @@
int mAddingPointerOffset = 0;
final boolean[] mDown = new boolean[MAX_POINTERS];
+ void dumpIntArray(PrintWriter pw, int[] array) {
+ pw.print("[");
+ for (int i=0; i<array.length; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(array[i]);
+ }
+ pw.print("]");
+ }
+
+ void dumpBooleanArray(PrintWriter pw, boolean[] array) {
+ pw.print("[");
+ for (int i=0; i<array.length; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(array[i] ? "true" : "false");
+ }
+ pw.print("]");
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
+ pw.print(" yPrecision="); pw.println(yPrecision);
+ pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale);
+ pw.print(" yMoveScale="); pw.println(yMoveScale);
+ if (currentMove != null) {
+ pw.print(prefix); pw.print("currentMove="); pw.println(currentMove);
+ }
+ if (changed || mDownTime != 0) {
+ pw.print(prefix); pw.print("changed="); pw.print(changed);
+ pw.print(" mDownTime="); pw.println(mDownTime);
+ }
+ pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds);
+ pw.println("");
+ if (mSkipLastPointers || mLastNumPointers != 0) {
+ pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers);
+ pw.print(" mLastNumPointers="); pw.println(mLastNumPointers);
+ pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData);
+ pw.println("");
+ }
+ if (mNextNumPointers != 0) {
+ pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers);
+ pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData);
+ pw.println("");
+ }
+ pw.print(prefix); pw.print("mDroppedBadPoint=");
+ dumpBooleanArray(pw, mDroppedBadPoint); pw.println("");
+ pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset);
+ pw.print(prefix); pw.print("mDown=");
+ dumpBooleanArray(pw, mDown); pw.println("");
+ }
+
MotionState(int mx, int my) {
xPrecision = mx;
yPrecision = my;
@@ -775,6 +828,14 @@
int range;
int flat;
int fuzz;
+
+ final void dump(PrintWriter pw) {
+ pw.print("minValue="); pw.print(minValue);
+ pw.print(" maxValue="); pw.print(maxValue);
+ pw.print(" range="); pw.print(range);
+ pw.print(" flat="); pw.print(flat);
+ pw.print(" fuzz="); pw.print(fuzz);
+ }
};
InputDevice(int _id, int _classes, String _name,
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a6a3e27..60813f1 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1475,13 +1475,22 @@
final List<InputMethodInfo> immis = getEnabledInputMethodList();
- int N = (immis == null ? 0 : immis.size());
+ if (immis == null) {
+ return;
+ }
+
+ int N = immis.size();
mItems = new CharSequence[N];
mIms = new InputMethodInfo[N];
for (int i = 0; i < N; ++i) {
InputMethodInfo property = immis.get(i);
+ if (property == null) {
+ i--;
+ N--;
+ continue;
+ }
mItems[i] = property.loadLabel(pm);
mIms[i] = property;
}
@@ -1517,6 +1526,9 @@
mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
+ if (mIms == null) {
+ return;
+ }
synchronized (mMethodMap) {
InputMethodInfo im = mIms[which];
hideInputMethodMenu();
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 0535d4c..a08258a 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -22,6 +22,7 @@
import android.os.LatencyTimer;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -43,6 +44,7 @@
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.PrintWriter;
import java.util.ArrayList;
public abstract class KeyInputQueue {
@@ -738,6 +740,7 @@
InputDevice.MotionState ms = di.mAbs;
if (ms.changed) {
+ ms.everChanged = true;
ms.changed = false;
if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
@@ -809,6 +812,7 @@
ms = di.mRel;
if (ms.changed) {
+ ms.everChanged = true;
ms.changed = false;
me = ms.generateRelMotion(di, curTime,
@@ -1280,4 +1284,91 @@
return null;
}
private static native boolean readEvent(RawInputEvent outEvent);
+
+ void dump(PrintWriter pw, String prefix) {
+ synchronized (mFirst) {
+ for (int i=0; i<mDevices.size(); i++) {
+ InputDevice dev = mDevices.valueAt(i);
+ pw.print(prefix); pw.print("Device #");
+ pw.print(mDevices.keyAt(i)); pw.print(" ");
+ pw.print(dev.name); pw.print(" (classes=0x");
+ pw.print(Integer.toHexString(dev.classes));
+ pw.println("):");
+ pw.print(prefix); pw.print(" mKeyDownTime=");
+ pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
+ pw.println(dev.mMetaKeysState);
+ if (dev.absX != null) {
+ pw.print(prefix); pw.print(" absX: "); dev.absX.dump(pw);
+ pw.println("");
+ }
+ if (dev.absY != null) {
+ pw.print(prefix); pw.print(" absY: "); dev.absY.dump(pw);
+ pw.println("");
+ }
+ if (dev.absPressure != null) {
+ pw.print(prefix); pw.print(" absPressure: ");
+ dev.absPressure.dump(pw); pw.println("");
+ }
+ if (dev.absSize != null) {
+ pw.print(prefix); pw.print(" absSize: ");
+ dev.absSize.dump(pw); pw.println("");
+ }
+ if (dev.mAbs.everChanged) {
+ pw.print(prefix); pw.println(" mAbs:");
+ dev.mAbs.dump(pw, prefix + " ");
+ }
+ if (dev.mRel.everChanged) {
+ pw.print(prefix); pw.println(" mRel:");
+ dev.mRel.dump(pw, prefix + " ");
+ }
+ }
+ pw.println(" ");
+ for (int i=0; i<mIgnoredDevices.size(); i++) {
+ InputDevice dev = mIgnoredDevices.valueAt(i);
+ pw.print(prefix); pw.print("Ignored Device #");
+ pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
+ pw.print(dev.name); pw.print(" (classes=0x");
+ pw.print(Integer.toHexString(dev.classes));
+ pw.println(")");
+ }
+ pw.println(" ");
+ for (int i=0; i<mVirtualKeys.size(); i++) {
+ VirtualKey vk = mVirtualKeys.get(i);
+ pw.print(prefix); pw.print("Virtual Key #");
+ pw.print(i); pw.println(":");
+ pw.print(prefix); pw.print(" scancode="); pw.println(vk.scancode);
+ pw.print(prefix); pw.print(" centerx="); pw.print(vk.centerx);
+ pw.print(" centery="); pw.print(vk.centery);
+ pw.print(" width="); pw.print(vk.width);
+ pw.print(" height="); pw.println(vk.height);
+ pw.print(prefix); pw.print(" hitLeft="); pw.print(vk.hitLeft);
+ pw.print(" hitTop="); pw.print(vk.hitTop);
+ pw.print(" hitRight="); pw.print(vk.hitRight);
+ pw.print(" hitBottom="); pw.println(vk.hitBottom);
+ if (vk.lastDevice != null) {
+ pw.print(prefix); pw.print(" lastDevice=#");
+ pw.println(vk.lastDevice.id);
+ }
+ if (vk.lastKeycode != 0) {
+ pw.print(prefix); pw.print(" lastKeycode=");
+ pw.println(vk.lastKeycode);
+ }
+ }
+ pw.println(" ");
+ pw.print(prefix); pw.print(" Default keyboard: ");
+ pw.println(SystemProperties.get("hw.keyboards.0.devname"));
+ pw.print(prefix); pw.print(" mGlobalMetaState=");
+ pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
+ pw.println(mHaveGlobalMetaState);
+ pw.print(prefix); pw.print(" mDisplayWidth=");
+ pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
+ pw.println(mDisplayHeight);
+ pw.print(prefix); pw.print(" mOrientation=");
+ pw.println(mOrientation);
+ if (mPressedVirtualKey != null) {
+ pw.print(prefix); pw.print(" mPressedVirtualKey.scancode=");
+ pw.println(mPressedVirtualKey.scancode);
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 67eba3d..8781263 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -10851,6 +10851,10 @@
return;
}
+ pw.println("Input State:");
+ mQueue.dump(pw, " ");
+ pw.println(" ");
+
synchronized(mWindowMap) {
pw.println("Current Window Manager state:");
for (int i=mWindows.size()-1; i>=0; i--) {
@@ -11014,7 +11018,7 @@
if (mDimAnimator != null) {
mDimAnimator.printTo(pw);
} else {
- pw.print( " no DimAnimator ");
+ pw.println( " no DimAnimator ");
}
pw.print(" mInputMethodAnimLayerAdjustment=");
pw.print(mInputMethodAnimLayerAdjustment);