Merge "No more use audio mime type for voicemail uris."
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index e57ceab..8e92eca 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -4354,7 +4354,11 @@
// If the cursor doesn't contain a snippet column, don't bother wrapping it.
if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) {
- return cursor;
+ if (VERBOSE_LOGGING) {
+ return new InstrumentedCursorWrapper(cursor, uri, TAG);
+ } else {
+ return cursor;
+ }
}
// Parse out snippet arguments for use when snippets are retrieved from the cursor.
@@ -4375,8 +4379,13 @@
int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3])
: DEFAULT_SNIPPET_ARG_MAX_TOKENS;
- return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis,
- maxTokens);
+ if (VERBOSE_LOGGING) {
+ return new InstrumentedCursorWrapper(new SnippetizingCursorWrapper(
+ cursor, query, startMatch, endMatch, ellipsis, maxTokens), uri, TAG);
+ } else {
+ return new SnippetizingCursorWrapper(cursor, query, startMatch, endMatch, ellipsis,
+ maxTokens);
+ }
}
private CrossProcessCursor getCrossProcessCursor(Cursor cursor) {
diff --git a/src/com/android/providers/contacts/CrossProcessCursorWrapper.java b/src/com/android/providers/contacts/CrossProcessCursorWrapper.java
new file mode 100644
index 0000000..76baa96
--- /dev/null
+++ b/src/com/android/providers/contacts/CrossProcessCursorWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts;
+
+import android.database.CrossProcessCursor;
+import android.database.Cursor;
+import android.database.CursorWindow;
+import android.database.CursorWrapper;
+
+/**
+ * Cursor wrapper that implements {@link CrossProcessCursor}, but will only behave as such if the
+ * cursor it is wrapping is itself a {@link CrossProcessCursor} or another wrapper around the same.
+ */
+public class CrossProcessCursorWrapper extends CursorWrapper implements CrossProcessCursor {
+
+ // The cross process cursor. Only non-null if the wrapped cursor was a cross-process cursor.
+ private final CrossProcessCursor mCrossProcessCursor;
+
+ public CrossProcessCursorWrapper(Cursor cursor) {
+ super(cursor);
+ mCrossProcessCursor = getCrossProcessCursor(cursor);
+ }
+
+ private CrossProcessCursor getCrossProcessCursor(Cursor cursor) {
+ if (cursor instanceof CrossProcessCursor) {
+ return (CrossProcessCursor) cursor;
+ } else if (cursor instanceof CursorWrapper) {
+ return getCrossProcessCursor(((CursorWrapper) cursor).getWrappedCursor());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void fillWindow(int pos, CursorWindow window) {
+ if (mCrossProcessCursor != null) {
+ mCrossProcessCursor.fillWindow(pos, window);
+ } else {
+ throw new UnsupportedOperationException("Wrapped cursor is not a cross-process cursor");
+ }
+ }
+
+ @Override
+ public CursorWindow getWindow() {
+ if (mCrossProcessCursor != null) {
+ return mCrossProcessCursor.getWindow();
+ } else {
+ throw new UnsupportedOperationException("Wrapped cursor is not a cross-process cursor");
+ }
+ }
+
+ @Override
+ public boolean onMove(int oldPosition, int newPosition) {
+ if (mCrossProcessCursor != null) {
+ return mCrossProcessCursor.onMove(oldPosition, newPosition);
+ } else {
+ throw new UnsupportedOperationException("Wrapped cursor is not a cross-process cursor");
+ }
+ }
+
+}
diff --git a/src/com/android/providers/contacts/InstrumentedCursorWrapper.java b/src/com/android/providers/contacts/InstrumentedCursorWrapper.java
new file mode 100644
index 0000000..c412810
--- /dev/null
+++ b/src/com/android/providers/contacts/InstrumentedCursorWrapper.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.contacts;
+
+import com.google.android.collect.Lists;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Cursor wrapper that handles tracking time taken before query result came back and how long
+ * the cursor was open before it was closed.
+ */
+public class InstrumentedCursorWrapper extends CrossProcessCursorWrapper {
+
+ /**
+ * Static list of active cursors.
+ */
+ private static List<InstrumentedCursorWrapper> mActiveCursors = Lists.newArrayList();
+
+ /**
+ * Time (ms since epoch) when the cursor was created.
+ */
+ private long mCreationTime;
+
+ /**
+ * Milliseconds after creation at which the query completed (triggered by a getCount or
+ * any method that moves the cursor).
+ */
+ private long mTimeToQuery;
+
+ /**
+ * The URI being queried in this cursor.
+ */
+ private Uri mUri;
+
+ /**
+ * Log tag to use.
+ */
+ private String mTag;
+
+ public InstrumentedCursorWrapper(Cursor cursor, Uri uri, String tag) {
+ super(cursor);
+ mCreationTime = System.currentTimeMillis();
+ mUri = uri;
+ mTag = tag;
+ mActiveCursors.add(this);
+ }
+
+ @Override
+ public int getCount() {
+ int count = super.getCount();
+ logQueryTime();
+ return count;
+ }
+
+ @Override
+ public boolean moveToFirst() {
+ boolean result = super.moveToFirst();
+ logQueryTime();
+ return result;
+ }
+
+ @Override
+ public boolean moveToLast() {
+ boolean result = super.moveToLast();
+ logQueryTime();
+ return result;
+ }
+
+ @Override
+ public boolean move(int offset) {
+ boolean result = super.move(offset);
+ logQueryTime();
+ return result;
+ }
+
+ @Override
+ public boolean moveToPosition(int position) {
+ boolean result = super.moveToPosition(position);
+ logQueryTime();
+ return result;
+ }
+
+ @Override
+ public boolean moveToNext() {
+ boolean result = super.moveToNext();
+ logQueryTime();
+ return result;
+ }
+
+ @Override
+ public boolean moveToPrevious() {
+ boolean result = super.moveToPrevious();
+ logQueryTime();
+ return result;
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ long timeToClose = System.currentTimeMillis() - mCreationTime;
+ Log.v(mTag, timeToClose + "ms to close for URI " + mUri
+ + " (" + (timeToClose - mTimeToQuery) + "ms since query complete)");
+ mActiveCursors.remove(this);
+ Log.v(mTag, mActiveCursors.size() + " cursors still open");
+ }
+
+ private void logQueryTime() {
+ if (mTimeToQuery == 0) {
+ mTimeToQuery = System.currentTimeMillis() - mCreationTime;
+ Log.v(mTag, mTimeToQuery + "ms to query URI " + mUri);
+ }
+ }
+}
diff --git a/src/com/android/providers/contacts/SnippetizingCursorWrapper.java b/src/com/android/providers/contacts/SnippetizingCursorWrapper.java
index 73fd2a3..61c5dcd 100644
--- a/src/com/android/providers/contacts/SnippetizingCursorWrapper.java
+++ b/src/com/android/providers/contacts/SnippetizingCursorWrapper.java
@@ -18,8 +18,6 @@
import android.database.CrossProcessCursor;
import android.database.Cursor;
-import android.database.CursorWindow;
-import android.database.CursorWrapper;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.SearchSnippetColumns;
import android.text.TextUtils;
@@ -38,15 +36,12 @@
* Note that this wrapper implements {@link CrossProcessCursor}, but will only behave as such if the
* cursor it is wrapping is itself a {@link CrossProcessCursor} or another wrapper around the same.
*/
-public class SnippetizingCursorWrapper extends CursorWrapper implements CrossProcessCursor {
+public class SnippetizingCursorWrapper extends CrossProcessCursorWrapper {
// Pattern for splitting a line into tokens. This matches e-mail addresses as a single token,
// otherwise splitting on any group of non-alphanumeric characters.
Pattern SPLIT_PATTERN = Pattern.compile("([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
- // The cross process cursor. Only non-null if the wrapped cursor was a cross-process cursor.
- private final CrossProcessCursor mCrossProcessCursor;
-
// Index of the snippet field (if any).
private final int mSnippetIndex;
@@ -71,10 +66,9 @@
* @param ellipsis Ellipsis characters to use at the start or end of the snippet if appropriate.
* @param maxTokens Maximum number of tokens to include in the snippet.
*/
- SnippetizingCursorWrapper(Cursor cursor, String query, String startMatch,
- String endMatch, String ellipsis, int maxTokens) {
+ SnippetizingCursorWrapper(Cursor cursor, String query, String startMatch, String endMatch,
+ String ellipsis, int maxTokens) {
super(cursor);
- mCrossProcessCursor = getCrossProcessCursor(cursor);
mSnippetIndex = getColumnIndex(SearchSnippetColumns.SNIPPET);
mQuery = query;
mStartMatch = startMatch;
@@ -84,43 +78,6 @@
mDoSnippetizing = mQuery.split(ContactsProvider2.QUERY_TOKENIZER_REGEX).length == 1;
}
- private CrossProcessCursor getCrossProcessCursor(Cursor cursor) {
- if (cursor instanceof CrossProcessCursor) {
- return (CrossProcessCursor) cursor;
- } else if (cursor instanceof CursorWrapper) {
- return getCrossProcessCursor(((CursorWrapper) cursor).getWrappedCursor());
- } else {
- return null;
- }
- }
-
- @Override
- public void fillWindow(int pos, CursorWindow window) {
- if (mCrossProcessCursor != null) {
- mCrossProcessCursor.fillWindow(pos, window);
- } else {
- throw new UnsupportedOperationException("Wrapped cursor is not a cross-process cursor");
- }
- }
-
- @Override
- public CursorWindow getWindow() {
- if (mCrossProcessCursor != null) {
- return mCrossProcessCursor.getWindow();
- } else {
- throw new UnsupportedOperationException("Wrapped cursor is not a cross-process cursor");
- }
- }
-
- @Override
- public boolean onMove(int oldPosition, int newPosition) {
- if (mCrossProcessCursor != null) {
- return mCrossProcessCursor.onMove(oldPosition, newPosition);
- } else {
- throw new UnsupportedOperationException("Wrapped cursor is not a cross-process cursor");
- }
- }
-
@Override
public String getString(int columnIndex) {
String columnContent = super.getString(columnIndex);