summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/9.xml23
-rw-r--r--api/current.xml53
-rw-r--r--core/java/android/hardware/Camera.java24
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java1
-rw-r--r--core/java/android/net/http/SslCertificate.java3
-rw-r--r--core/java/android/util/EventLogTags.java1
-rw-r--r--core/java/android/view/View.java12
-rw-r--r--core/java/android/view/ViewRoot.java4
-rw-r--r--core/java/android/webkit/WebSettings.java2
-rw-r--r--core/java/android/webkit/WebViewClient.java1
-rw-r--r--core/java/android/widget/ListView.java1
-rw-r--r--core/java/android/widget/TextView.java127
-rw-r--r--core/jni/android_nfc.h9
-rw-r--r--core/jni/android_nfc_NdefMessage.cpp20
-rw-r--r--core/jni/android_nfc_NdefRecord.cpp8
-rw-r--r--[-rwxr-xr-x]core/res/res/drawable-hdpi/textfield_pressed.9.pngbin1020 -> 591 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_pressed.9.pngbin820 -> 584 bytes
-rw-r--r--docs/html/sdk/index.jd55
-rw-r--r--docs/html/sdk/installing.jd8
-rw-r--r--docs/html/sdk/ndk/index.jd46
-rw-r--r--include/media/IOMX.h9
-rw-r--r--include/media/stagefright/HardwareAPI.h8
-rw-r--r--include/media/stagefright/MPEG4Writer.h1
-rw-r--r--include/media/stagefright/MetaData.h2
-rw-r--r--include/private/media/VideoFrame.h1
-rw-r--r--libs/ui/Region.cpp2
-rw-r--r--media/java/android/media/CamcorderProfile.java18
-rw-r--r--media/java/android/media/CameraProfile.java16
-rw-r--r--media/java/android/media/MediaRecorder.java25
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp59
-rw-r--r--media/libmedia/IOMX.cpp20
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp2
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp20
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h2
-rw-r--r--media/libstagefright/AwesomePlayer.cpp88
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp140
-rw-r--r--media/libstagefright/MPEG4Writer.cpp81
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp6
-rw-r--r--media/libstagefright/colorconversion/SoftwareRenderer.cpp13
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h2
-rw-r--r--media/libstagefright/include/OMX.h3
-rw-r--r--media/libstagefright/include/SoftwareRenderer.h3
-rw-r--r--media/libstagefright/omx/OMX.cpp48
-rw-r--r--services/sensorservice/SensorService.cpp3
-rw-r--r--services/sensorservice/SensorService.h4
-rw-r--r--services/sensorservice/tests/sensorservicetest.cpp14
46 files changed, 703 insertions, 285 deletions
diff --git a/api/9.xml b/api/9.xml
index 3056e47ebfb8..27629b7fb1b9 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -73399,16 +73399,6 @@
visibility="public"
>
</field>
-<field name="CAMERA_ID_DEFAULT"
- type="int"
- transient="false"
- volatile="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<interface name="Camera.AutoFocusCallback"
abstract="true"
@@ -86967,6 +86957,19 @@
<parameter name="listener" type="android.media.MediaRecorder.OnInfoListener">
</parameter>
</method>
+<method name="setOrientationHint"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="degrees" type="int">
+</parameter>
+</method>
<method name="setOutputFile"
return="void"
abstract="false"
diff --git a/api/current.xml b/api/current.xml
index 833fb6bd6603..3b9ab1a0edfc 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -73399,16 +73399,6 @@
visibility="public"
>
</field>
-<field name="CAMERA_ID_DEFAULT"
- type="int"
- transient="false"
- volatile="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</class>
<interface name="Camera.AutoFocusCallback"
abstract="true"
@@ -86967,6 +86957,19 @@
<parameter name="listener" type="android.media.MediaRecorder.OnInfoListener">
</parameter>
</method>
+<method name="setOrientationHint"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="degrees" type="int">
+</parameter>
+</method>
<method name="setOutputFile"
return="void"
abstract="false"
@@ -93860,7 +93863,7 @@
type="android.net.SSLCertificateSocketFactory"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handshakeTimeoutMillis" type="int">
@@ -95960,7 +95963,7 @@
type="android.net.http.SslCertificate"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="issuedTo" type="java.lang.String">
@@ -96027,7 +96030,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -96049,7 +96052,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -172461,7 +172464,7 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="EventLogTags"
@@ -202792,7 +202795,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -203338,7 +203341,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="flag" type="boolean">
@@ -205463,7 +205466,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="view" type="android.webkit.WebView">
@@ -213996,7 +213999,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -411701,7 +411704,7 @@
abstract="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<method name="getLength"
@@ -412190,7 +412193,7 @@
abstract="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<method name="characters"
@@ -412405,7 +412408,7 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="org.xml.sax.DTDHandler">
@@ -412872,7 +412875,7 @@
abstract="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<method name="parse"
@@ -414304,7 +414307,7 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="org.xml.sax.AttributeList">
@@ -415793,7 +415796,7 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<method name="makeParser"
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 275e2eb4a8c8..378189e6fcbe 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -211,8 +211,7 @@ public class Camera {
* blocking the main application UI thread.
*
* @param cameraId the hardware camera to access, between 0 and
- * {@link #getNumberOfCameras()}-1. Use {@link #CAMERA_ID_DEFAULT}
- * to access the default camera.
+ * {@link #getNumberOfCameras()}-1.
* @return a new Camera object, connected, locked and ready for use.
* @throws RuntimeException if connection to the camera service fails (for
* example, if the camera is in use by another process).
@@ -222,18 +221,21 @@ public class Camera {
}
/**
- * The id for the default camera.
- * @see #open(int)
- */
- public static int CAMERA_ID_DEFAULT = 0;
-
- /**
- * Equivalent to Camera.open(Camera.CAMERA_ID_DEFAULT).
- * Creates a new Camera object to access the default camera.
+ * Creates a new Camera object to access the first back-facing camera on the
+ * device. If the device does not have a back-facing camera, this returns
+ * null.
* @see #open(int)
*/
public static Camera open() {
- return new Camera(CAMERA_ID_DEFAULT);
+ int numberOfCameras = getNumberOfCameras();
+ CameraInfo cameraInfo = new CameraInfo();
+ for (int i = 0; i < numberOfCameras; i++) {
+ getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
+ return new Camera(i);
+ }
+ }
+ return null;
}
Camera(int cameraId) {
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index b822b27f98d3..63ac21f7cdb2 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -102,6 +102,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
private final boolean mSecure;
/** @deprecated Use {@link #getDefault(int)} instead. */
+ @Deprecated
public SSLCertificateSocketFactory(int handshakeTimeoutMillis) {
this(handshakeTimeoutMillis, null, true);
}
diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java
index c29926c04be8..30f25a2cd309 100644
--- a/core/java/android/net/http/SslCertificate.java
+++ b/core/java/android/net/http/SslCertificate.java
@@ -112,6 +112,7 @@ public class SslCertificate {
* @param validNotAfter The not-after date from the certificate validity period in ISO 8601 format
* @deprecated Use {@link #SslCertificate(String, String, Date, Date)}
*/
+ @Deprecated
public SslCertificate(
String issuedTo, String issuedBy, String validNotBefore, String validNotAfter) {
this(issuedTo, issuedBy, parseDate(validNotBefore), parseDate(validNotAfter));
@@ -157,6 +158,7 @@ public class SslCertificate {
*
* @deprecated Use {@link #getValidNotBeforeDate()}
*/
+ @Deprecated
public String getValidNotBefore() {
return formatDate(mValidNotBefore);
}
@@ -175,6 +177,7 @@ public class SslCertificate {
*
* @deprecated Use {@link #getValidNotAfterDate()}
*/
+ @Deprecated
public String getValidNotAfter() {
return formatDate(mValidNotAfter);
}
diff --git a/core/java/android/util/EventLogTags.java b/core/java/android/util/EventLogTags.java
index 5cf5332a5622..8c18417286fd 100644
--- a/core/java/android/util/EventLogTags.java
+++ b/core/java/android/util/EventLogTags.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
* @deprecated This class is no longer functional.
* Use {@link android.util.EventLog} instead.
*/
+@Deprecated
public class EventLogTags {
public static class Description {
public final int mTag;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index acda3e184775..65904972d396 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6533,11 +6533,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
- final boolean translucentWindow = attachInfo != null && attachInfo.mTranslucentWindow;
+ final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
if (width <= 0 || height <= 0 ||
// Projected bitmap size in bytes
- (width * height * (opaque && !translucentWindow ? 2 : 4) >
+ (width * height * (opaque && !use32BitCache ? 2 : 4) >
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
destroyDrawingCache();
return;
@@ -6567,7 +6567,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
} else {
// Optimization for translucent windows
// If the window is translucent, use a 32 bits bitmap to benefit from memcpy()
- quality = translucentWindow ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
}
// Try to cleanup memory
@@ -6581,7 +6581,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
} else {
mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap);
}
- if (opaque && translucentWindow) bitmap.setHasAlpha(false);
+ if (opaque && use32BitCache) bitmap.setHasAlpha(false);
} catch (OutOfMemoryError e) {
// If there is not enough memory to create the bitmap cache, just
// ignore the issue as bitmap caches are not required to draw the
@@ -9315,9 +9315,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
int mWindowTop;
/**
- * Indicates whether the window is translucent/transparent
+ * Indicates whether views need to use 32-bit drawing caches
*/
- boolean mTranslucentWindow;
+ boolean mUse32BitDrawingCache;
/**
* For windows that are full-screen but using insets to layout inside
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 9c249ceeab27..c58207ee9999 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -754,7 +754,8 @@ public final class ViewRoot extends Handler implements ViewParent,
// object is not initialized to its backing store, but soon it
// will be (assuming the window is visible).
attachInfo.mSurface = mSurface;
- attachInfo.mTranslucentWindow = PixelFormat.formatHasAlpha(lp.format);
+ attachInfo.mUse32BitDrawingCache = PixelFormat.formatHasAlpha(lp.format) ||
+ lp.format == PixelFormat.RGBX_8888;
attachInfo.mHasWindowFocus = false;
attachInfo.mWindowVisibility = viewVisibility;
attachInfo.mRecomputeGlobalAttributes = false;
@@ -1301,6 +1302,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// Need to make sure we re-evaluate the window attributes next
// time around, to ensure the window has the correct format.
mWindowAttributesChanged = true;
+ requestLayout();
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index da0c61b2dc51..4d70e7cddb78 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1029,6 +1029,7 @@ public class WebSettings {
* @deprecated This method has been deprecated in favor of
* {@link #setPluginState}
*/
+ @Deprecated
public synchronized void setPluginsEnabled(boolean flag) {
setPluginState(PluginState.ON);
}
@@ -1211,6 +1212,7 @@ public class WebSettings {
* @return True if plugins are enabled.
* @deprecated This method has been replaced by {@link #getPluginState}
*/
+ @Deprecated
public synchronized boolean getPluginsEnabled() {
return mPluginState == PluginState.ON;
}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 02c721009b10..1f8eeba9016c 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -89,6 +89,7 @@ public class WebViewClient {
* @deprecated This method is no longer called. When the WebView encounters
* a redirect loop, it will cancel the load.
*/
+ @Deprecated
public void onTooManyRedirects(WebView view, Message cancelMsg,
Message continueMsg) {
cancelMsg.sendToTarget();
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 82b7c4fb1393..e1a1894f9432 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3626,6 +3626,7 @@ public class ListView extends AbsListView {
*
* @deprecated Use {@link #getCheckedItemIds()} instead.
*/
+ @Deprecated
public long[] getCheckItemIds() {
// Use new behavior that correctly handles stable ID mapping.
if (mAdapter != null && mAdapter.hasStableIds()) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b30b6b1d3841..41c973614b82 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3758,7 +3758,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// - ExtractEditText does not call onFocus when it is displayed. Fixing this issue would
// allow to test for hasSelection in onFocusChanged, which would trigger a
// startTextSelectionMode here. TODO
- if (selectionController != null && hasSelection()) {
+ if (this instanceof ExtractEditText && selectionController != null && hasSelection()) {
startTextSelectionMode();
}
@@ -4819,6 +4819,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public void beginBatchEdit() {
+ mInBatchEditControllers = true;
final InputMethodState ims = mInputMethodState;
if (ims != null) {
int nesting = ++ims.mBatchEditNesting;
@@ -4841,6 +4842,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public void endBatchEdit() {
+ mInBatchEditControllers = false;
final InputMethodState ims = mInputMethodState;
if (ims != null) {
int nesting = --ims.mBatchEditNesting;
@@ -6747,10 +6749,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Restore previous selection
Selection.setSelection((Spannable)mText, prevStart, prevEnd);
- if (mSelectionModifierCursorController != null &&
- !mSelectionModifierCursorController.isShowing()) {
+ if (hasSelectionController() && !getSelectionController().isShowing()) {
// If the anchors aren't showing, revive them.
- mSelectionModifierCursorController.show();
+ getSelectionController().show();
} else {
// Tapping inside the selection displays the cut/copy/paste context menu
// as long as the anchors are already showing.
@@ -6761,12 +6762,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Tapping outside stops selection mode, if any
stopTextSelectionMode();
- if (mInsertionPointCursorController != null && mText.length() > 0) {
- mInsertionPointCursorController.show();
+ if (hasInsertionController() && mText.length() > 0) {
+ getInsertionController().show();
}
}
- } else if (hasSelection() && mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.show();
+ } else if (hasSelection() && hasSelectionController()) {
+ getSelectionController().show();
}
}
@@ -6800,11 +6801,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
- if (mInsertionPointCursorController != null) {
- mInsertionPointCursorController.onTouchEvent(event);
+ if (hasInsertionController()) {
+ getInsertionController().onTouchEvent(event);
}
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.onTouchEvent(event);
+ if (hasSelectionController()) {
+ getSelectionController().onTouchEvent(event);
}
// Reset this state; it will be re-set if super.onTouchEvent
@@ -6826,11 +6827,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) {
- if (mInsertionPointCursorController != null) {
- mInsertionPointCursorController.onTouchEvent(event);
+ if (hasInsertionController()) {
+ getInsertionController().onTouchEvent(event);
}
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.onTouchEvent(event);
+ if (hasSelectionController()) {
+ getSelectionController().onTouchEvent(event);
}
boolean handled = false;
@@ -6892,19 +6893,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// TODO Add an extra android:cursorController flag to disable the controller?
- if (windowSupportsHandles && mCursorVisible && mLayout != null) {
- if (mInsertionPointCursorController == null) {
- mInsertionPointCursorController = new InsertionPointCursorController();
- }
- } else {
+ mInsertionControllerEnabled = windowSupportsHandles && mCursorVisible && mLayout != null;
+ mSelectionControllerEnabled = windowSupportsHandles && textCanBeSelected() &&
+ mLayout != null;
+
+ if (!mInsertionControllerEnabled) {
mInsertionPointCursorController = null;
}
- if (windowSupportsHandles && textCanBeSelected() && mLayout != null) {
- if (mSelectionModifierCursorController == null) {
- mSelectionModifierCursorController = new SelectionModifierCursorController();
- }
- } else {
+ if (!mSelectionControllerEnabled) {
// Stop selection mode if the controller becomes unavailable.
stopTextSelectionMode();
mSelectionModifierCursorController = null;
@@ -7535,10 +7532,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case ID_SELECT_ALL:
Selection.setSelection((Spannable) mText, 0, mText.length());
startTextSelectionMode();
+ getSelectionController().show();
return true;
case ID_START_SELECTING_TEXT:
startTextSelectionMode();
+ getSelectionController().show();
return true;
case ID_CUT:
@@ -7648,7 +7647,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private void startTextSelectionMode() {
if (!mIsInTextSelectionMode) {
- if (mSelectionModifierCursorController == null) {
+ if (!hasSelectionController()) {
Log.w(LOG_TAG, "TextView has no selection controller. Action mode cancelled.");
return;
}
@@ -7658,7 +7657,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
selectCurrentWord();
- mSelectionModifierCursorController.show();
mIsInTextSelectionMode = true;
}
}
@@ -7837,6 +7835,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return true;
}
+ if (isInBatchEditMode()) {
+ return false;
+ }
+
final int extendedPaddingTop = getExtendedPaddingTop();
final int extendedPaddingBottom = getExtendedPaddingBottom();
final int compoundPaddingLeft = getCompoundPaddingLeft();
@@ -7876,7 +7878,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mPositionY = y - TextView.this.mScrollY;
if (isPositionVisible()) {
int[] coords = null;
- if (mContainer.isShowing()){
+ if (mContainer.isShowing()) {
coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
mContainer.update(coords[0] + mPositionX, coords[1] + mPositionY,
@@ -8065,6 +8067,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public void show() {
+ if (isInBatchEditMode()) {
+ return;
+ }
+
mIsShowing = true;
updatePosition();
mStartHandle.show();
@@ -8128,6 +8134,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
public void updatePosition() {
+ if (!isShowing()) {
+ return;
+ }
+
final int selectionStart = getSelectionStart();
final int selectionEnd = getSelectionEnd();
@@ -8288,6 +8298,62 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return getOffsetForHorizontal(line, x);
}
+ /**
+ * @return True if this view supports insertion handles.
+ */
+ boolean hasInsertionController() {
+ return mInsertionControllerEnabled;
+ }
+
+ /**
+ * @return True if this view supports selection handles.
+ */
+ boolean hasSelectionController() {
+ return mSelectionControllerEnabled;
+ }
+
+ CursorController getInsertionController() {
+ if (!mInsertionControllerEnabled) {
+ return null;
+ }
+
+ if (mInsertionPointCursorController == null) {
+ mInsertionPointCursorController = new InsertionPointCursorController();
+
+ final ViewTreeObserver observer = getViewTreeObserver();
+ if (observer != null) {
+ observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
+ }
+ }
+
+ return mInsertionPointCursorController;
+ }
+
+ CursorController getSelectionController() {
+ if (!mSelectionControllerEnabled) {
+ return null;
+ }
+
+ if (mSelectionModifierCursorController == null) {
+ mSelectionModifierCursorController = new SelectionModifierCursorController();
+
+ final ViewTreeObserver observer = getViewTreeObserver();
+ if (observer != null) {
+ observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
+ }
+ }
+
+ return mSelectionModifierCursorController;
+ }
+
+ boolean isInBatchEditMode() {
+ final InputMethodState ims = mInputMethodState;
+ if (ims != null) {
+ return ims.mBatchEditNesting > 0;
+ }
+ return mInBatchEditControllers;
+ }
+
@ViewDebug.ExportedProperty
private CharSequence mText;
private CharSequence mTransformed;
@@ -8319,6 +8385,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Cursor Controllers. Null when disabled.
private CursorController mInsertionPointCursorController;
private CursorController mSelectionModifierCursorController;
+ private boolean mInsertionControllerEnabled;
+ private boolean mSelectionControllerEnabled;
+ private boolean mInBatchEditControllers;
private boolean mIsInTextSelectionMode = false;
// These are needed to desambiguate a long click. If the long click comes from ones of these, we
// select from the current cursor position. Otherwise, select from long pressed position.
diff --git a/core/jni/android_nfc.h b/core/jni/android_nfc.h
index df660f2ee3b3..de0ddde1d716 100644
--- a/core/jni/android_nfc.h
+++ b/core/jni/android_nfc.h
@@ -22,8 +22,17 @@
#ifndef __ANDROID_NFC_H__
#define __ANDROID_NFC_H__
+#define LOG_TAG "NdefMessage"
+#include <utils/Log.h>
+
extern "C" {
+#if 0
+ #define TRACE(...) LOG(LOG_DEBUG, "NdefMessage", __VA_ARGS__)
+#else
+ #define TRACE(...)
+#endif
+
typedef struct phFriNfc_NdefRecord {
uint8_t Flags;
uint8_t Tnf;
diff --git a/core/jni/android_nfc_NdefMessage.cpp b/core/jni/android_nfc_NdefMessage.cpp
index eaf989d2f2e1..9beef2a97a5e 100644
--- a/core/jni/android_nfc_NdefMessage.cpp
+++ b/core/jni/android_nfc_NdefMessage.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "NdefMessage"
-
#include <stdlib.h>
#include "jni.h"
@@ -23,8 +21,6 @@
#include "android_nfc.h"
-#include <utils/Log.h>
-
namespace android {
static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
@@ -53,7 +49,7 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
return -1;
/* Get the number of records in the message so we can allocate buffers */
- LOGD("phFriNfc_NdefRecord_GetRecords(NULL)");
+ TRACE("phFriNfc_NdefRecord_GetRecords(NULL)");
status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg,
(uint32_t)raw_msg_size, NULL, NULL, &num_of_records);
@@ -62,9 +58,7 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
LOGE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x", status);
goto end;
}
- LOGD("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x", status);
-
- LOGD("found %d records in message", num_of_records);
+ TRACE("phFriNfc_NdefRecord_GetRecords(NULL) returned 0x%04x, with %d records", status, num_of_records);
is_chunked = (uint8_t*)malloc(num_of_records);
if (is_chunked == NULL)
@@ -74,7 +68,7 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
goto end;
/* Now, actually retrieve records position in message */
- LOGD("phFriNfc_NdefRecord_GetRecords()");
+ TRACE("phFriNfc_NdefRecord_GetRecords()");
status = phFriNfc_NdefRecord_GetRecords((uint8_t *)raw_msg,
(uint32_t)raw_msg_size, records, is_chunked, &num_of_records);
@@ -83,7 +77,7 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
LOGE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x", status);
goto end;
}
- LOGD("phFriNfc_NdefRecord_GetRecords() returned 0x%04x", status);
+ TRACE("phFriNfc_NdefRecord_GetRecords() returned 0x%04x, with %d records", status, num_of_records);
/* Build NDEF records array */
record_cls = e->FindClass("android/nfc/NdefRecord");
@@ -94,13 +88,11 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
ctor = e->GetMethodID(record_cls, "<init>", "(S[B[B[B)V");
- LOGD("NFC_Number of records = %d\n", num_of_records);
-
for (i = 0; i < num_of_records; i++) {
jbyteArray type, id, payload;
jobject new_record;
- LOGD("phFriNfc_NdefRecord_Parse()");
+ TRACE("phFriNfc_NdefRecord_Parse()");
status = phFriNfc_NdefRecord_Parse(&record, records[i]);
@@ -108,7 +100,7 @@ static jint android_nfc_NdefMessage_parseNdefMessage(JNIEnv *e, jobject o,
LOGE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
goto end;
}
- LOGD("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
+ TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
type = e->NewByteArray(record.TypeLength);
if (type == NULL) {
diff --git a/core/jni/android_nfc_NdefRecord.cpp b/core/jni/android_nfc_NdefRecord.cpp
index 0a3a5193fff7..a7a80c8b1b98 100644
--- a/core/jni/android_nfc_NdefRecord.cpp
+++ b/core/jni/android_nfc_NdefRecord.cpp
@@ -54,7 +54,7 @@ static jbyteArray android_nfc_NdefRecord_generate(
if (buf == NULL)
goto end;
- LOGD("phFriNfc_NdefRecord_Generate()");
+ TRACE("phFriNfc_NdefRecord_Generate()");
status = phFriNfc_NdefRecord_Generate(&record, buf, buf_size,
&record_size);
@@ -63,7 +63,7 @@ static jbyteArray android_nfc_NdefRecord_generate(
LOGE("phFriNfc_NdefRecord_Generate() returned 0x%04x", status);
goto end;
}
- LOGD("phFriNfc_NdefRecord_Generate() returned 0x%04x", status);
+ TRACE("phFriNfc_NdefRecord_Generate() returned 0x%04x", status);
result = e->NewByteArray(record_size);
if (result == NULL)
@@ -104,13 +104,13 @@ static jint android_nfc_NdefRecord_parseNdefRecord(JNIEnv *e, jobject o,
goto clean_and_return;
}
- LOGD("phFriNfc_NdefRecord_Parse()");
+ TRACE("phFriNfc_NdefRecord_Parse()");
status = phFriNfc_NdefRecord_Parse(&record, (uint8_t *)raw_record);
if (status) {
LOGE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
goto clean_and_return;
}
- LOGD("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
+ TRACE("phFriNfc_NdefRecord_Parse() returned 0x%04x", status);
/* Set TNF field */
mTnf = e->GetFieldID(record_cls, "mTnf", "S");
diff --git a/core/res/res/drawable-hdpi/textfield_pressed.9.png b/core/res/res/drawable-hdpi/textfield_pressed.9.png
index 296d3daa6c00..6537be05a599 100755..100644
--- a/core/res/res/drawable-hdpi/textfield_pressed.9.png
+++ b/core/res/res/drawable-hdpi/textfield_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_pressed.9.png b/core/res/res/drawable-mdpi/textfield_pressed.9.png
index 6d03e1e3f390..9524fec0791c 100644
--- a/core/res/res/drawable-mdpi/textfield_pressed.9.png
+++ b/core/res/res/drawable-mdpi/textfield_pressed.9.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 2812ae834ae0..3dda5ee9b7ca 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -19,52 +19,15 @@ sdk.linux_checksum=TODO
@jd:body
+<p>Here's an overview of the steps you must follow to set up the Android SDK:</p>
-<h2 id="quickstart">Quick Start</h2>
+<ol>
+ <li>Prepare your development computer and ensure it meets the system requirements.</li>
+ <li>Install the SDK starter package from the table above.</li>
+ <li>Install the ADT Plugin for Eclipse (if you'll be developing in Eclipse).</li>
+ <li>Add Android platforms and other components to your SDK.</li>
+ <li>Explore the contents of the Android SDK (optional).</li>
+</ol>
-<p><strong>1. Prepare your development computer</strong></p>
-
-<p>Read the <a href="{@docRoot}sdk/requirements.html">System Requirements</a>
-document and make sure that your development computer meets the hardware and
-software requirements for the Android SDK. Install any additional software
-needed before downloading the Android SDK. In particular, you may need to
-install the <a href="http://java.sun.com/javase/downloads/index.jsp">JDK</a>
- (version 5 or 6 required) and <a href="http://www.eclipse.org/downloads/">Eclipse</a>
- (version 3.4 or 3.5, needed only if you want develop using the ADT Plugin).
-
-<p><strong>2. Download and install the SDK starter package</strong></p>
-
-<p>Download a starter package from the table above onto your development computer.
-If you're using Windows, we recommend that you download the installer (the {@code .exe} file),
-which will launch a Wizard to guide you through the installation and check your computer for
-required software. Otherwise, download the SDK starter package ({@code .zip} or {@code .tgz})
-appropriate for your system, unpack it to a safe location, then add the location to your PATH
-environment variable. </p>
-
-<p><strong>3. Install the ADT Plugin for Eclipse</strong></p>
-
-<p>If you are developing in Eclipse, add a new remote update site with the URL
-<code>https://dl-ssl.google.com/android/eclipse/</code>. Install the Android
-Development Tools (ADT) Plugin from that site, restart Eclipse, and set the "Android"
-preferences in Eclipse to point to the Android SDK directory (installed in the previous step). For
-detailed instructions to setup Eclipse, see <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin
-for Eclipse</a>.</p>
-
-<p><strong>4. Add Android platforms and other components to your SDK</strong></p>
-
-<p>Launch the <em>Android SDK and AVD Manager</em> by executing {@code SDK Manager.exe} (Windows) or
-{@code android} (Mac/Linux) from the SDK's {@code tools/} directory (if you used the Windows
-installer, this is launched for you when the Wizard is complete). Add some Android platforms
-(such as Android 1.6 and Android 2.3) and other components (such as documentation) to your SDK. If
-you aren't sure what to add, see <a
-href="installing.html#which">Recommended Components</a></p>
-
-<p><strong>Done!</strong></p>
-
-<p>To write your first Android application, see the <a
-href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a> tutorial. Also see <a
-href="{@docRoot}sdk/installing.html#NextSteps">Next
-Steps</a> for other suggestions about how to get started.</p>
-
-<p>For a more detailed guide to installing and setting up the SDK, read <a
+<p>To get started, download the appropriate package from the table above, then read the guide to <a
href="installing.html">Installing the SDK</a>.</p>
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index 5b5c4f492095..2f1918124aaf 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -58,7 +58,7 @@ function toggleDiv(link) {
<ol>
<li><a href="#which">Recommended Components</a></li>
</ol></li>
- <li><a href="#sdkContents">5. Exploring the SDK</a></li>
+ <li><a href="#sdkContents">5. Exploring the SDK (Optional)</a></li>
<li><a href="#NextSteps">Next Steps</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ol>
@@ -112,7 +112,7 @@ RCP version of Eclipse is recommended.</p>
development environment&mdash;it includes only the core SDK Tools, which you can
use to download the rest of the SDK components (such as the latest Android platform).</p>
-<p>You can get the latest version of the SDK starter package from the <a
+<p>If you haven't already, get the latest version of the SDK starter package from the <a
href="{@docRoot}sdk/index.html">SDK download page</a>.</p>
<p>If you downloaded a {@code .zip} or {@code .tgz} package (instead of the SDK installer), unpack
@@ -379,10 +379,10 @@ you with the components you've just installed.</p>
href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a> document. </p>
-<h2 id="sdkContents">Step 5. Exploring the SDK</h2>
+<h2 id="sdkContents">Step 5. Exploring the SDK (Optional)</h2>
<p>Once you've installed the SDK and downloaded the platforms, documentation,
-and add-ons that you need, open the SDK directory and take a look at what's
+and add-ons that you need, we suggest that you open the SDK directory and take a look at what's
inside.</p>
<p>The table below describes the full SDK directory contents, with components
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 11e6642ceb2c..0f3634561401 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -84,34 +84,56 @@ padding: .25em 1em;
<dd>
<ul>
+
+ <li>A new toolchain (based on GCC 4.4.3), which generates better code, and can also now
+be used as a standalone cross-compiler, for people who want to build their stuff with
+<code>./configure &amp;&amp; make</code>. See
+docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
+but the 4.2.1 binaries were removed.</li>
+
+ <li>Support for prebuilt static and shared libraries (docs/PREBUILTS.html), module
+exports and imports to make sharing and reuse of third-party modules much easier
+(docs/IMPORT-MODULE.html explains why).</li>
+
+ <li>A C++ STL implementation (based on STLport) is now provided as a helper module. It
+can be used either as a static or shared library (details and usage exemple under
+sources/android/stlport/README). <strong>Note:</strong> For now, C++ Exceptions and RTTI are still
+not supported.</li>
+
+ <li>Improvements to the <code>cpufeatures</code> helper library to deal with buggy
+kernel that incorrectly report they run on an ARMv7 CPU (while the device really is an ARMv6). We
+recommend developers that use it to simply rebuild their applications to benefit from it, then
+upload to Market.</li>
+
<li>Adds support for native activities, which allows you to write completely native
applications.</li>
<li>Adds an EGL library that lets you create and manage OpenGL ES textures and
services.</li>
- <li>Provides an interface that lets you write a native text-to-speech engine.</li>
-
<li>Adds native support for the following:
<ul>
- <li>the input subsystem (such as the keyboard and touch screen)</li>
+ <li>Input subsystem (such as the keyboard and touch screen)</li>
- <li>the window and surface subsystem.</li>
+ <li>Window and surface subsystem</li>
- <li>audio APIs based on the OpenSL ES standard that support playback and recording
- as well as control over platform audio effects.</li>
+ <li>Audio APIs based on the OpenSL ES standard that support playback and recording
+ as well as control over platform audio effects</li>
- <li>event loop APIs to wait for things such as input and sensor events.</li>
+ <li>Event loop APIs to wait for things such as input and sensor events</li>
- <li>accessing assets packaged in an <code>.apk</code> file.</li>
+ <li>Access to assets packaged in the <code>.apk</code></li>
- <li>accessing sensor data (accelerometer, compass, gyroscope, etc).</li>
-
- <li>provides sample applications, <code>native-plasma</code> and
- <code>native-activity</code>, to demonstrate how to write a native activity.</li>
+ <li>Access to sensor data (accelerometer, compass, gyroscope, etc.)</li>
</ul>
</li>
+
+ <li>New sample applications, <code>native-plasma</code> and
+ <code>native-activity</code>, to demonstrate how to write a native activity.</li>
+
+ <li>Plus many bugfixes and other small improvements; see docs/CHANGES.html for a more
+detailed list of changes.</li>
</ul>
</dd>
</dl>
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 2f61cbe1cabd..f79476677f4b 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -115,7 +115,8 @@ public:
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) = 0;
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) = 0;
// Note: These methods are _not_ virtual, it exists as a wrapper around
// the virtual "createRenderer" method above facilitating extraction
@@ -125,14 +126,16 @@ public:
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight);
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees);
sp<IOMXRenderer> createRendererFromJavaSurface(
JNIEnv *env, jobject javaSurface,
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight);
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees);
};
struct omx_message {
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index 221c6796306f..63f11d19ebec 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -32,6 +32,14 @@ extern android::VideoRenderer *createRenderer(
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
+extern android::VideoRenderer *createRendererWithRotation(
+ const android::sp<android::ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
+
extern android::OMXPluginBase *createOMXPlugin();
#endif // HARDWARE_API_H_
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index bb469e565f7b..7bf07eb11e49 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -154,6 +154,7 @@ private:
bool exceedsFileDurationLimit();
bool isFileStreamable() const;
void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
+ void writeCompositionMatrix(int32_t degrees);
MPEG4Writer(const MPEG4Writer &);
MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index d2bd9f2dd14d..29bfc4aaf588 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -32,6 +32,7 @@ enum {
kKeyMIMEType = 'mime', // cstring
kKeyWidth = 'widt', // int32_t
kKeyHeight = 'heig', // int32_t
+ kKeyRotation = 'rotA', // int32_t (angle in degrees)
kKeyIFramesInterval = 'ifiv', // int32_t
kKeyStride = 'strd', // int32_t
kKeySliceHeight = 'slht', // int32_t
@@ -90,6 +91,7 @@ enum {
// Track authoring progress status
// kKeyTrackTimeStatus is used to track progress in elapsed time
kKeyTrackTimeStatus = 'tktm', // int64_t
+ kKeyRotationDegree = 'rdge', // int32_t (clockwise, in degree)
kKeyNotRealTime = 'ntrt', // bool (int32_t)
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 9c35274bafa6..3aff0c6acaa4 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -120,6 +120,7 @@ public:
uint32_t mDisplayHeight;
uint32_t mSize; // Number of bytes in mData
uint8_t* mData; // Actual binary data
+ int32_t mRotationAngle; // rotation angle, clockwise
};
}; // namespace android
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 12db90885c4b..1994f6a4325f 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -289,7 +289,7 @@ private:
void flushSpan() {
bool merge = false;
if (tail-head == ssize_t(span.size())) {
- Rect const* p = cur;
+ Rect const* p = span.editArray();
Rect const* q = head;
if (p->top == q->bottom) {
merge = true;
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index a27df575749f..4004c7637c1a 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -16,6 +16,9 @@
package android.media;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+
/**
* The CamcorderProfile class is used to retrieve the
* predefined camcorder profile settings for camcorder applications.
@@ -119,12 +122,21 @@ public class CamcorderProfile
public int audioChannels;
/**
- * Returns the camcorder profile for the default camera at the given
- * quality level.
+ * Returns the camcorder profile for the first back-facing camera on the
+ * device at the given quality level. If the device has no back-facing
+ * camera, this returns null.
* @param quality the target quality level for the camcorder profile
*/
public static CamcorderProfile get(int quality) {
- return get(0, quality);
+ int numberOfCameras = Camera.getNumberOfCameras();
+ CameraInfo cameraInfo = new CameraInfo();
+ for (int i = 0; i < numberOfCameras; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
+ return get(i, quality);
+ }
+ }
+ return null;
}
/**
diff --git a/media/java/android/media/CameraProfile.java b/media/java/android/media/CameraProfile.java
index 6a0be08defdd..905e2d2d5de3 100644
--- a/media/java/android/media/CameraProfile.java
+++ b/media/java/android/media/CameraProfile.java
@@ -16,6 +16,9 @@
package android.media;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+
import java.util.Arrays;
import java.util.HashMap;
@@ -46,12 +49,21 @@ public class CameraProfile
/**
* Returns a pre-defined still image capture (jpeg) quality level
* used for the given quality level in the Camera application for
- * the default camera.
+ * the first back-facing camera on the device. If the device has no
+ * back-facing camera, this returns 0.
*
* @param quality The target quality level
*/
public static int getJpegEncodingQualityParameter(int quality) {
- return getJpegEncodingQualityParameter(0, quality);
+ int numberOfCameras = Camera.getNumberOfCameras();
+ CameraInfo cameraInfo = new CameraInfo();
+ for (int i = 0; i < numberOfCameras; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
+ return getJpegEncodingQualityParameter(i, quality);
+ }
+ }
+ return 0;
}
/**
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index b38124ecc401..ecabae8c775f 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -285,6 +285,31 @@ public class MediaRecorder
}
/**
+ * Sets the orientation hint for output video playback.
+ * This method should be called before prepare(). This method will not
+ * trigger the source video frame to rotate during video recording, but to
+ * add a composition matrix containing the rotation angle in the output
+ * video if the output format is OutputFormat.THREE_GPP or
+ * OutputFormat.MPEG_4 so that a video player can choose the proper
+ * orientation for playback. Note that some video players may choose
+ * to ignore the compostion matrix in a video during playback.
+ *
+ * @param degrees the angle to be rotated clockwise in degrees.
+ * The supported angles are 0, 90, 180, and 270 degrees.
+ * @throws IllegalArgumentException if the angle is not supported.
+ *
+ */
+ public void setOrientationHint(int degrees) {
+ if (degrees != 0 &&
+ degrees != 90 &&
+ degrees != 180 &&
+ degrees != 270) {
+ throw new IllegalArgumentException("Unsupported angle: " + degrees);
+ }
+ setParameter(String.format("video-param-rotation-angle-degrees=%d", degrees));
+ }
+
+ /**
* Sets the format of the output file produced during recording. Call this
* after setAudioSource()/setVideoSource() but before prepare().
*
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index efea8020613e..63e9dc867569 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -36,6 +36,7 @@ struct fields_t {
jfieldID context;
jclass bitmapClazz;
jmethodID bitmapConstructor;
+ jmethodID createBitmapMethod;
};
static fields_t fields;
@@ -174,6 +175,41 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
return NULL;
}
+ jobject matrix = NULL;
+ if (videoFrame->mRotationAngle != 0) {
+ LOGD("Create a rotation matrix: %d degrees", videoFrame->mRotationAngle);
+ jclass matrixClazz = env->FindClass("android/graphics/Matrix");
+ if (matrixClazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find android/graphics/Matrix");
+ return NULL;
+ }
+ jmethodID matrixConstructor =
+ env->GetMethodID(matrixClazz, "<init>", "()V");
+ if (matrixConstructor == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Matrix constructor");
+ return NULL;
+ }
+ matrix =
+ env->NewObject(matrixClazz, matrixConstructor);
+ if (matrix == NULL) {
+ LOGE("Could not create a Matrix object");
+ return NULL;
+ }
+
+ LOGV("Rotate the matrix: %d degrees", videoFrame->mRotationAngle);
+ jmethodID setRotateMethod =
+ env->GetMethodID(matrixClazz, "setRotate", "(F)V");
+ if (setRotateMethod == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Matrix setRotate method");
+ return NULL;
+ }
+ env->CallVoidMethod(matrix, setRotateMethod, 1.0 * videoFrame->mRotationAngle);
+ env->DeleteLocalRef(matrixClazz);
+ }
+
// Create a SkBitmap to hold the pixels
SkBitmap *bitmap = new SkBitmap();
if (bitmap == NULL) {
@@ -191,7 +227,19 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
// Since internally SkBitmap uses reference count to manage the reference to
// its pixels, it is important that the pixels (along with SkBitmap) be
// available after creating the Bitmap is returned to Java app.
- return env->NewObject(fields.bitmapClazz, fields.bitmapConstructor, (int) bitmap, true, NULL, -1);
+ jobject jSrcBitmap = env->NewObject(fields.bitmapClazz,
+ fields.bitmapConstructor, (int) bitmap, true, NULL, -1);
+
+ LOGV("Return a new bitmap constructed with the rotation matrix");
+ return env->CallStaticObjectMethod(
+ fields.bitmapClazz, fields.createBitmapMethod,
+ jSrcBitmap, // source Bitmap
+ 0, // x
+ 0, // y
+ videoFrame->mDisplayWidth, // width
+ videoFrame->mDisplayHeight, // height
+ matrix, // transform matrix
+ false); // filter
}
static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz)
@@ -291,6 +339,15 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
jniThrowException(env, "java/lang/RuntimeException", "Can't find Bitmap constructor");
return;
}
+ fields.createBitmapMethod =
+ env->GetStaticMethodID(fields.bitmapClazz, "createBitmap",
+ "(Landroid/graphics/Bitmap;IIIILandroid/graphics/Matrix;Z)"
+ "Landroid/graphics/Bitmap;");
+ if (fields.createBitmapMethod == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Bitmap.createBitmap method");
+ return;
+ }
}
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index f3804b8cfd49..ae6c2bf93785 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -38,11 +38,13 @@ sp<IOMXRenderer> IOMX::createRenderer(
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
return createRenderer(
surface->getISurface(),
componentName, colorFormat, encodedWidth, encodedHeight,
- displayWidth, displayHeight);
+ displayWidth, displayHeight,
+ rotationDegrees);
}
sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
@@ -50,7 +52,8 @@ sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
jclass surfaceClass = env->FindClass("android/view/Surface");
if (surfaceClass == NULL) {
LOGE("Can't find android/view/Surface");
@@ -67,7 +70,8 @@ sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
return createRenderer(
surface, componentName, colorFormat, encodedWidth,
- encodedHeight, displayWidth, displayHeight);
+ encodedHeight, displayWidth, displayHeight,
+ rotationDegrees);
}
class BpOMX : public BpInterface<IOMX> {
@@ -349,7 +353,8 @@ public:
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -360,6 +365,7 @@ public:
data.writeInt32(encodedHeight);
data.writeInt32(displayWidth);
data.writeInt32(displayHeight);
+ data.writeInt32(rotationDegrees);
remote()->transact(CREATE_RENDERER, data, &reply);
@@ -682,11 +688,13 @@ status_t BnOMX::onTransact(
size_t encodedHeight = (size_t)data.readInt32();
size_t displayWidth = (size_t)data.readInt32();
size_t displayHeight = (size_t)data.readInt32();
+ int32_t rotationDegrees = data.readInt32();
sp<IOMXRenderer> renderer =
createRenderer(isurface, componentName, colorFormat,
encodedWidth, encodedHeight,
- displayWidth, displayHeight);
+ displayWidth, displayHeight,
+ rotationDegrees);
reply->writeStrongBinder(renderer->asBinder());
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index ca229fa52ba2..39fce81d6c7e 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -253,6 +253,8 @@ sp<IMemory> MetadataRetrieverClient::captureFrame()
frameCopy->mDisplayWidth = frame->mDisplayWidth;
frameCopy->mDisplayHeight = frame->mDisplayHeight;
frameCopy->mSize = frame->mSize;
+ frameCopy->mRotationAngle = frame->mRotationAngle;
+ LOGV("rotation: %d", frameCopy->mRotationAngle);
frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
memcpy(frameCopy->mData, frame->mData, frame->mSize);
delete frame; // Fix memory leakage
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d37d83d3472e..553648da0358 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -340,6 +340,17 @@ status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
return OK;
}
+// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
+ LOGV("setParamVideoRotation: %d", degrees);
+ if (degrees < 0 || degrees % 90 != 0) {
+ LOGE("Unsupported video rotation angle: %d", degrees);
+ return BAD_VALUE;
+ }
+ mRotationDegrees = degrees % 360;
+ return OK;
+}
+
status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
if (timeUs <= 0) {
@@ -532,6 +543,11 @@ status_t StagefrightRecorder::setParameter(
if (safe_strtoi32(value.string(), &video_bitrate)) {
return setParamVideoEncodingBitRate(video_bitrate);
}
+ } else if (key == "video-param-rotation-angle-degrees") {
+ int32_t degrees;
+ if (safe_strtoi32(value.string(), &degrees)) {
+ return setParamVideoRotation(degrees);
+ }
} else if (key == "video-param-i-frames-interval") {
int32_t seconds;
if (safe_strtoi32(value.string(), &seconds)) {
@@ -1105,6 +1121,9 @@ status_t StagefrightRecorder::startMPEG4Recording() {
if (mTrackEveryTimeDurationUs > 0) {
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
+ if (mRotationDegrees != 0) {
+ meta->setInt32(kKeyRotationDegree, mRotationDegrees);
+ }
writer->setListener(mListener);
mWriter = writer;
return mWriter->start(meta.get());
@@ -1187,6 +1206,7 @@ status_t StagefrightRecorder::reset() {
mMaxFileDurationUs = 0;
mMaxFileSizeBytes = 0;
mTrackEveryTimeDurationUs = 0;
+ mRotationDegrees = 0;
mEncoderProfiles = MediaProfiles::getInstance();
mOutputFd = -1;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index ad0dfa05fda8..e42df2e82108 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -91,6 +91,7 @@ private:
int64_t mMaxFileSizeBytes;
int64_t mMaxFileDurationUs;
int64_t mTrackEveryTimeDurationUs;
+ int32_t mRotationDegrees; // Clockwise
String8 mParams;
int mOutputFd;
@@ -120,6 +121,7 @@ private:
status_t setParamVideoEncoderLevel(int32_t level);
status_t setParamVideoCameraId(int32_t cameraId);
status_t setParamVideoTimeScale(int32_t timeScale);
+ status_t setParamVideoRotation(int32_t degrees);
status_t setParamTrackTimeStatus(int64_t timeDurationUs);
status_t setParamInterleaveDuration(int32_t durationUs);
status_t setParam64BitFileOffset(bool use64BitFileOffset);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 064a00cc0fd6..66eb7ee59fab 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -103,12 +103,14 @@ struct AwesomeLocalRenderer : public AwesomeRenderer {
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight)
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees)
: mTarget(NULL),
mLibHandle(NULL) {
init(previewOnly, componentName,
colorFormat, surface, displayWidth,
- displayHeight, decodedWidth, decodedHeight);
+ displayHeight, decodedWidth, decodedHeight,
+ rotationDegrees);
}
virtual void render(MediaBuffer *buffer) {
@@ -141,7 +143,8 @@ private:
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight);
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
AwesomeLocalRenderer(const AwesomeLocalRenderer &);
AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
@@ -153,7 +156,8 @@ void AwesomeLocalRenderer::init(
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight) {
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees) {
if (!previewOnly) {
// We will stick to the vanilla software-color-converting renderer
// for "previewOnly" mode, to avoid unneccessarily switching overlays
@@ -162,6 +166,14 @@ void AwesomeLocalRenderer::init(
mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
if (mLibHandle) {
+ typedef VideoRenderer *(*CreateRendererWithRotationFunc)(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
+
typedef VideoRenderer *(*CreateRendererFunc)(
const sp<ISurface> &surface,
const char *componentName,
@@ -169,17 +181,36 @@ void AwesomeLocalRenderer::init(
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
- CreateRendererFunc func =
- (CreateRendererFunc)dlsym(
+ CreateRendererWithRotationFunc funcWithRotation =
+ (CreateRendererWithRotationFunc)dlsym(
mLibHandle,
- "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
- "OMX_COLOR_FORMATTYPEjjjj");
+ "_Z26createRendererWithRotationRKN7android2spINS_8"
+ "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
- if (func) {
+ if (funcWithRotation) {
mTarget =
- (*func)(surface, componentName, colorFormat,
- displayWidth, displayHeight,
- decodedWidth, decodedHeight);
+ (*funcWithRotation)(
+ surface, componentName, colorFormat,
+ displayWidth, displayHeight,
+ decodedWidth, decodedHeight,
+ rotationDegrees);
+ } else {
+ if (rotationDegrees != 0) {
+ LOGW("renderer does not support rotation.");
+ }
+
+ CreateRendererFunc func =
+ (CreateRendererFunc)dlsym(
+ mLibHandle,
+ "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+ "OMX_COLOR_FORMATTYPEjjjj");
+
+ if (func) {
+ mTarget =
+ (*func)(surface, componentName, colorFormat,
+ displayWidth, displayHeight,
+ decodedWidth, decodedHeight);
+ }
}
}
}
@@ -187,7 +218,7 @@ void AwesomeLocalRenderer::init(
if (mTarget == NULL) {
mTarget = new SoftwareRenderer(
colorFormat, surface, displayWidth, displayHeight,
- decodedWidth, decodedHeight);
+ decodedWidth, decodedHeight, rotationDegrees);
}
}
@@ -785,6 +816,12 @@ void AwesomePlayer::initRenderer_l() {
CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
+ int32_t rotationDegrees;
+ if (!mVideoTrack->getFormat()->findInt32(
+ kKeyRotation, &rotationDegrees)) {
+ rotationDegrees = 0;
+ }
+
mVideoRenderer.clear();
// Must ensure that mVideoRenderer's destructor is actually executed
@@ -800,7 +837,8 @@ void AwesomePlayer::initRenderer_l() {
mISurface, component,
(OMX_COLOR_FORMATTYPE)format,
decodedWidth, decodedHeight,
- mVideoWidth, mVideoHeight));
+ mVideoWidth, mVideoHeight,
+ rotationDegrees));
} else {
// Other decoders are instantiated locally and as a consequence
// allocate their buffers in local address space.
@@ -810,7 +848,7 @@ void AwesomePlayer::initRenderer_l() {
(OMX_COLOR_FORMATTYPE)format,
mISurface,
mVideoWidth, mVideoHeight,
- decodedWidth, decodedHeight);
+ decodedWidth, decodedHeight, rotationDegrees);
}
}
}
@@ -1625,7 +1663,22 @@ void AwesomePlayer::finishAsyncPrepare_l() {
if (mVideoWidth < 0 || mVideoHeight < 0) {
notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
} else {
- notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+ int32_t rotationDegrees;
+ if (!mVideoTrack->getFormat()->findInt32(
+ kKeyRotation, &rotationDegrees)) {
+ rotationDegrees = 0;
+ }
+
+#if 1
+ if (rotationDegrees == 90 || rotationDegrees == 270) {
+ notifyListener_l(
+ MEDIA_SET_VIDEO_SIZE, mVideoHeight, mVideoWidth);
+ } else
+#endif
+ {
+ notifyListener_l(
+ MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+ }
}
notifyListener_l(MEDIA_PREPARED);
@@ -1757,7 +1810,8 @@ status_t AwesomePlayer::resume() {
state->mVideoWidth,
state->mVideoHeight,
state->mDecodedWidth,
- state->mDecodedHeight);
+ state->mDecodedHeight,
+ 0);
mVideoRendererIsPreview = true;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index f4047087c544..2154f2f5fc69 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -27,11 +27,11 @@
#include <stdlib.h>
#include <string.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include "include/ESDS.h"
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
@@ -579,52 +579,9 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
case FOURCC('t', 'k', 'h', 'd'):
{
- if (chunk_data_size < 4) {
- return ERROR_MALFORMED;
- }
-
- uint8_t version;
- if (mDataSource->readAt(data_offset, &version, 1) < 1) {
- return ERROR_IO;
- }
-
- uint64_t ctime, mtime, duration;
- int32_t id;
- uint32_t width, height;
-
- if (version == 1) {
- if (chunk_data_size != 36 + 60) {
- return ERROR_MALFORMED;
- }
-
- uint8_t buffer[36 + 60];
- if (mDataSource->readAt(
- data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
- return ERROR_IO;
- }
-
- ctime = U64_AT(&buffer[4]);
- mtime = U64_AT(&buffer[12]);
- id = U32_AT(&buffer[20]);
- duration = U64_AT(&buffer[28]);
- width = U32_AT(&buffer[88]);
- height = U32_AT(&buffer[92]);
- } else if (version == 0) {
- if (chunk_data_size != 24 + 60) {
- return ERROR_MALFORMED;
- }
-
- uint8_t buffer[24 + 60];
- if (mDataSource->readAt(
- data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
- return ERROR_IO;
- }
- ctime = U32_AT(&buffer[4]);
- mtime = U32_AT(&buffer[8]);
- id = U32_AT(&buffer[12]);
- duration = U32_AT(&buffer[20]);
- width = U32_AT(&buffer[76]);
- height = U32_AT(&buffer[80]);
+ status_t err;
+ if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
+ return err;
}
*offset += chunk_size;
@@ -1073,6 +1030,89 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return OK;
}
+status_t MPEG4Extractor::parseTrackHeader(
+ off_t data_offset, off_t data_size) {
+ if (data_size < 4) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t version;
+ if (mDataSource->readAt(data_offset, &version, 1) < 1) {
+ return ERROR_IO;
+ }
+
+ size_t dynSize = (version == 1) ? 36 : 24;
+
+ uint8_t buffer[36 + 60];
+
+ if (data_size != (off_t)dynSize + 60) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(
+ data_offset, buffer, data_size) < (ssize_t)data_size) {
+ return ERROR_IO;
+ }
+
+ uint64_t ctime, mtime, duration;
+ int32_t id;
+
+ if (version == 1) {
+ ctime = U64_AT(&buffer[4]);
+ mtime = U64_AT(&buffer[12]);
+ id = U32_AT(&buffer[20]);
+ duration = U64_AT(&buffer[28]);
+ } else if (version == 0) {
+ ctime = U32_AT(&buffer[4]);
+ mtime = U32_AT(&buffer[8]);
+ id = U32_AT(&buffer[12]);
+ duration = U32_AT(&buffer[20]);
+ }
+
+ size_t matrixOffset = dynSize + 16;
+ int32_t a00 = U32_AT(&buffer[matrixOffset]);
+ int32_t a01 = U32_AT(&buffer[matrixOffset + 4]);
+ int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
+ int32_t a10 = U32_AT(&buffer[matrixOffset + 12]);
+ int32_t a11 = U32_AT(&buffer[matrixOffset + 16]);
+ int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
+
+#if 0
+ LOGI("x' = %.2f * x + %.2f * y + %.2f",
+ a00 / 65536.0f, a01 / 65536.0f, dx / 65536.0f);
+ LOGI("y' = %.2f * x + %.2f * y + %.2f",
+ a10 / 65536.0f, a11 / 65536.0f, dy / 65536.0f);
+#endif
+
+ uint32_t rotationDegrees;
+
+ static const int32_t kFixedOne = 0x10000;
+ if (a00 == kFixedOne && a01 == 0 && a10 == 0 && a11 == kFixedOne) {
+ // Identity, no rotation
+ rotationDegrees = 0;
+ } else if (a00 == 0 && a01 == kFixedOne && a10 == -kFixedOne && a11 == 0) {
+ rotationDegrees = 90;
+ } else if (a00 == 0 && a01 == -kFixedOne && a10 == kFixedOne && a11 == 0) {
+ rotationDegrees = 270;
+ } else if (a00 == -kFixedOne && a01 == 0 && a10 == 0 && a11 == -kFixedOne) {
+ rotationDegrees = 180;
+ } else {
+ LOGW("We only support 0,90,180,270 degree rotation matrices");
+ rotationDegrees = 0;
+ }
+
+ if (rotationDegrees != 0) {
+ mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
+ }
+
+#if 0
+ uint32_t width = U32_AT(&buffer[dynSize + 52]);
+ uint32_t height = U32_AT(&buffer[dynSize + 56]);
+#endif
+
+ return OK;
+}
+
status_t MPEG4Extractor::parseMetaData(off_t offset, size_t size) {
if (size < 4) {
return ERROR_MALFORMED;
@@ -1386,7 +1426,7 @@ MPEG4Source::MPEG4Source(
const uint8_t *ptr = (const uint8_t *)data;
CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
// The number of bytes used to encode the length of a NAL unit.
mNALLengthSize = 1 + (ptr[4] & 3);
@@ -1534,7 +1574,7 @@ status_t MPEG4Source::read(
}
uint32_t sampleTime;
- CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
+ CHECK_EQ((status_t)OK, mSampleTable->getMetaDataForSample(
sampleIndex, NULL, NULL, &sampleTime));
if (mode == ReadOptions::SEEK_CLOSEST) {
@@ -1581,7 +1621,7 @@ status_t MPEG4Source::read(
err = mGroup->acquire_buffer(&mBuffer);
if (err != OK) {
- CHECK_EQ(mBuffer, NULL);
+ CHECK(mBuffer == NULL);
return err;
}
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a15c2741352c..cbb160402431 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -202,6 +202,7 @@ private:
// Simple validation on the codec specific data
status_t checkCodecSpecificData() const;
+ int32_t mRotation;
void updateTrackSizeEstimate();
void addOneStscTableEntry(size_t chunkId, size_t sampleId);
@@ -519,6 +520,58 @@ void MPEG4Writer::stopWriterThread() {
pthread_join(mThread, &dummy);
}
+/*
+ * MP4 file standard defines a composition matrix:
+ * | a b u |
+ * | c d v |
+ * | x y w |
+ *
+ * the element in the matrix is stored in the following
+ * order: {a, b, u, c, d, v, x, y, w},
+ * where a, b, c, d, x, and y is in 16.16 format, while
+ * u, v and w is in 2.30 format.
+ */
+void MPEG4Writer::writeCompositionMatrix(int degrees) {
+ LOGV("writeCompositionMatrix");
+ uint32_t a = 0x00010000;
+ uint32_t b = 0;
+ uint32_t c = 0;
+ uint32_t d = 0x00010000;
+ switch (degrees) {
+ case 0:
+ break;
+ case 90:
+ a = 0;
+ b = 0x00010000;
+ c = 0xFFFF0000;
+ d = 0;
+ break;
+ case 180:
+ a = 0xFFFF0000;
+ d = 0xFFFF0000;
+ break;
+ case 270:
+ a = 0;
+ b = 0xFFFF0000;
+ c = 0x00010000;
+ d = 0;
+ break;
+ default:
+ CHECK(!"Should never reach this unknown rotation");
+ break;
+ }
+
+ writeInt32(a); // a
+ writeInt32(b); // b
+ writeInt32(0); // u
+ writeInt32(c); // c
+ writeInt32(d); // d
+ writeInt32(0); // v
+ writeInt32(0); // x
+ writeInt32(0); // y
+ writeInt32(0x40000000); // w
+}
+
status_t MPEG4Writer::stop() {
if (mFile == NULL) {
return OK;
@@ -584,15 +637,7 @@ status_t MPEG4Writer::stop() {
writeInt16(0); // reserved
writeInt32(0); // reserved
writeInt32(0); // reserved
- writeInt32(0x10000); // matrix
- writeInt32(0);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0x10000);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0);
- writeInt32(0x40000000);
+ writeCompositionMatrix(0);
writeInt32(0); // predefined
writeInt32(0); // predefined
writeInt32(0); // predefined
@@ -885,7 +930,8 @@ MPEG4Writer::Track::Track(
mCodecSpecificData(NULL),
mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
- mReachedEOS(false) {
+ mReachedEOS(false),
+ mRotation(0) {
getCodecSpecificDataFromInputFormatIfPossible();
const char *mime;
@@ -1178,6 +1224,11 @@ status_t MPEG4Writer::Track::start(MetaData *params) {
startTimeUs = 0;
}
+ int32_t rotationDegrees;
+ if (!mIsAudio && params && params->findInt32(kKeyRotationDegree, &rotationDegrees)) {
+ mRotation = rotationDegrees;
+ }
+
mIsRealTimeRecording = true;
{
int32_t isNotRealTime;
@@ -2071,15 +2122,7 @@ void MPEG4Writer::Track::writeTrackHeader(
mOwner->writeInt16(mIsAudio ? 0x100 : 0); // volume
mOwner->writeInt16(0); // reserved
- mOwner->writeInt32(0x10000); // matrix
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0x10000);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0);
- mOwner->writeInt32(0x40000000);
+ mOwner->writeCompositionMatrix(mRotation);
if (mIsAudio) {
mOwner->writeInt32(0);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index a800a93f23fc..9b2dec9b389a 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -191,6 +191,11 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
CHECK(meta->findInt32(kKeyWidth, &width));
CHECK(meta->findInt32(kKeyHeight, &height));
+ int32_t rotationAngle;
+ if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+ rotationAngle = 0; // By default, no rotation
+ }
+
VideoFrame *frame = new VideoFrame;
frame->mWidth = width;
frame->mHeight = height;
@@ -198,6 +203,7 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
frame->mDisplayHeight = height;
frame->mSize = width * height * 2;
frame->mData = new uint8_t[frame->mSize];
+ frame->mRotationAngle = rotationAngle;
int32_t srcFormat;
CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index a6dbf6912ee1..86ad85bf3d15 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -30,7 +30,8 @@ SoftwareRenderer::SoftwareRenderer(
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight)
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees)
: mColorFormat(colorFormat),
mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
mISurface(surface),
@@ -56,10 +57,20 @@ SoftwareRenderer::SoftwareRenderer(
CHECK(mMemoryHeap->heapID() >= 0);
CHECK(mConverter.isValid());
+ uint32_t orientation;
+ switch (rotationDegrees) {
+ case 0: orientation = ISurface::BufferHeap::ROT_0; break;
+ case 90: orientation = ISurface::BufferHeap::ROT_90; break;
+ case 180: orientation = ISurface::BufferHeap::ROT_180; break;
+ case 270: orientation = ISurface::BufferHeap::ROT_270; break;
+ default: orientation = ISurface::BufferHeap::ROT_0; break;
+ }
+
ISurface::BufferHeap bufferHeap(
mDisplayWidth, mDisplayHeight,
mDecodedWidth, mDecodedHeight,
PIXEL_FORMAT_RGB_565,
+ orientation, 0,
mMemoryHeap);
status_t err = mISurface->registerBuffers(bufferHeap);
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 1c9cc7e5b3a2..2610b0e2c965 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -71,6 +71,8 @@ private:
static status_t verifyTrack(Track *track);
+ status_t parseTrackHeader(off_t data_offset, off_t data_size);
+
MPEG4Extractor(const MPEG4Extractor &);
MPEG4Extractor &operator=(const MPEG4Extractor &);
};
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index c99da5977784..72ab5aaf389e 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -92,7 +92,8 @@ public:
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight);
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees);
virtual void binderDied(const wp<IBinder> &the_late_who);
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 9eed089ce9d4..25c9df71d9f9 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -33,7 +33,8 @@ public:
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
- size_t decodedWidth, size_t decodedHeight);
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees = 0);
virtual ~SoftwareRenderer();
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index c927da182d57..63af26a6ccb4 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -459,7 +459,8 @@ sp<IOMXRenderer> OMX::createRenderer(
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
- size_t displayWidth, size_t displayHeight) {
+ size_t displayWidth, size_t displayHeight,
+ int32_t rotationDegrees) {
Mutex::Autolock autoLock(mLock);
VideoRenderer *impl = NULL;
@@ -467,6 +468,14 @@ sp<IOMXRenderer> OMX::createRenderer(
void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
if (libHandle) {
+ typedef VideoRenderer *(*CreateRendererWithRotationFunc)(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight,
+ int32_t rotationDegrees);
+
typedef VideoRenderer *(*CreateRendererFunc)(
const sp<ISurface> &surface,
const char *componentName,
@@ -474,22 +483,35 @@ sp<IOMXRenderer> OMX::createRenderer(
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
- CreateRendererFunc func =
- (CreateRendererFunc)dlsym(
+ CreateRendererWithRotationFunc funcWithRotation =
+ (CreateRendererWithRotationFunc)dlsym(
libHandle,
- "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
- "OMX_COLOR_FORMATTYPEjjjj");
-
- if (func) {
- impl = (*func)(surface, componentName, colorFormat,
- displayWidth, displayHeight, encodedWidth, encodedHeight);
-
- if (impl) {
- impl = new SharedVideoRenderer(libHandle, impl);
- libHandle = NULL;
+ "_Z26createRendererWithRotationRKN7android2spINS_8"
+ "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
+
+ if (funcWithRotation) {
+ impl = (*funcWithRotation)(
+ surface, componentName, colorFormat,
+ displayWidth, displayHeight, encodedWidth, encodedHeight,
+ rotationDegrees);
+ } else {
+ CreateRendererFunc func =
+ (CreateRendererFunc)dlsym(
+ libHandle,
+ "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+ "OMX_COLOR_FORMATTYPEjjjj");
+
+ if (func) {
+ impl = (*func)(surface, componentName, colorFormat,
+ displayWidth, displayHeight, encodedWidth, encodedHeight);
}
}
+ if (impl) {
+ impl = new SharedVideoRenderer(libHandle, impl);
+ libHandle = NULL;
+ }
+
if (libHandle) {
dlclose(libHandle);
libHandle = NULL;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index e204e0402aaa..c9ab9922482e 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -175,10 +175,11 @@ status_t SensorService::dump(int fd, const Vector<String16>& args)
for (size_t i=0 ; i<mSensorList.size() ; i++) {
const Sensor& s(mSensorList[i]);
const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
- snprintf(buffer, SIZE, "%s (vendor=%s, handle=%d, last=<%5.1f,%5.1f,%5.1f>)\n",
+ snprintf(buffer, SIZE, "%s (vendor=%s, handle=%d, maxRate=%.2fHz, last=<%5.1f,%5.1f,%5.1f>)\n",
s.getName().string(),
s.getVendor().string(),
s.getHandle(),
+ s.getMinDelay() ? (1000000.0f / s.getMinDelay()) : 0.0f,
e.data[0], e.data[1], e.data[2]);
result.append(buffer);
}
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 9f37799fe7d9..dfb1c0e15c63 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -49,8 +49,8 @@ class SensorService :
{
friend class BinderService<SensorService>;
- static const nsecs_t MINIMUM_EVENTS_PERIOD = 10000000; // 10ms
- static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 200 ms
+ static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
+ static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz
SensorService();
virtual ~SensorService();
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 42bf983fe7fd..aea106224bda 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -27,15 +27,25 @@ int receiver(int fd, int events, void* data)
sp<SensorEventQueue> q((SensorEventQueue*)data);
ssize_t n;
ASensorEvent buffer[8];
+
+ static nsecs_t oldTimeStamp = 0;
+
while ((n = q->read(buffer, 8)) > 0) {
for (int i=0 ; i<n ; i++) {
- if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+ if (buffer[i].type == Sensor::TYPE_GYROSCOPE) {
printf("time=%lld, value=<%5.1f,%5.1f,%5.1f>\n",
buffer[i].timestamp,
buffer[i].acceleration.x,
buffer[i].acceleration.y,
buffer[i].acceleration.z);
}
+
+ if (oldTimeStamp) {
+ float t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
+ printf("%f ms (%f Hz)\n", t*1000, 1.0/t);
+ }
+ oldTimeStamp = buffer[i].timestamp;
+
}
}
if (n<0 && n != -EAGAIN) {
@@ -56,7 +66,7 @@ int main(int argc, char** argv)
sp<SensorEventQueue> q = mgr.createEventQueue();
printf("queue=%p\n", q.get());
- Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
+ Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_GYROSCOPE);
printf("accelerometer=%p (%s)\n",
accelerometer, accelerometer->getName().string());
q->enableSensor(accelerometer);