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 <infile> <outfile></pre>
+<pre> hprof-conv [-z] <infile> <outfile></pre>
<p>
You can use "-" for <code><infile></code> or <code><outfile></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