diff options
| -rw-r--r-- | api/current.xml | 6 | ||||
| -rw-r--r-- | calendar/Android.mk | 17 | ||||
| -rw-r--r-- | core/java/android/content/ContentService.java | 53 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteCompiledSql.java | 19 | ||||
| -rw-r--r-- | core/java/android/database/sqlite/SQLiteProgram.java | 9 | ||||
| -rw-r--r-- | core/java/android/provider/Browser.java | 60 | ||||
| -rw-r--r-- | core/java/android/widget/AbsListView.java | 11 | ||||
| -rw-r--r-- | core/java/android/widget/GridView.java | 4 | ||||
| -rw-r--r-- | core/java/android/widget/ListView.java | 4 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/content/ObserverNodeTest.java | 35 | ||||
| -rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 3 |
11 files changed, 143 insertions, 78 deletions
diff --git a/api/current.xml b/api/current.xml index d74127ad2d06..28a71687e3ad 100644 --- a/api/current.xml +++ b/api/current.xml @@ -55017,7 +55017,7 @@ volatile="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="protected" > </field> @@ -55027,7 +55027,7 @@ volatile="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="protected" > </field> @@ -55037,7 +55037,7 @@ volatile="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="protected" > </field> diff --git a/calendar/Android.mk b/calendar/Android.mk deleted file mode 100644 index 7f9ee0ac452f..000000000000 --- a/calendar/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2009 Google, Inc. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := calendar -LOCAL_SRC_FILES := \ - ../core/java/android/provider/Calendar.java \ - ../core/java/android/pim/EventRecurrence.java \ - ../core/java/android/pim/ICalendar.java \ - ../core/java/android/pim/RecurrenceSet.java \ - ../core/java/android/pim/ContactsAsyncHelper.java \ - -include $(BUILD_STATIC_JAVA_LIBRARY) - -# Include this library in the build server's output directory -$(call dist-for-goals, droid, $(LOCAL_BUILT_MODULE):calendar.jar) diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index b5a78fa95c71..0477d6dfc3e9 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -32,7 +32,6 @@ import android.Manifest; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** @@ -104,7 +103,7 @@ public final class ContentService extends IContentService.Stub { throw new IllegalArgumentException("You must pass a valid uri and observer"); } synchronized (mRootNode) { - mRootNode.addObserver(uri, observer, notifyForDescendents); + mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode); if (Config.LOGV) Log.v(TAG, "Registered observer " + observer + " at " + uri + " with notifyForDescendents " + notifyForDescendents); } @@ -115,7 +114,7 @@ public final class ContentService extends IContentService.Stub { throw new IllegalArgumentException("You must pass a valid observer"); } synchronized (mRootNode) { - mRootNode.removeObserver(observer); + mRootNode.removeObserverLocked(observer); if (Config.LOGV) Log.v(TAG, "Unregistered observer " + observer); } } @@ -132,7 +131,7 @@ public final class ContentService extends IContentService.Stub { try { ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); synchronized (mRootNode) { - mRootNode.collectObservers(uri, 0, observer, observerWantsSelfNotifications, + mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, calls); } final int numCalls = calls.size(); @@ -470,10 +469,12 @@ public final class ContentService extends IContentService.Stub { */ public static final class ObserverNode { private class ObserverEntry implements IBinder.DeathRecipient { - public IContentObserver observer; - public boolean notifyForDescendents; + public final IContentObserver observer; + public final boolean notifyForDescendents; + private final Object observersLock; - public ObserverEntry(IContentObserver o, boolean n) { + public ObserverEntry(IContentObserver o, boolean n, Object observersLock) { + this.observersLock = observersLock; observer = o; notifyForDescendents = n; try { @@ -484,7 +485,9 @@ public final class ContentService extends IContentService.Stub { } public void binderDied() { - removeObserver(observer); + synchronized (observersLock) { + removeObserverLocked(observer); + } } } @@ -519,16 +522,16 @@ public final class ContentService extends IContentService.Stub { return uri.getPathSegments().size() + 1; } - public void addObserver(Uri uri, IContentObserver observer, boolean notifyForDescendents) { - addObserver(uri, 0, observer, notifyForDescendents); + public void addObserverLocked(Uri uri, IContentObserver observer, + boolean notifyForDescendents, Object observersLock) { + addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock); } - private void addObserver(Uri uri, int index, IContentObserver observer, - boolean notifyForDescendents) { - + private void addObserverLocked(Uri uri, int index, IContentObserver observer, + boolean notifyForDescendents, Object observersLock) { // If this is the leaf node add the observer if (index == countUriSegments(uri)) { - mObservers.add(new ObserverEntry(observer, notifyForDescendents)); + mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock)); return; } @@ -538,7 +541,7 @@ public final class ContentService extends IContentService.Stub { for (int i = 0; i < N; i++) { ObserverNode node = mChildren.get(i); if (node.mName.equals(segment)) { - node.addObserver(uri, index + 1, observer, notifyForDescendents); + node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock); return; } } @@ -546,13 +549,13 @@ public final class ContentService extends IContentService.Stub { // No child found, create one ObserverNode node = new ObserverNode(segment); mChildren.add(node); - node.addObserver(uri, index + 1, observer, notifyForDescendents); + node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock); } - public boolean removeObserver(IContentObserver observer) { + public boolean removeObserverLocked(IContentObserver observer) { int size = mChildren.size(); for (int i = 0; i < size; i++) { - boolean empty = mChildren.get(i).removeObserver(observer); + boolean empty = mChildren.get(i).removeObserverLocked(observer); if (empty) { mChildren.remove(i); i--; @@ -578,10 +581,8 @@ public final class ContentService extends IContentService.Stub { return false; } - private void collectMyObservers(Uri uri, - boolean leaf, IContentObserver observer, boolean selfNotify, - ArrayList<ObserverCall> calls) - { + private void collectMyObserversLocked(boolean leaf, IContentObserver observer, + boolean selfNotify, ArrayList<ObserverCall> calls) { int N = mObservers.size(); IBinder observerBinder = observer == null ? null : observer.asBinder(); for (int i = 0; i < N; i++) { @@ -600,17 +601,17 @@ public final class ContentService extends IContentService.Stub { } } - public void collectObservers(Uri uri, int index, IContentObserver observer, + public void collectObserversLocked(Uri uri, int index, IContentObserver observer, boolean selfNotify, ArrayList<ObserverCall> calls) { String segment = null; int segmentCount = countUriSegments(uri); if (index >= segmentCount) { // This is the leaf node, notify all observers - collectMyObservers(uri, true, observer, selfNotify, calls); + collectMyObserversLocked(true, observer, selfNotify, calls); } else if (index < segmentCount){ segment = getUriSegment(uri, index); // Notify any observers at this level who are interested in descendents - collectMyObservers(uri, false, observer, selfNotify, calls); + collectMyObserversLocked(false, observer, selfNotify, calls); } int N = mChildren.size(); @@ -618,7 +619,7 @@ public final class ContentService extends IContentService.Stub { ObserverNode node = mChildren.get(i); if (segment == null || node.mName.equals(segment)) { // We found the child, - node.collectObservers(uri, index + 1, observer, selfNotify, calls); + node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls); if (segment != null) { break; } diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java index a7a1d9ae6d25..486ad20dcb7f 100644 --- a/core/java/android/database/sqlite/SQLiteCompiledSql.java +++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java @@ -28,6 +28,8 @@ import android.util.Log; */ /* package */ class SQLiteCompiledSql { + private static final String TAG = "SQLiteCompiledSql"; + /** The database this program is compiled against. */ /* package */ SQLiteDatabase mDatabase; @@ -44,11 +46,17 @@ import android.util.Log; */ /* package */ int nStatement = 0; + /** the following are for debugging purposes */ + private String mSqlStmt = null; + private Throwable mStackTrace = null; + /** when in cache and is in use, this member is set */ private boolean mInUse = false; /* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) { mDatabase = db; + mSqlStmt = sql; + mStackTrace = new Exception().fillInStackTrace(); this.nHandle = db.mNativeHandle; compile(sql, true); } @@ -115,8 +123,15 @@ import android.util.Log; * Make sure that the native resource is cleaned up. */ @Override - protected void finalize() { - releaseSqlStatement(); + protected void finalize() throws Throwable { + try { + if (nStatement == 0) return; + // finalizer should NEVER get called + Log.w(TAG, "finalizer should never be called. sql: " + mSqlStmt, mStackTrace); + releaseSqlStatement(); + } finally { + super.finalize(); + } } /** diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index 63acab767d71..389e15e6935a 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -21,7 +21,10 @@ package android.database.sqlite; */ public abstract class SQLiteProgram extends SQLiteClosable { - /** The database this program is compiled against. */ + /** The database this program is compiled against. + * @deprecated do not use this + */ + @Deprecated protected SQLiteDatabase mDatabase; /** The SQL used to create this query */ @@ -30,7 +33,9 @@ public abstract class SQLiteProgram extends SQLiteClosable { /** * Native linkage, do not modify. This comes from the database and should not be modified * in here or in the native code. + * @deprecated do not use this */ + @Deprecated protected int nHandle = 0; /** @@ -41,7 +46,9 @@ public abstract class SQLiteProgram extends SQLiteClosable { /** * SQLiteCompiledSql statement id is populated with the corresponding object from the above * member. This member is used by the native_bind_* methods + * @deprecated do not use this */ + @Deprecated protected int nStatement = 0; /* package */ SQLiteProgram(SQLiteDatabase db, String sql) { diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java index 10b93711ebba..f32fb5a2ec57 100644 --- a/core/java/android/provider/Browser.java +++ b/core/java/android/provider/Browser.java @@ -211,6 +211,57 @@ public class Browser { new String[] { BookmarkColumns.URL }, null, null, null); } + private static final void addOrUrlEquals(StringBuilder sb) { + sb.append(" OR " + BookmarkColumns.URL + " = "); + } + + /** + * Return a Cursor with all history/bookmarks that are similar to url, + * where similar means 'http(s)://' and 'www.' are optional, but the rest + * of the url is the same. + * @param cr The ContentResolver used to access the database. + * @param url The url to compare to. + * @hide + */ + public static final Cursor getVisitedLike(ContentResolver cr, String url) { + boolean secure = false; + String compareString = url; + if (compareString.startsWith("http://")) { + compareString = compareString.substring(7); + } else if (compareString.startsWith("https://")) { + compareString = compareString.substring(8); + secure = true; + } + if (compareString.startsWith("www.")) { + compareString = compareString.substring(4); + } + StringBuilder whereClause = null; + if (secure) { + whereClause = new StringBuilder(BookmarkColumns.URL + " = "); + DatabaseUtils.appendEscapedSQLString(whereClause, + "https://" + compareString); + addOrUrlEquals(whereClause); + DatabaseUtils.appendEscapedSQLString(whereClause, + "https://www." + compareString); + } else { + whereClause = new StringBuilder(BookmarkColumns.URL + " = "); + DatabaseUtils.appendEscapedSQLString(whereClause, + compareString); + addOrUrlEquals(whereClause); + String wwwString = "www." + compareString; + DatabaseUtils.appendEscapedSQLString(whereClause, + wwwString); + addOrUrlEquals(whereClause); + DatabaseUtils.appendEscapedSQLString(whereClause, + "http://" + compareString); + addOrUrlEquals(whereClause); + DatabaseUtils.appendEscapedSQLString(whereClause, + "http://" + wwwString); + } + return cr.query(BOOKMARKS_URI, HISTORY_PROJECTION, + whereClause.toString(), null, null); + } + /** * Update the visited history to acknowledge that a site has been * visited. @@ -225,14 +276,7 @@ public class Browser { String url, boolean real) { long now = new Date().getTime(); try { - StringBuilder sb = new StringBuilder(BookmarkColumns.URL + " = "); - DatabaseUtils.appendEscapedSQLString(sb, url); - Cursor c = cr.query( - BOOKMARKS_URI, - HISTORY_PROJECTION, - sb.toString(), - null, - null); + Cursor c = getVisitedLike(cr, url); /* We should only get one answer that is exactly the same. */ if (c.moveToFirst()) { ContentValues map = new ContentValues(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 2ea6abcad0da..a555ae4772f5 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4032,6 +4032,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @ViewDebug.ExportedProperty boolean recycledHeaderFooter; + /** + * When an AbsListView is measured with an AT_MOST measure spec, it needs + * to obtain children views to measure itself. When doing so, the children + * are not attached to the window, but put in the recycler which assumes + * they've been attached before. Setting this flag will force the reused + * view to be attached to the window rather than just attached to the + * parent. + */ + @ViewDebug.ExportedProperty + boolean forceAdd; + public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 9e930a5f7e39..be633be65084 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -938,6 +938,7 @@ public class GridView extends AbsListView { child.setLayoutParams(p); } p.viewType = mAdapter.getItemViewType(0); + p.forceAdd = true; int childHeightSpec = getChildMeasureSpec( MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height); @@ -1257,9 +1258,10 @@ public class GridView extends AbsListView { } p.viewType = mAdapter.getItemViewType(position); - if (recycled) { + if (recycled && !p.forceAdd) { attachViewToParent(child, where, p); } else { + p.forceAdd = false; addViewInLayout(child, where, p, true); } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 88f2e123096c..e3eb6db99168 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1109,6 +1109,7 @@ public class ListView extends AbsListView { child.setLayoutParams(p); } p.viewType = mAdapter.getItemViewType(position); + p.forceAdd = true; int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, mListPadding.left + mListPadding.right, p.width); @@ -1743,10 +1744,11 @@ public class ListView extends AbsListView { } p.viewType = mAdapter.getItemViewType(position); - if (recycled || (p.recycledHeaderFooter && + if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter && p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) { attachViewToParent(child, flowDown ? -1 : 0, p); } else { + p.forceAdd = false; if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { p.recycledHeaderFooter = true; } diff --git a/core/tests/coretests/src/android/content/ObserverNodeTest.java b/core/tests/coretests/src/android/content/ObserverNodeTest.java index 68cc75b7b2ad..736c75926db4 100644 --- a/core/tests/coretests/src/android/content/ObserverNodeTest.java +++ b/core/tests/coretests/src/android/content/ObserverNodeTest.java @@ -24,50 +24,49 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.test.AndroidTestCase; -import android.util.Log; -public class ObserverNodeTest extends AndroidTestCase { +public class ObserverNodeTest extends AndroidTestCase { static class TestObserver extends ContentObserver { public TestObserver() { super(new Handler()); } } - + public void testUri() { ObserverNode root = new ObserverNode(""); Uri[] uris = new Uri[] { Uri.parse("content://c/a/"), Uri.parse("content://c/"), - Uri.parse("content://x/"), + Uri.parse("content://x/"), Uri.parse("content://c/b/"), Uri.parse("content://c/a/a1/1/"), Uri.parse("content://c/a/a1/2/"), Uri.parse("content://c/b/1/"), Uri.parse("content://c/b/2/"), }; - + int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3}; - + // special case - root.addObserver(uris[0], new TestObserver().getContentObserver(), false); + root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root); for(int i = 1; i < uris.length; i++) { - root.addObserver(uris[i], new TestObserver().getContentObserver(), true); + root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root); } - + ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); - + for (int i = nums.length - 1; i >=0; --i) { - root.collectObservers(uris[i], 0, null, false, calls); + root.collectObserversLocked(uris[i], 0, null, false, calls); assertEquals(nums[i], calls.size()); calls.clear(); } } - + public void testUriNotNotify() { ObserverNode root = new ObserverNode(""); Uri[] uris = new Uri[] { Uri.parse("content://c/"), - Uri.parse("content://x/"), + Uri.parse("content://x/"), Uri.parse("content://c/a/"), Uri.parse("content://c/b/"), Uri.parse("content://c/a/1/"), @@ -76,15 +75,15 @@ public class ObserverNodeTest extends AndroidTestCase { Uri.parse("content://c/b/2/"), }; int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1}; - + for(int i = 0; i < uris.length; i++) { - root.addObserver(uris[i], new TestObserver().getContentObserver(), false); + root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root); } - + ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); - + for (int i = uris.length - 1; i >=0; --i) { - root.collectObservers(uris[i], 0, null, false, calls); + root.collectObserversLocked(uris[i], 0, null, false, calls); assertEquals(nums[i], calls.size()); calls.clear(); } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index c26d68274e60..594e01049157 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1768,7 +1768,7 @@ ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size) status_t MediaPlayerService::AudioCache::wait() { Mutex::Autolock lock(mLock); - if (!mCommandComplete) { + while (!mCommandComplete) { mSignal.wait(mLock); } mCommandComplete = false; @@ -1805,6 +1805,7 @@ void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int } // wake up thread + Mutex::Autolock lock(p->mLock); p->mCommandComplete = true; p->mSignal.signal(); } |