Merge "The TI MP3 decoder lies about the number of channels it outputs, add a quirk for that."
diff --git a/api/current.xml b/api/current.xml
index 2fbd374..9bd5c01 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -78032,17 +78032,6 @@
  visibility="public"
 >
 </method>
-<method name="isEnabled"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="removeListener"
  return="void"
  abstract="true"
diff --git a/common/java/com/android/common/speech/LoggingEvents.java b/common/java/com/android/common/speech/LoggingEvents.java
index eb9476f..3b3ecb8 100644
--- a/common/java/com/android/common/speech/LoggingEvents.java
+++ b/common/java/com/android/common/speech/LoggingEvents.java
@@ -16,9 +16,6 @@
 
 package com.android.common.speech;
 
-import android.content.Intent;
-import android.content.Context;
-
 /**
  * Logging event constants used for Voice Search and VoiceIME. These are the
  * keys and values of extras to be specified in logging broadcast intents.
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 3dfbe71..ec9f3b4 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -903,15 +903,14 @@
             if (mSearchable == null) {
                 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 {
-                // 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.
-                ((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE)).
-                        stopSearch();
-                
-                if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+                if (searchable.getVoiceSearchLaunchWebSearch()) {
                     getContext().startActivity(mVoiceWebSearchIntent);
-                } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+                } else if (searchable.getVoiceSearchLaunchRecognizer()) {
                     Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);                    
                     getContext().startActivity(appSearchIntent);
                 }
diff --git a/core/java/android/speech/RecognizerResultsIntent.java b/core/java/android/speech/RecognizerResultsIntent.java
new file mode 100644
index 0000000..2310a07
--- /dev/null
+++ b/core/java/android/speech/RecognizerResultsIntent.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 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.speech;
+
+import java.util.ArrayList;
+
+/**
+ * Constants for intents related to showing speech recognition results.
+ * 
+ * These constants should not be needed for normal utilization of speech recognition. They
+ * would only be called if you wanted to trigger a view of voice search results in your
+ * application, or implemented if you wanted to offer a different view for voice search results
+ * with your application.
+ * 
+ * The standard behavior here for someone receiving an {@link #ACTION_VOICE_SEARCH_RESULTS} is to
+ * first retrieve the list of {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS}, and use any provided
+ * HTML for that result in {@link #EXTRA_VOICE_SEARCH_RESULT_HTML}, if available, to display
+ * the search results. If that is not available, then the corresponding url for that result in
+ * {@link #EXTRA_VOICE_SEARCH_RESULT_URLS} should be used. And if even that is not available,
+ * then a search url should be constructed from the actual recognition result string.
+ * 
+ * @hide for making public in a later release
+ */
+public class RecognizerResultsIntent {
+    private RecognizerResultsIntent() {
+        // Not for instantiating.
+    }
+
+    /**
+     * Intent that can be sent by implementations of voice search to display the results of
+     * a search in, for example, a web browser.
+     * 
+     * This intent should always be accompanied by at least
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS}, and optionally but recommended,
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_URLS}, and sometimes
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_HTML}. These are three parallel arrays, where a
+     * recognition result string at index N of {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS} should
+     * be accompanied by a url to use for searching based on that string at index N of
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_URLS}, and, possibly, the full html to display for
+     * that result at index N of {@link #EXTRA_VOICE_SEARCH_RESULT_HTML}. 
+     * 
+     * @hide for making public in a later release
+     */
+    public static final String ACTION_VOICE_SEARCH_RESULTS =
+            "android.speech.action.VOICE_SEARCH_RESULTS";
+    
+    /**
+     * The key to an extra {@link ArrayList} of {@link String}s that contains the list of
+     * recognition alternates from voice search, in order from highest to lowest confidence.
+     * 
+     * @hide for making public in a later release
+     */
+    public static final String EXTRA_VOICE_SEARCH_RESULT_STRINGS =
+            "android.speech.extras.VOICE_SEARCH_RESULT_STRINGS";
+    
+    /**
+     * The key to an extra {@link ArrayList} of {@link String}s that contains the search urls
+     * to use, if available, for the recognition alternates provided in
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS}. This list should always be the same size as the
+     * one provided in {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS} - if a result cannot provide a
+     * search url, that entry in this ArrayList should be <code>null</code>, and the implementor of
+     * {@link #ACTION_VOICE_SEARCH_RESULTS} should execute a search of its own choosing,
+     * based on the recognition result string.
+     * 
+     * @hide for making public in a later release
+     */
+    public static final String EXTRA_VOICE_SEARCH_RESULT_URLS =
+            "android.speech.extras.VOICE_SEARCH_RESULT_URLS";
+    
+    /**
+     * The key to an extra {@link ArrayList} of {@link String}s that contains the html content to
+     * use, if available, for the recognition alternates provided in
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS}. This list should always be the same size as the
+     * one provided in {@link #EXTRA_VOICE_SEARCH_RESULT_STRINGS} - if a result cannot provide
+     * html, that entry in this list should be <code>null</code>, and the implementor of
+     * {@link #ACTION_VOICE_SEARCH_RESULTS} should back off to the corresponding url provided in
+     * {@link #EXTRA_VOICE_SEARCH_RESULT_URLS}, if available, or else should execute a search of
+     * its own choosing, based on the recognition result string.
+     * 
+     * Currently this html content should be expected in the form of an "inline:" uri for the
+     * Browser. In the future this may change to a "content://" uri or some other identifier.
+     * Anyone who reads this extra should confirm that a result is in fact an "inline:" uri and
+     * back off to the urls or strings gracefully if it is not, thus maintaining future backwards
+     * compatibility if this changes.
+     * 
+     * @hide not to be exposed immediately as the implementation details may change
+     */
+    public static final String EXTRA_VOICE_SEARCH_RESULT_HTML =
+            "android.speech.extras.VOICE_SEARCH_RESULT_HTML";
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 39b0a63..e23109f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3109,6 +3109,7 @@
                 zoomScale = mZoomScale;
                 // set mZoomScale to be 0 as we have done animation
                 mZoomScale = 0;
+                WebViewCore.resumeUpdatePicture(mWebViewCore);
                 // call invalidate() again to draw with the final filters
                 invalidate();
                 if (mNeedToAdjustWebTextView) {
@@ -4458,7 +4459,7 @@
                     deltaX = 0;
                     deltaY = 0;
 
-                    WebViewCore.reducePriority(mWebViewCore);
+                    WebViewCore.reducePriority();
                     if (!mDragFromTextInput) {
                         nativeHideCursor();
                     }
@@ -4621,7 +4622,7 @@
                                     || computeVerticalScrollExtent() < computeVerticalScrollRange())) {
                                 // we will not rewrite drag code here, but we
                                 // will try fling if it applies.
-                                WebViewCore.reducePriority(mWebViewCore);
+                                WebViewCore.reducePriority();
                                 // fall through to TOUCH_DRAG_MODE
                             } else {
                                 break;
@@ -4658,7 +4659,7 @@
                             break;
                         }
                         mLastVelocity = 0;
-                        WebViewCore.resumePriority(mWebViewCore);
+                        WebViewCore.resumePriority();
                         break;
                     case TOUCH_DRAG_START_MODE:
                     case TOUCH_DONE_MODE:
@@ -4707,7 +4708,7 @@
             mVelocityTracker = null;
         }
         if (mTouchMode == TOUCH_DRAG_MODE) {
-            WebViewCore.resumePriority(mWebViewCore);
+            WebViewCore.resumePriority();
         }
         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
         mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
@@ -5033,7 +5034,7 @@
             vy = vy * 3 / 4;
         }
         if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) {
-            WebViewCore.resumePriority(mWebViewCore);
+            WebViewCore.resumePriority();
             return;
         }
         float currentVelocity = mScroller.getCurrVelocity();
@@ -5090,6 +5091,7 @@
             mInvInitialZoomScale = 1.0f / oldScale;
             mInvFinalZoomScale = 1.0f / mActualScale;
             mZoomScale = mActualScale;
+            WebViewCore.pauseUpdatePicture(mWebViewCore);
             invalidate();
             return true;
         } else {
@@ -5904,7 +5906,7 @@
                     }
                     break;
                 case RESUME_WEBCORE_PRIORITY:
-                    WebViewCore.resumePriority(mWebViewCore);
+                    WebViewCore.resumePriority();
                     break;
 
                 case LONG_PRESS_CENTER:
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 310721f..d4bb1d2 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1676,6 +1676,9 @@
     // Used to avoid posting more than one split picture message.
     private boolean mSplitPictureIsScheduled;
 
+    // Used to suspend drawing.
+    private boolean mDrawIsPaused;
+
     // mRestoreState is set in didFirstLayout(), and reset in the next
     // webkitDraw after passing it to the UI thread.
     private RestoreState mRestoreState = null;
@@ -1788,7 +1791,7 @@
         return result;
     }
 
-    static void reducePriority(WebViewCore core) {
+    static void reducePriority() {
         // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
         sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
         sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
@@ -1796,7 +1799,7 @@
                 .obtainMessage(WebCoreThread.REDUCE_PRIORITY));
     }
 
-    static void resumePriority(WebViewCore core) {
+    static void resumePriority() {
         // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
         sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
         sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
@@ -1814,6 +1817,33 @@
                 .obtainMessage(WebCoreThread.BLOCK_CACHE_TICKER));
     }
 
+    static void pauseUpdatePicture(WebViewCore core) {
+        // Note: there is one possible failure mode. If pauseUpdatePicture() is
+        // called from UI thread while WEBKIT_DRAW is just pulled out of the
+        // queue in WebCore thread to be executed. Then update won't be blocked.
+        if (core != null) {
+            synchronized (core) {
+                core.mDrawIsPaused = true;
+                if (core.mDrawIsScheduled) {
+                    core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
+                }
+            }
+        }
+
+    }
+
+    static void resumeUpdatePicture(WebViewCore core) {
+        if (core != null) {
+            synchronized (core) {
+                core.mDrawIsPaused = false;
+                if (core.mDrawIsScheduled) {
+                    core.mDrawIsScheduled = false;
+                    core.contentDraw();
+                }
+            }
+        }
+    }
+
     //////////////////////////////////////////////////////////////////////////
 
     private void restoreState(int index) {
@@ -1842,6 +1872,7 @@
         synchronized (this) {
             if (mDrawIsScheduled) return;
             mDrawIsScheduled = true;
+            if (mDrawIsPaused) return;
             mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
         }
     }
diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp
index 694514e..7877921 100644
--- a/core/jni/CursorWindow.cpp
+++ b/core/jni/CursorWindow.cpp
@@ -18,7 +18,8 @@
 #define LOG_TAG "CursorWindow"
 
 #include <utils/Log.h>
-#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
 
 #include <assert.h>
 #include <string.h>
@@ -37,7 +38,7 @@
 {
 }
 
-bool CursorWindow::setMemory(sp<IMemory> memory)     
+bool CursorWindow::setMemory(const sp<IMemory>& memory)
 {
     mMemory = memory;
     mData = (uint8_t *) memory->pointer();
@@ -47,7 +48,6 @@
     mHeader = (window_header_t *) mData;
 
     // Make the window read-only
-    mHeap = NULL;
     ssize_t size = memory->size();
     mSize = size;
     mMaxSize = size;
@@ -60,9 +60,10 @@
 {
     //TODO Use a non-memory dealer mmap region for localOnly
 
-    mHeap = new MemoryDealer(mMaxSize, "CursorWindow");
-    if (mHeap != NULL) {
-        mMemory = mHeap->allocate(mMaxSize);
+    sp<MemoryHeapBase> heap;
+    heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow");
+    if (heap != NULL) {
+        mMemory = new MemoryBase(heap, 0, mMaxSize);
         if (mMemory != NULL) {
             mData = (uint8_t *) mMemory->pointer();
             if (mData) {
@@ -75,10 +76,10 @@
                 return true;                
             }
         } 
-        LOGE("memory dealer allocation failed");
+        LOGE("CursorWindow heap allocation failed");
         return false;
     } else {
-        LOGE("failed to create the memory dealer");
+        LOGE("failed to create the CursorWindow heap");
         return false;
     }
 }
diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h
index e98b009..3fcb560 100644
--- a/core/jni/CursorWindow.h
+++ b/core/jni/CursorWindow.h
@@ -21,7 +21,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <binder/MemoryDealer.h>
+#include <binder/IMemory.h>
 #include <utils/RefBase.h>
 
 #include <jni.h>
@@ -101,7 +101,7 @@
 public:
                         CursorWindow(size_t maxSize);
                         CursorWindow(){}
-    bool                setMemory(sp<IMemory>);
+    bool                setMemory(const sp<IMemory>&);
                         ~CursorWindow();
 
     bool                initBuffer(bool localOnly);
@@ -189,7 +189,6 @@
     size_t mSize;
     size_t mMaxSize;
     window_header_t * mHeader;
-    sp<MemoryDealer> mHeap;
     sp<IMemory> mMemory;
 
     /**
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 7da16e4..9fe6ab4 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -37,7 +37,6 @@
     int getAccuracy();
     void enable();
     void disable();
-    boolean isEnabled();
     int getStatus(out Bundle extras);
     long getStatusUpdateTime();
     void enableLocationTracking(boolean enable);
diff --git a/location/java/android/location/LocationProviderImpl.java b/location/java/android/location/LocationProviderImpl.java
index 9a3624e..7148a02 100644
--- a/location/java/android/location/LocationProviderImpl.java
+++ b/location/java/android/location/LocationProviderImpl.java
@@ -75,10 +75,6 @@
             LocationProviderImpl.this.disable();
         }
 
-        public boolean isEnabled() {
-            return LocationProviderImpl.this.isEnabled();
-        }
-
         public int getStatus(Bundle extras) {
             return LocationProviderImpl.this.getStatus(extras);
         }
@@ -138,11 +134,6 @@
     public abstract void disable();
 
     /**
-     * Returns true if the provider is currently enabled
-     */
-    public abstract boolean isEnabled();
-
-    /**
      * Returns a information on the status of this provider.
      * {@link #OUT_OF_SERVICE} is returned if the provider is
      * out of service, and this is not expected to change in the near
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 9d67882..c8809a2 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -571,10 +571,6 @@
         }
     }
 
-    public boolean isEnabled() {
-        return mEnabled;
-    }
-
     public int getStatus(Bundle extras) {
         if (extras != null) {
             extras.putInt("satellites", mSvCount);
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index 89337b3..2e0be89 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -40,6 +40,7 @@
     private final String mName;
     private final ILocationProvider mProvider;
     private boolean mLocationTracking = false;
+    private boolean mEnabled = false;
     private long mMinTime = 0;
     private boolean mDead;
 
@@ -152,6 +153,7 @@
     public void enable() {
         try {
             mProvider.enable();
+            mEnabled = true;
         } catch (RemoteException e) {
             Log.e(TAG, "enable failed", e);
         }
@@ -160,18 +162,14 @@
     public void disable() {
         try {
             mProvider.disable();
+            mEnabled = false;
         } catch (RemoteException e) {
             Log.e(TAG, "disable failed", e);
         }
     }
 
     public boolean isEnabled() {
-        try {
-            return mProvider.isEnabled();
-        } catch (RemoteException e) {
-            Log.e(TAG, "isEnabled failed", e);
-            return false;
-        }
+        return mEnabled;
     }
 
     public int getStatus(Bundle extras) {
diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java
index 2614f82..7d9e86c 100644
--- a/location/java/com/android/internal/location/MockProvider.java
+++ b/location/java/com/android/internal/location/MockProvider.java
@@ -95,10 +95,6 @@
         return mStatusUpdateTime;
     }
 
-    public boolean isEnabled() {
-        return mEnabled;
-    }
-
     public int getAccuracy() {
         return mAccuracy;
     }
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 162bebb..550b84df 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -28,7 +28,8 @@
 #include <string.h>
 #include <cutils/atomic.h>
 #include <cutils/properties.h>
-#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
 #include <android_runtime/ActivityManager.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -62,8 +63,6 @@
 {
     LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
     mPid = pid;
-    mThumbnailDealer = NULL;
-    mAlbumArtDealer = NULL;
     mThumbnail = NULL;
     mAlbumArt = NULL;
     mRetriever = NULL;
@@ -94,8 +93,6 @@
     LOGV("disconnect from pid %d", mPid);
     Mutex::Autolock lock(mLock);
     mRetriever.clear();
-    mThumbnailDealer.clear();
-    mAlbumArtDealer.clear();
     mThumbnail.clear();
     mAlbumArt.clear();
     mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
@@ -242,7 +239,6 @@
     LOGV("captureFrame");
     Mutex::Autolock lock(mLock);
     mThumbnail.clear();
-    mThumbnailDealer.clear();
     if (mRetriever == NULL) {
         LOGE("retriever is not initialized");
         return NULL;
@@ -253,16 +249,15 @@
         return NULL;
     }
     size_t size = sizeof(VideoFrame) + frame->mSize;
-    mThumbnailDealer = new MemoryDealer(size, "MetadataRetrieverClient");
-    if (mThumbnailDealer == NULL) {
+    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
+    if (heap == NULL) {
         LOGE("failed to create MemoryDealer");
         delete frame;
         return NULL;
     }
-    mThumbnail = mThumbnailDealer->allocate(size);
+    mThumbnail = new MemoryBase(heap, 0, size);
     if (mThumbnail == NULL) {
         LOGE("not enough memory for VideoFrame size=%u", size);
-        mThumbnailDealer.clear();
         delete frame;
         return NULL;
     }
@@ -283,7 +278,6 @@
     LOGV("extractAlbumArt");
     Mutex::Autolock lock(mLock);
     mAlbumArt.clear();
-    mAlbumArtDealer.clear();
     if (mRetriever == NULL) {
         LOGE("retriever is not initialized");
         return NULL;
@@ -294,16 +288,15 @@
         return NULL;
     }
     size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
-    mAlbumArtDealer = new MemoryDealer(size, "MetadataRetrieverClient");
-    if (mAlbumArtDealer == NULL) {
+    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
+    if (heap == NULL) {
         LOGE("failed to create MemoryDealer object");
         delete albumArt;
         return NULL;
     }
-    mAlbumArt = mAlbumArtDealer->allocate(size);
+    mAlbumArt = new MemoryBase(heap, 0, size);
     if (mAlbumArt == NULL) {
         LOGE("not enough memory for MediaAlbumArt size=%u", size);
-        mAlbumArtDealer.clear();
         delete albumArt;
         return NULL;
     }
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 8cb8ad1..4aab94f 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -63,8 +63,6 @@
     int                                    mMode;
 
     // Keep the shared memory copy of album art and capture frame (for thumbnail)
-    sp<MemoryDealer>                       mAlbumArtDealer;
-    sp<MemoryDealer>                       mThumbnailDealer;
     sp<IMemory>                            mAlbumArt;
     sp<IMemory>                            mThumbnail;
 };