Merge "Move Phone.java APIs into InCallService"
diff --git a/api/current.txt b/api/current.txt
index deaf400..747fd29 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15564,6 +15564,11 @@
     ctor public MediaCryptoException(java.lang.String);
   }
 
+  public abstract interface MediaDataSource implements java.io.Closeable {
+    method public abstract long getSize();
+    method public abstract int readAt(long, byte[], int);
+  }
+
   public class MediaDescription implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.CharSequence getDescription();
@@ -15699,6 +15704,7 @@
     method public final void release();
     method public void seekTo(long, int);
     method public void selectTrack(int);
+    method public final void setDataSource(android.media.MediaDataSource) throws java.io.IOException, java.lang.IllegalArgumentException;
     method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String) throws java.io.IOException;
@@ -15878,6 +15884,7 @@
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.lang.IllegalArgumentException;
     method public void setDataSource(java.io.FileDescriptor) throws java.lang.IllegalArgumentException;
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
+    method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException;
     field public static final int METADATA_KEY_ALBUM = 1; // 0x1
     field public static final int METADATA_KEY_ALBUMARTIST = 13; // 0xd
     field public static final int METADATA_KEY_ARTIST = 2; // 0x2
@@ -15962,6 +15969,7 @@
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDisplay(android.view.SurfaceHolder);
     method public void setLooping(boolean);
     method public void setNextMediaPlayer(android.media.MediaPlayer);
@@ -30406,9 +30414,9 @@
     method public java.lang.String getLine1Number(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccountHandle getSimCallManager();
+    method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
-    method public boolean hasVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
@@ -34475,6 +34483,7 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public void setIsLongpressEnabled(boolean);
     method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+    method public void setOnStylusButtonPressListener(android.view.GestureDetector.OnStylusButtonPressListener);
   }
 
   public static abstract interface GestureDetector.OnDoubleTapListener {
@@ -34492,7 +34501,11 @@
     method public abstract boolean onSingleTapUp(android.view.MotionEvent);
   }
 
-  public static class GestureDetector.SimpleOnGestureListener implements android.view.GestureDetector.OnDoubleTapListener android.view.GestureDetector.OnGestureListener {
+  public static abstract interface GestureDetector.OnStylusButtonPressListener {
+    method public abstract boolean onStylusButtonPress(android.view.MotionEvent);
+  }
+
+  public static class GestureDetector.SimpleOnGestureListener implements android.view.GestureDetector.OnDoubleTapListener android.view.GestureDetector.OnGestureListener android.view.GestureDetector.OnStylusButtonPressListener {
     ctor public GestureDetector.SimpleOnGestureListener();
     method public boolean onDoubleTap(android.view.MotionEvent);
     method public boolean onDoubleTapEvent(android.view.MotionEvent);
@@ -34503,6 +34516,7 @@
     method public void onShowPress(android.view.MotionEvent);
     method public boolean onSingleTapConfirmed(android.view.MotionEvent);
     method public boolean onSingleTapUp(android.view.MotionEvent);
+    method public boolean onStylusButtonPress(android.view.MotionEvent);
   }
 
   public class Gravity {
diff --git a/api/system-current.txt b/api/system-current.txt
index 611b9ae..b9362ae 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -16776,6 +16776,11 @@
     ctor public MediaCryptoException(java.lang.String);
   }
 
+  public abstract interface MediaDataSource implements java.io.Closeable {
+    method public abstract long getSize();
+    method public abstract int readAt(long, byte[], int);
+  }
+
   public class MediaDescription implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.CharSequence getDescription();
@@ -16912,6 +16917,7 @@
     method public final void release();
     method public void seekTo(long, int);
     method public void selectTrack(int);
+    method public final void setDataSource(android.media.MediaDataSource) throws java.io.IOException, java.lang.IllegalArgumentException;
     method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
     method public final void setDataSource(java.lang.String) throws java.io.IOException;
@@ -17091,6 +17097,7 @@
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.lang.IllegalArgumentException;
     method public void setDataSource(java.io.FileDescriptor) throws java.lang.IllegalArgumentException;
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
+    method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException;
     field public static final int METADATA_KEY_ALBUM = 1; // 0x1
     field public static final int METADATA_KEY_ALBUMARTIST = 13; // 0xd
     field public static final int METADATA_KEY_ARTIST = 2; // 0x2
@@ -17175,6 +17182,7 @@
     method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDisplay(android.view.SurfaceHolder);
     method public void setLooping(boolean);
     method public void setNextMediaPlayer(android.media.MediaPlayer);
@@ -32524,9 +32532,9 @@
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
     method public java.util.List<android.telecom.PhoneAccountHandle> getRegisteredConnectionManagers();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
+    method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
-    method public boolean hasVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isRinging();
     method public boolean isTtySupported();
@@ -36643,6 +36651,7 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public void setIsLongpressEnabled(boolean);
     method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+    method public void setOnStylusButtonPressListener(android.view.GestureDetector.OnStylusButtonPressListener);
   }
 
   public static abstract interface GestureDetector.OnDoubleTapListener {
@@ -36660,7 +36669,11 @@
     method public abstract boolean onSingleTapUp(android.view.MotionEvent);
   }
 
-  public static class GestureDetector.SimpleOnGestureListener implements android.view.GestureDetector.OnDoubleTapListener android.view.GestureDetector.OnGestureListener {
+  public static abstract interface GestureDetector.OnStylusButtonPressListener {
+    method public abstract boolean onStylusButtonPress(android.view.MotionEvent);
+  }
+
+  public static class GestureDetector.SimpleOnGestureListener implements android.view.GestureDetector.OnDoubleTapListener android.view.GestureDetector.OnGestureListener android.view.GestureDetector.OnStylusButtonPressListener {
     ctor public GestureDetector.SimpleOnGestureListener();
     method public boolean onDoubleTap(android.view.MotionEvent);
     method public boolean onDoubleTapEvent(android.view.MotionEvent);
@@ -36671,6 +36684,7 @@
     method public void onShowPress(android.view.MotionEvent);
     method public boolean onSingleTapConfirmed(android.view.MotionEvent);
     method public boolean onSingleTapUp(android.view.MotionEvent);
+    method public boolean onStylusButtonPress(android.view.MotionEvent);
   }
 
   public class Gravity {
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index ea53c0d..ab8a8b6 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -192,6 +192,8 @@
     public static final int KM_ERROR_SECURE_HW_BUSY = -48;
     public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49;
     public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50;
+    public static final int KM_ERROR_MISSING_NONCE = -51;
+    public static final int KM_ERROR_INVALID_NONCE = -52;
     public static final int KM_ERROR_UNIMPLEMENTED = -100;
     public static final int KM_ERROR_VERSION_MISMATCH = -101;
     public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -231,6 +233,8 @@
         sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag");
         sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed");
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field");
+        sErrorCodeToString.put(KM_ERROR_MISSING_NONCE, "Required IV missing");
+        sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 2351548..b8544c6 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -149,12 +149,30 @@
     }
 
     /**
+     * The listener that is used to notify when a stylus button press occurs.
+     */
+    public interface OnStylusButtonPressListener {
+        /**
+         * Notified when a stylus button press occurs. This is when the stylus
+         * is touching the screen and the {@value MotionEvent#BUTTON_SECONDARY}
+         * is pressed.
+         *
+         * @param e The motion event that occurred during the stylus button
+         *            press.
+         * @return true if the event is consumed, else false
+         */
+        boolean onStylusButtonPress(MotionEvent e);
+    }
+
+    /**
      * A convenience class to extend when you only want to listen for a subset
      * of all the gestures. This implements all methods in the
-     * {@link OnGestureListener} and {@link OnDoubleTapListener} but does
-     * nothing and return {@code false} for all applicable methods.
+     * {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnStylusButtonPressListener}
+     * but does nothing and return {@code false} for all applicable methods.
      */
-    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
+    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
+            OnStylusButtonPressListener {
+
         public boolean onSingleTapUp(MotionEvent e) {
             return false;
         }
@@ -190,6 +208,10 @@
         public boolean onSingleTapConfirmed(MotionEvent e) {
             return false;
         }
+
+        public boolean onStylusButtonPress(MotionEvent e) {
+            return false;
+        }
     }
 
     private int mTouchSlopSquare;
@@ -211,10 +233,12 @@
     private final Handler mHandler;
     private final OnGestureListener mListener;
     private OnDoubleTapListener mDoubleTapListener;
+    private OnStylusButtonPressListener mStylusButtonListener;
 
     private boolean mStillDown;
     private boolean mDeferConfirmSingleTap;
     private boolean mInLongPress;
+    private boolean mInStylusButtonPress;
     private boolean mAlwaysInTapRegion;
     private boolean mAlwaysInBiggerTapRegion;
 
@@ -358,6 +382,9 @@
         if (listener instanceof OnDoubleTapListener) {
             setOnDoubleTapListener((OnDoubleTapListener) listener);
         }
+        if (listener instanceof OnStylusButtonPressListener) {
+            setOnStylusButtonPressListener((OnStylusButtonPressListener) listener);
+        }
         init(context);
     }
     
@@ -420,6 +447,19 @@
     }
 
     /**
+     * Sets the listener which will be called for stylus button related
+     * gestures.
+     *
+     * @param onStylusButtonPressListener the listener invoked for all the
+     *            callbacks, or null to stop listening for stylus button
+     *            gestures.
+     */
+    public void setOnStylusButtonPressListener(
+            OnStylusButtonPressListener onStylusButtonPressListener) {
+        mStylusButtonListener = onStylusButtonPressListener;
+    }
+
+    /**
      * Set whether longpress is enabled, if this is enabled when a user
      * presses and holds down you get a longpress event and nothing further.
      * If it's disabled the user can press and hold down and then later
@@ -512,7 +552,18 @@
             break;
 
         case MotionEvent.ACTION_DOWN:
-            if (mDoubleTapListener != null) {
+            if (mStylusButtonListener != null
+                    && ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+                    && (ev.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
+                if (mStylusButtonListener.onStylusButtonPress(ev)) {
+                    mInStylusButtonPress = true;
+                    handled = true;
+                    mHandler.removeMessages(LONG_PRESS);
+                    mHandler.removeMessages(TAP);
+                }
+            }
+
+            if (mDoubleTapListener != null && !mInStylusButtonPress) {
                 boolean hadTapMessage = mHandler.hasMessages(TAP);
                 if (hadTapMessage) mHandler.removeMessages(TAP);
                 if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
@@ -540,8 +591,8 @@
             mStillDown = true;
             mInLongPress = false;
             mDeferConfirmSingleTap = false;
-            
-            if (mIsLongpressEnabled) {
+
+            if (mIsLongpressEnabled && !mInStylusButtonPress) {
                 mHandler.removeMessages(LONG_PRESS);
                 mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
                         + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
@@ -551,7 +602,17 @@
             break;
 
         case MotionEvent.ACTION_MOVE:
-            if (mInLongPress) {
+            if (mStylusButtonListener != null && !mInStylusButtonPress && !mInLongPress
+                    && ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+                    && (ev.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
+                if (mStylusButtonListener.onStylusButtonPress(ev)) {
+                    mInStylusButtonPress = true;
+                    handled = true;
+                    mHandler.removeMessages(LONG_PRESS);
+                    mHandler.removeMessages(TAP);
+                }
+            }
+            if (mInLongPress || mInStylusButtonPress) {
                 break;
             }
             final float scrollX = mLastFocusX - focusX;
@@ -591,6 +652,9 @@
             } else if (mInLongPress) {
                 mHandler.removeMessages(TAP);
                 mInLongPress = false;
+            } else if (mInStylusButtonPress) {
+                mHandler.removeMessages(TAP);
+                mInStylusButtonPress = false;
             } else if (mAlwaysInTapRegion) {
                 handled = mListener.onSingleTapUp(ev);
                 if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
@@ -649,9 +713,8 @@
         mAlwaysInTapRegion = false;
         mAlwaysInBiggerTapRegion = false;
         mDeferConfirmSingleTap = false;
-        if (mInLongPress) {
-            mInLongPress = false;
-        }
+        mInLongPress = false;
+        mInStylusButtonPress = false;
     }
 
     private void cancelTaps() {
@@ -662,9 +725,8 @@
         mAlwaysInTapRegion = false;
         mAlwaysInBiggerTapRegion = false;
         mDeferConfirmSingleTap = false;
-        if (mInLongPress) {
-            mInLongPress = false;
-        }
+        mInLongPress = false;
+        mInStylusButtonPress = false;
     }
 
     private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e7b6238..c9d9a8c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3116,6 +3116,25 @@
         }
     }
 
+    private boolean performStylusButtonPressAction(MotionEvent ev) {
+        if (ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+                && ev.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
+                && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) {
+            final View child = getChildAt(mMotionPosition - mFirstPosition);
+            if (child != null) {
+                final int longPressPosition = mMotionPosition;
+                final long longPressId = mAdapter.getItemId(mMotionPosition);
+                if (performLongPress(child, longPressPosition, longPressId)) {
+                    mTouchMode = TOUCH_MODE_REST;
+                    setPressed(false);
+                    child.setPressed(false);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     boolean performLongPress(final View child,
             final int longPressPosition, final long longPressId) {
         // CHOICE_MODE_MULTIPLE_MODAL takes over long press.
@@ -3757,8 +3776,8 @@
         }
 
         if (mTouchMode == TOUCH_MODE_DOWN && mMotionPosition != INVALID_POSITION
-                && performButtonActionOnTouchDown(ev)) {
-            removeCallbacks(mPendingCheckForTap);
+                && (performButtonActionOnTouchDown(ev) || performStylusButtonPressAction(ev))) {
+                removeCallbacks(mPendingCheckForTap);
         }
     }
 
@@ -3800,6 +3819,11 @@
                     mTouchMode = TOUCH_MODE_DONE_WAITING;
                     updateSelectorState();
                 } else if (motionView != null) {
+                    if (performStylusButtonPressAction(ev)) {
+                        removeCallbacks(mPendingCheckForTap);
+                        removeCallbacks(mPendingCheckForLongPress);
+                    }
+
                     // Still within bounds, update the hotspot.
                     final float[] point = mTmpPoint;
                     point[0] = x;
diff --git a/docs/html/tools/help/hprof-conv.jd b/docs/html/tools/help/hprof-conv.jd
index f96def2..982f337 100644
--- a/docs/html/tools/help/hprof-conv.jd
+++ b/docs/html/tools/help/hprof-conv.jd
@@ -8,9 +8,13 @@
 generated by the Android SDK tools to a standard format so you
 can view the file in a profiling tool of your choice. </p>
 
-<pre> hprof-conv &lt;infile&gt; &lt;outfile&gt;</pre>
+<pre> hprof-conv [-z] &lt;infile&gt; &lt;outfile&gt;</pre>
 
 <p>
 You can use "-" for <code>&lt;infile&gt;</code> or <code>&lt;outfile&gt;</code>
 to specify stdin or stdout.
 </p>
+
+<p>
+You can use "-z" to filter out zygote allocations shared by all applications.
+</p>
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 7bc6378..37e00b2 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -547,18 +547,12 @@
             if (mIvRequired) {
                 // IV is needed
                 if ((mIv == null) && (mEncrypting)) {
-                    // TODO: Switch to keymaster-generated IV code below once keymaster supports
-                    // that.
-                    // IV is needed but was not provided by the caller -- generate an IV.
-                    mIv = new byte[mBlockSizeBytes];
-                    SecureRandom rng = (mRng != null) ? mRng : new SecureRandom();
-                    rng.nextBytes(mIv);
-//                    // IV was not provided by the caller and thus will be generated by keymaster.
-//                    // Mix in some additional entropy from the provided SecureRandom.
-//                    if (mRng != null) {
-//                        mAdditionalEntropyForBegin = new byte[mBlockSizeBytes];
-//                        mRng.nextBytes(mAdditionalEntropyForBegin);
-//                    }
+                    // IV was not provided by the caller and thus will be generated by keymaster.
+                    // Mix in some additional entropy from the provided SecureRandom.
+                    if (mRng != null) {
+                        mAdditionalEntropyForBegin = new byte[mBlockSizeBytes];
+                        mRng.nextBytes(mAdditionalEntropyForBegin);
+                    }
                 }
             }
         }
diff --git a/media/java/android/media/DataSource.java b/media/java/android/media/DataSource.java
deleted file mode 100644
index 347bd5f..0000000
--- a/media/java/android/media/DataSource.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012 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.media;
-
-import java.io.Closeable;
-
-/**
- * An abstraction for a media data source, e.g. a file or an http stream
- * {@hide}
- */
-public interface DataSource extends Closeable {
-    /**
-     * Reads data from the data source at the requested position
-     *
-     * @param offset where in the source to read
-     * @param buffer the buffer to read the data into
-     * @param size how many bytes to read
-     * @return the number of bytes read, or -1 if there was an error
-     */
-    public int readAt(long offset, byte[] buffer, int size);
-
-    /**
-     * Gets the size of the data source.
-     *
-     * @return size of data source, or -1 if the length is unknown
-     */
-    public long getSize();
-}
diff --git a/media/java/android/media/MediaDataSource.java b/media/java/android/media/MediaDataSource.java
new file mode 100644
index 0000000..246c0ef
--- /dev/null
+++ b/media/java/android/media/MediaDataSource.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 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.media;
+
+import java.io.Closeable;
+
+/**
+ * For supplying media data to the framework. Implement this if your app has
+ * special requirements for the way media data is obtained.
+ *
+ * <p class="note">Methods of this interface may be called on multiple different
+ * threads. There will be a thread synchronization point between each call to ensure that
+ * modifications to the state of your MediaDataSource are visible to future calls. This means
+ * you don't need to do your own synchronization unless you're modifying the
+ * MediaDataSource from another thread while it's being used by the framework.</p>
+ */
+public interface MediaDataSource extends Closeable {
+    /**
+     * Called to request data from the given position.
+     *
+     * Implementations should should write up to {@code size} bytes into
+     * {@code buffer}, and return the number of bytes written.
+     *
+     * Return {@code 0} to indicate that {@code position} is at, or beyond, the
+     * end of the source.
+     *
+     * Return {@code -1} to indicate that a fatal error occurred. The failed
+     * read will not be retried, so transient errors should be handled
+     * internally.
+     *
+     * Throwing an exception from this method will have the same effect as
+     * returning {@code -1}.
+     *
+     * @param position the position in the data source to read from.
+     * @param buffer the buffer to read the data into.
+     * @param size the number of bytes to read.
+     * @return the number of bytes read, or -1 if there was an error.
+     */
+    public int readAt(long position, byte[] buffer, int size);
+
+    /**
+     * Called to get the size of the data source.
+     *
+     * @return the size of data source in bytes, or -1 if the size is unknown.
+     */
+    public long getSize();
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index b23b540..b4acbc0 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -66,10 +66,11 @@
     }
 
     /**
-     * Sets the DataSource object to be used as the data source for this extractor
-     * {@hide}
+     * Sets the data source (MediaDataSource) to use.
+     *
+     * @param dataSource the MediaDataSource for the media you want to extract from
      */
-    public native final void setDataSource(DataSource source) throws IOException;
+    public native final void setDataSource(MediaDataSource dataSource) throws IllegalArgumentException, IOException;
 
     /**
      * Sets the data source as a content Uri.
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 9aa8003..a3ff080 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -203,7 +203,20 @@
     }
 
     /**
-     * Call this method after setDataSource(). This method retrieves the 
+     * Sets the data source (MediaDataSource) to use.
+     *
+     * @param dataSource the MediaDataSource for the media you want to play
+     */
+    public void setDataSource(MediaDataSource dataSource)
+            throws IllegalArgumentException {
+        _setDataSource(dataSource);
+    }
+
+    private native void _setDataSource(MediaDataSource dataSource)
+          throws IllegalArgumentException;
+
+    /**
+     * Call this method after setDataSource(). This method retrieves the
      * meta data value associated with the keyCode.
      * 
      * The keyCode currently supported is listed below as METADATA_XXX
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 83954ae..cb80bc4 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -181,7 +181,8 @@
  *         {@link #setDataSource(FileDescriptor)}, or
  *         {@link #setDataSource(String)}, or
  *         {@link #setDataSource(Context, Uri)}, or
- *         {@link #setDataSource(FileDescriptor, long, long)} transfers a
+ *         {@link #setDataSource(FileDescriptor, long, long)}, or
+ *         {@link #setDataSource(MediaDataSource)} transfers a
  *         MediaPlayer object in the <em>Idle</em> state to the
  *         <em>Initialized</em> state.
  *         <ul>
@@ -1127,6 +1128,20 @@
             throws IOException, IllegalArgumentException, IllegalStateException;
 
     /**
+     * Sets the data source (MediaDataSource) to use.
+     *
+     * @param dataSource the MediaDataSource for the media you want to play
+     * @throws IllegalStateException if it is called in an invalid state
+     */
+    public void setDataSource(MediaDataSource dataSource)
+            throws IllegalArgumentException, IllegalStateException {
+        _setDataSource(dataSource);
+    }
+
+    private native void _setDataSource(MediaDataSource dataSource)
+          throws IllegalArgumentException, IllegalStateException;
+
+    /**
      * Prepares the player for playback, synchronously.
      *
      * After setting the datasource and the display surface, you need to either
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 66d055a..c8464c7 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -7,6 +7,7 @@
     android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
     android_media_MediaCodecList.cpp \
+    android_media_MediaDataSource.cpp \
     android_media_MediaDrm.cpp \
     android_media_MediaExtractor.cpp \
     android_media_MediaHTTPConnection.cpp \
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
new file mode 100644
index 0000000..1e6d2af
--- /dev/null
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2015, 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "JMediaDataSource-JNI"
+#include <utils/Log.h>
+
+#include "android_media_MediaDataSource.h"
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <binder/MemoryDealer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+
+JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source)
+    : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) {
+    mMediaDataSourceObj = env->NewGlobalRef(source);
+    CHECK(mMediaDataSourceObj != NULL);
+
+    ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj));
+    CHECK(mediaDataSourceClass.get() != NULL);
+
+    mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BI)I");
+    CHECK(mReadMethod != NULL);
+    mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J");
+    CHECK(mGetSizeMethod != NULL);
+    mCloseMethod = env->GetMethodID(mediaDataSourceClass.get(), "close", "()V");
+    CHECK(mCloseMethod != NULL);
+
+    ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize));
+    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
+    CHECK(mByteArrayObj != NULL);
+
+    sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "JMediaDataSource");
+    mMemory = memoryDealer->allocate(kBufferSize);
+    if (mMemory == NULL) {
+        ALOGE("Failed to allocate memory!");
+    }
+}
+
+JMediaDataSource::~JMediaDataSource() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mMediaDataSourceObj);
+    env->DeleteGlobalRef(mByteArrayObj);
+}
+
+sp<IMemory> JMediaDataSource::getIMemory() {
+    Mutex::Autolock lock(mLock);
+    return mMemory;
+}
+
+ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) {
+    Mutex::Autolock lock(mLock);
+
+    if (mJavaObjStatus != OK || mMemory == NULL) {
+        return -1;
+    }
+    if (size > kBufferSize) {
+        size = kBufferSize;
+    }
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod,
+                                      (jlong)offset, mByteArrayObj, (jint)size);
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred in readAt()");
+        LOGW_EX(env);
+        env->ExceptionClear();
+        mJavaObjStatus = UNKNOWN_ERROR;
+        return -1;
+    }
+    if (numread < 0) {
+        ALOGW("An error occurred in readAt()");
+        mJavaObjStatus = UNKNOWN_ERROR;
+        return -1;
+    }
+    if ((size_t)numread > size) {
+        ALOGE("readAt read too many bytes.");
+        mJavaObjStatus = UNKNOWN_ERROR;
+        return -1;
+    }
+
+    ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread);
+    env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer());
+    return numread;
+}
+
+status_t JMediaDataSource::getSize(off64_t* size) {
+    Mutex::Autolock lock(mLock);
+
+    if (mJavaObjStatus != OK) {
+        return UNKNOWN_ERROR;
+    }
+    if (mSizeIsCached) {
+        return mCachedSize;
+    }
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    *size = env->CallLongMethod(mMediaDataSourceObj, mGetSizeMethod);
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred in getSize()");
+        LOGW_EX(env);
+        env->ExceptionClear();
+        // After returning an error, size shouldn't be used by callers.
+        *size = UNKNOWN_ERROR;
+        mJavaObjStatus = UNKNOWN_ERROR;
+        return UNKNOWN_ERROR;
+    }
+
+    // The minimum size should be -1, which indicates unknown size.
+    if (*size < 0) {
+        *size = -1;
+    }
+
+    mCachedSize = *size;
+    mSizeIsCached = true;
+    return OK;
+}
+
+void JMediaDataSource::close() {
+    Mutex::Autolock lock(mLock);
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mMediaDataSourceObj, mCloseMethod);
+    // The closed state is effectively the same as an error state.
+    mJavaObjStatus = UNKNOWN_ERROR;
+}
+
+}  // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
new file mode 100644
index 0000000..2bc237e
--- /dev/null
+++ b/media/jni/android_media_MediaDataSource.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015, 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.
+ */
+
+#ifndef _ANDROID_MEDIA_MEDIADATASOURCE_H_
+#define _ANDROID_MEDIA_MEDIADATASOURCE_H_
+
+#include "jni.h"
+
+#include <media/IDataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+// The native counterpart to a Java android.media.MediaDataSource. It inherits from
+// IDataSource so that it can be accessed remotely.
+//
+// If the java DataSource returns an error or throws an exception it
+// will be considered to be in a broken state, and the only further call this
+// will make is to close().
+class JMediaDataSource : public BnDataSource {
+public:
+    enum {
+        kBufferSize = 64 * 1024,
+    };
+
+    JMediaDataSource(JNIEnv *env, jobject source);
+    virtual ~JMediaDataSource();
+
+    virtual sp<IMemory> getIMemory();
+    virtual ssize_t readAt(off64_t offset, size_t size);
+    virtual status_t getSize(off64_t* size);
+    virtual void close();
+
+private:
+    // Protect all member variables with mLock because this object will be
+    // accessed on different binder worker threads.
+    Mutex mLock;
+
+    // The status of the java DataSource. Set to OK unless an error occurred or
+    // close() was called.
+    status_t mJavaObjStatus;
+    // Only call the java getSize() once so the app can't change the size on us.
+    bool mSizeIsCached;
+    off64_t mCachedSize;
+    sp<IMemory> mMemory;
+
+    jobject mMediaDataSourceObj;
+    jmethodID mReadMethod;
+    jmethodID mGetSizeMethod;
+    jmethodID mCloseMethod;
+    jbyteArray mByteArrayObj;
+
+    DISALLOW_EVIL_CONSTRUCTORS(JMediaDataSource);
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_MEDIADATASOURCE_H_
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index c0795b6..b6b7a80 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -25,6 +25,7 @@
 #include "android_runtime/Log.h"
 #include "jni.h"
 #include "JNIHelp.h"
+#include "android_media_MediaDataSource.h"
 
 #include <media/IMediaHTTPService.h>
 #include <media/hardware/CryptoAPI.h>
@@ -50,74 +51,6 @@
 
 static fields_t gFields;
 
-class JavaDataSourceBridge : public DataSource {
-    jmethodID mReadMethod;
-    jmethodID mGetSizeMethod;
-    jmethodID mCloseMethod;
-    jobject   mDataSource;
- public:
-    JavaDataSourceBridge(JNIEnv *env, jobject source) {
-        mDataSource = env->NewGlobalRef(source);
-
-        jclass datasourceclass = env->GetObjectClass(mDataSource);
-        CHECK(datasourceclass != NULL);
-
-        mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
-        CHECK(mReadMethod != NULL);
-
-        mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
-        CHECK(mGetSizeMethod != NULL);
-
-        mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
-        CHECK(mCloseMethod != NULL);
-    }
-
-    ~JavaDataSourceBridge() {
-        JNIEnv *env = AndroidRuntime::getJNIEnv();
-        env->CallVoidMethod(mDataSource, mCloseMethod);
-        env->DeleteGlobalRef(mDataSource);
-    }
-
-    virtual status_t initCheck() const {
-        return OK;
-    }
-
-    virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
-        JNIEnv *env = AndroidRuntime::getJNIEnv();
-
-        // XXX could optimize this by reusing the same array
-        jbyteArray byteArrayObj = env->NewByteArray(size);
-        env->DeleteLocalRef(env->GetObjectClass(mDataSource));
-        env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
-        ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, (jint)size);
-        env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
-        env->DeleteLocalRef(byteArrayObj);
-        if (env->ExceptionCheck()) {
-            ALOGW("Exception occurred while reading %zu at %lld", size, (long long)offset);
-            LOGW_EX(env);
-            env->ExceptionClear();
-            return -1;
-        }
-        return numread;
-    }
-
-    virtual status_t getSize(off64_t *size) {
-        JNIEnv *env = AndroidRuntime::getJNIEnv();
-
-        CHECK(size != NULL);
-
-        int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
-        if (len < 0) {
-            *size = ERROR_UNSUPPORTED;
-        } else {
-            *size = len;
-        }
-        return OK;
-    }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
 JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
     : mClass(NULL),
       mObject(NULL) {
@@ -777,7 +710,8 @@
         return;
     }
 
-    sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
+    sp<DataSource> bridge =
+        DataSource::CreateFromIDataSource(new JMediaDataSource(env, callbackObj));
     status_t err = extractor->setDataSource(bridge);
 
     if (err != OK) {
@@ -881,7 +815,7 @@
     { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
       (void *)android_media_MediaExtractor_setDataSourceFd },
 
-    { "setDataSource", "(Landroid/media/DataSource;)V",
+    { "setDataSource", "(Landroid/media/MediaDataSource;)V",
       (void *)android_media_MediaExtractor_setDataSourceCallback },
 
     { "getCachedDuration", "()J",
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 7226ef5..393003d 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -134,7 +134,6 @@
 static jint android_media_MediaHTTPConnection_native_readAt(
         JNIEnv *env, jobject thiz, jlong offset, jint size) {
     sp<JMediaHTTPConnection> conn = getObject(env, thiz);
-
     if (size > JMediaHTTPConnection::kBufferSize) {
         size = JMediaHTTPConnection::kBufferSize;
     }
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index c6fa379..59fb6d6 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -30,6 +30,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_media_MediaDataSource.h"
 #include "android_media_Utils.h"
 #include "android_util_Binder.h"
 
@@ -171,6 +172,23 @@
     process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed");
 }
 
+static void android_media_MediaMetadataRetriever_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
+{
+    ALOGV("setDataSourceCallback");
+    MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+    if (retriever == 0) {
+        jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+        return;
+    }
+    if (dataSource == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
+    process_media_retriever_call(env, retriever->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed");
+}
+
 template<typename T>
 static void rotate0(T* dst, const T* src, size_t width, size_t height)
 {
@@ -457,6 +475,7 @@
         },
 
         {"setDataSource",   "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
+        {"_setDataSource",   "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
         {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
         {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
         {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 3e41716..c247220 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -36,6 +36,7 @@
 #include "utils/Errors.h"  // for status_t
 #include "utils/KeyedVector.h"
 #include "utils/String8.h"
+#include "android_media_MediaDataSource.h"
 #include "android_media_Utils.h"
 
 #include "android_os_Parcel.h"
@@ -251,6 +252,23 @@
     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
 }
 
+static void
+android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
+{
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (dataSource == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+    sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
+    process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
+}
+
 static sp<IGraphicBufferProducer>
 getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
     IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
@@ -871,7 +889,8 @@
         (void *)android_media_MediaPlayer_setDataSourceAndHeaders
     },
 
-    {"_setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
+    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
+    {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
     {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index d2ef3d7..a9f03b6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -191,7 +191,8 @@
         cancelIntent.putExtra(EXTRA_CANCEL, mJobId);
         mProgressBuilder.addAction(R.drawable.ic_cab_cancel,
                 getString(android.R.string.cancel), PendingIntent.getService(this, 0,
-                        cancelIntent, PendingIntent.FLAG_ONE_SHOT));
+                        cancelIntent,
+                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT));
 
         // Send an initial progress notification.
         mProgressBuilder.setProgress(0, 0, true); // Indeterminate progress while setting up.
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 60b9cb9..5abbb50 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -720,20 +720,21 @@
     }
 
     /**
-     * Return whether a given phone account has a voicemail number configured.
+     * Return the voicemail number for a given phone account.
      *
-     * @param accountHandle The handle for the account to check for a voicemail number.
-     * @return {@code true} If the given phone account has a voicemail number.
+     * @param accountHandle The handle for the phone account.
+     * @return The voicemail number for the phone account, and {@code null} if one has not been
+     *         configured.
      */
-    public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
+    public String getVoiceMailNumber(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().hasVoiceMailNumber(accountHandle);
+                return getTelecomService().getVoiceMailNumber(accountHandle);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
         }
-        return false;
+        return null;
     }
 
     /**
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index d2030f2..35db97f 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -121,9 +121,9 @@
     boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number);
 
     /**
-     * @see TelecomServiceImpl#hasVoiceMailNumber
+     * @see TelecomServiceImpl#getVoiceMailNumber
      */
-    boolean hasVoiceMailNumber(in PhoneAccountHandle accountHandle);
+    String getVoiceMailNumber(in PhoneAccountHandle accountHandle);
 
     /**
      * @see TelecomServiceImpl#getLine1Number