Merge change 8858
* changes:
resolved conflicts for merge of ac38dfc5 to master
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 12bdead..d8db8b3 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -119,7 +119,8 @@
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
- OMXDecoder *encoder = OMXDecoder::CreateEncoder(&client, enc_meta);
+ OMXDecoder *encoder =
+ OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
encoder->setSource(decoder);
// encoder->setSource(meta, new DummySource(width, height));
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 961942a..7e23574 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -102,6 +102,7 @@
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
+ bool audioOnly = false;
if (argc > 1 && !strcmp(argv[1], "--list")) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -121,6 +122,10 @@
}
return 0;
+ } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
+ audioOnly = true;
+ ++argv;
+ --argc;
}
#if 0
@@ -149,7 +154,11 @@
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
- if (!strncasecmp(mime, "video/", 6)) {
+ if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+ break;
+ }
+
+ if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
break;
}
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 5486920..188e7ff 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
void setPokeLock(int pokey, IBinder lock, String tag);
+ int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
long getScreenOnTime();
void preventScreenOn(boolean prevent);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index bfcf2fc..d5934102 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -114,12 +114,14 @@
private static final int WAKE_BIT_SCREEN_DIM = 4;
private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
+ private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
| WAKE_BIT_CPU_WEAK
| WAKE_BIT_SCREEN_DIM
| WAKE_BIT_SCREEN_BRIGHT
- | WAKE_BIT_KEYBOARD_BRIGHT;
+ | WAKE_BIT_KEYBOARD_BRIGHT
+ | WAKE_BIT_PROXIMITY_SCREEN_OFF;
/**
* Wake lock that ensures that the CPU is running. The screen might
@@ -147,6 +149,16 @@
public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
/**
+ * Wake lock that turns the screen off when the proximity sensor activates.
+ * Since not all devices have proximity sensors, use
+ * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
+ * this wake lock mode is supported.
+ *
+ * {@hide}
+ */
+ public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
+
+ /**
* Normally wake locks don't actually wake the device, they just cause
* it to remain on once it's already on. Think of the video player
* app as the normal behavior. Notifications that pop up and want
@@ -196,6 +208,7 @@
case SCREEN_DIM_WAKE_LOCK:
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
+ case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException();
@@ -365,7 +378,33 @@
} catch (RemoteException e) {
}
}
-
+
+ /**
+ * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
+ * that are supported on the device.
+ * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
+ * is supported:
+ *
+ * {@samplecode
+ * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ * int supportedFlags = pm.getSupportedWakeLockFlags();
+ * boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
+ * == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
+ * }
+ *
+ * @return the set of supported WakeLock flags.
+ *
+ * {@hide}
+ */
+ public int getSupportedWakeLockFlags()
+ {
+ try {
+ return mService.getSupportedWakeLockFlags();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
private PowerManager()
{
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 19df87f..358fc9e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -351,6 +351,9 @@
VelocityTracker mVelocityTracker;
private int mMaximumFling;
+ // use this flag to control whether enabling the new double tap zoom
+ static final boolean ENABLE_DOUBLETAP_ZOOM = true;
+
/**
* Touch mode
*/
@@ -370,6 +373,7 @@
private static final int SCROLL_ZOOM_OUT = 11;
private static final int LAST_SCROLL_ZOOM = 11;
// end of touch mode values specific to scale+scroll
+ private static final int TOUCH_DOUBLE_TAP_MODE = 12;
// Whether to forward the touch events to WebCore
private boolean mForwardTouchEvents = false;
@@ -394,6 +398,8 @@
*/
// pre-computed square of ViewConfiguration.getScaledTouchSlop()
private int mTouchSlopSquare;
+ // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
+ private int mDoubleTapSlopSquare;
// pre-computed density adjusted navigation slop
private int mNavSlop;
// This should be ViewConfiguration.getTapTimeout()
@@ -450,6 +456,7 @@
private static final int NEVER_REMEMBER_PASSWORD = 2;
private static final int SWITCH_TO_SHORTPRESS = 3;
private static final int SWITCH_TO_LONGPRESS = 4;
+ private static final int RELEASE_SINGLE_TAP = 5;
private static final int REQUEST_FORM_DATA = 6;
private static final int SWITCH_TO_CLICK = 7;
private static final int RESUME_WEBCORE_UPDATE = 8;
@@ -482,7 +489,7 @@
"NEVER_REMEMBER_PASSWORD", // = 2;
"SWITCH_TO_SHORTPRESS", // = 3;
"SWITCH_TO_LONGPRESS", // = 4;
- "5",
+ "RELEASE_SINGLE_TAP", // = 5;
"REQUEST_FORM_DATA", // = 6;
"SWITCH_TO_CLICK", // = 7;
"RESUME_WEBCORE_UPDATE", // = 8;
@@ -521,6 +528,16 @@
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
+ // while in the zoom overview mode, the page's width is fully fit to the
+ // current window. The page is alive, in another words, you can click to
+ // follow the links. Double tap will toggle between zoom overview mode and
+ // the last zoom scale.
+ boolean mInZoomOverview = false;
+ // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
+ // engadget always have wider mContentWidth no matter what viewport size is.
+ int mZoomOverviewWidth = 0;
+ float mLastScale;
+
// default scale. Depending on the display density.
static int DEFAULT_SCALE_PERCENT;
private float mDefaultScale;
@@ -762,9 +779,11 @@
setLongClickable(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- final int slop = configuration.getScaledTouchSlop();
+ int slop = configuration.getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = slop;
+ slop = configuration.getScaledDoubleTapSlop();
+ mDoubleTapSlopSquare = slop * slop;
final float density = getContext().getResources().getDisplayMetrics().density;
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
@@ -1124,6 +1143,9 @@
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
b.putFloat("scale", mActualScale);
+ if (mInZoomOverview) {
+ b.putFloat("lastScale", mLastScale);
+ }
return true;
}
return false;
@@ -1168,6 +1190,13 @@
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
+ float lastScale = b.getFloat("lastScale", -1.0f);
+ if (lastScale > 0) {
+ mInZoomOverview = true;
+ mLastScale = lastScale;
+ } else {
+ mInZoomOverview = false;
+ }
invalidate();
return true;
}
@@ -3060,6 +3089,11 @@
float y = mLastTouchY + (float) (mScrollY - lp.y);
mWebTextView.fakeTouchEvent(x, y);
}
+ if (mInZoomOverview) {
+ // if in zoom overview mode, call doDoubleTap() to bring it back
+ // to normal mode so that user can enter text.
+ doDoubleTap();
+ }
}
else { // used by plugins
imm.showSoftInput(this, 0);
@@ -3634,7 +3668,9 @@
// update mMinZoomScale if the minimum zoom scale is not fixed
if (!mMinZoomScaleFixed) {
mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
+ / Math.max(ZOOM_OUT_WIDTH, mDrawHistory ? mHistoryPicture
+ .getWidth() : (mZoomOverviewWidth > 0 ?
+ mZoomOverviewWidth : mContentWidth));
}
// we always force, in case our height changed, in which case we still
@@ -3755,6 +3791,15 @@
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
+ } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
+ mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
+ if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
+ mTouchMode = TOUCH_DOUBLE_TAP_MODE;
+ } else {
+ // commit the short press action for the previous tap
+ doShortPress();
+ // continue, mTouchMode should be still TOUCH_INIT_MODE
+ }
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
@@ -3764,7 +3809,8 @@
}
}
// Trigger the link
- if (mTouchMode == TOUCH_INIT_MODE) {
+ if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
@@ -3810,7 +3856,8 @@
if (mTouchMode == TOUCH_SHORTPRESS_MODE
|| mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- } else if (mTouchMode == TOUCH_INIT_MODE) {
+ } else if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
@@ -3836,7 +3883,7 @@
.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
}
WebSettings settings = getSettings();
- if (settings.supportZoom()
+ if (settings.supportZoom() && !mInZoomOverview
&& settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
&& (canZoomScrollOut() ||
@@ -3905,7 +3952,7 @@
mUserScroll = true;
}
- if (!getSettings().getBuiltInZoomControls()) {
+ if (!getSettings().getBuiltInZoomControls() && !mInZoomOverview) {
boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
boolean showMagnify = canZoomScrollOut();
if (mZoomControls != null && (showPlusMinus || showMagnify)) {
@@ -3929,7 +3976,22 @@
case MotionEvent.ACTION_UP: {
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
+ case TOUCH_DOUBLE_TAP_MODE: // double tap
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ doDoubleTap();
+ break;
case TOUCH_INIT_MODE: // tap
+ if (ENABLE_DOUBLETAP_ZOOM) {
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ if (!mPreventDrag) {
+ mPrivateHandler.sendMessageDelayed(
+ mPrivateHandler.obtainMessage(
+ RELEASE_SINGLE_TAP),
+ ViewConfiguration.getDoubleTapTimeout());
+ }
+ break;
+ }
+ // fall through
case TOUCH_SHORTPRESS_START_MODE:
case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -4365,6 +4427,9 @@
mInvInitialZoomScale = 1.0f / oldScale;
mInvFinalZoomScale = 1.0f / mActualScale;
mZoomScale = mActualScale;
+ if (!mInZoomOverview) {
+ mLastScale = scale;
+ }
invalidate();
return true;
} else {
@@ -4470,6 +4535,9 @@
public boolean zoomIn() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
return zoomWithPreview(mActualScale * 1.25f);
}
@@ -4480,6 +4548,9 @@
public boolean zoomOut() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
return zoomWithPreview(mActualScale * 0.8f);
}
@@ -4571,6 +4642,50 @@
}
}
+ private void doDoubleTap() {
+ if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
+ return;
+ }
+ mZoomCenterX = mLastTouchX;
+ mZoomCenterY = mLastTouchY;
+ mInZoomOverview = !mInZoomOverview;
+ if (mInZoomOverview) {
+ float newScale = (float) getViewWidth()
+ / (mZoomOverviewWidth > 0 ? mZoomOverviewWidth
+ : mContentWidth);
+ if (Math.abs(newScale - mActualScale) < 0.01) {
+ mInZoomOverview = !mInZoomOverview;
+ // as it is already full screen, do nothing.
+ return;
+ }
+ if (getSettings().getBuiltInZoomControls()) {
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
+ }
+ } else {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ }
+ zoomWithPreview(newScale);
+ } else {
+ // mLastTouchX and mLastTouchY are the point in the current viewport
+ int contentX = viewToContent((int) mLastTouchX + mScrollX);
+ int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int left = nativeGetBlockLeftEdge(contentX, contentY);
+ if (left != NO_LEFTEDGE) {
+ // add a 5pt padding to the left edge. Re-calculate the zoom
+ // center so that the new scroll x will be on the left edge.
+ mZoomCenterX = left < 5 ? 0 : (left - 5) * mLastScale
+ * mActualScale / (mLastScale - mActualScale);
+ }
+ zoomWithPreview(mLastScale);
+ }
+ }
+
// Called by JNI to handle a touch on a node representing an email address,
// address, or phone number
private void overrideLoading(String url) {
@@ -4791,6 +4906,8 @@
if (mTouchMode == TOUCH_INIT_MODE) {
mTouchMode = TOUCH_SHORTPRESS_START_MODE;
updateSelection();
+ } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
+ mTouchMode = TOUCH_DONE_MODE;
}
break;
}
@@ -4802,6 +4919,13 @@
}
break;
}
+ case RELEASE_SINGLE_TAP: {
+ if (!mPreventDrag) {
+ mTouchMode = TOUCH_DONE_MODE;
+ doShortPress();
+ }
+ break;
+ }
case SWITCH_TO_CLICK:
// The user clicked with the trackball, and did not click a
// second time, so perform the action of a trackball single
@@ -4854,6 +4978,7 @@
break;
case NEW_PICTURE_MSG_ID:
// called for new content
+ final int viewWidth = getViewWidth();
final WebViewCore.DrawData draw =
(WebViewCore.DrawData) msg.obj;
final Point viewSize = draw.mViewPoint;
@@ -4861,16 +4986,12 @@
// use the same logic in sendViewSizeZoom() to make sure
// the mZoomScale has matched the viewSize so that we
// can clear mZoomScale
- if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
+ if (Math.round(viewWidth / mZoomScale) == viewSize.x) {
mZoomScale = 0;
mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
0, 0);
}
}
- if (!mMinZoomScaleFixed) {
- mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
- }
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
// WebCore matches the view size of the picture we just
@@ -4888,6 +5009,25 @@
if (mPictureListener != null) {
mPictureListener.onNewPicture(WebView.this, capturePicture());
}
+ if (mWebViewCore.getSettings().getUseWideViewPort()) {
+ mZoomOverviewWidth = Math.max(draw.mMinPrefWidth,
+ draw.mViewPoint.x);
+ }
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) viewWidth
+ / Math.max(ZOOM_OUT_WIDTH,
+ mZoomOverviewWidth > 0 ? mZoomOverviewWidth
+ : mContentWidth);
+ }
+ if (!mDrawHistory && mInZoomOverview) {
+ // fit the content width to the current view. Ignore
+ // the rounding error case.
+ if (Math.abs((viewWidth * mInvActualScale)
+ - mZoomOverviewWidth) > 1) {
+ zoomWithPreview((float) viewWidth
+ / mZoomOverviewWidth);
+ }
+ }
break;
case WEBCORE_INITIALIZED_MSG_ID:
// nativeCreate sets mNativeClass to a non-zero value
@@ -4916,7 +5056,7 @@
}
}
break;
- case DID_FIRST_LAYOUT_MSG_ID:
+ case DID_FIRST_LAYOUT_MSG_ID: {
if (mNativeClass == 0) {
break;
}
@@ -4943,15 +5083,17 @@
if (width == 0) {
break;
}
+ final WebSettings settings = mWebViewCore.getSettings();
int initialScale = msg.arg1;
int viewportWidth = msg.arg2;
// start a new page with DEFAULT_SCALE zoom scale.
float scale = mDefaultScale;
+ mInZoomOverview = false;
if (mInitialScale > 0) {
scale = mInitialScale / 100.0f;
} else {
- if (initialScale < 0) break;
- if (mWebViewCore.getSettings().getUseWideViewPort()) {
+ if (initialScale == -1) break;
+ if (settings.getUseWideViewPort()) {
// force viewSizeChanged by setting mLastWidthSent
// to 0
mLastWidthSent = 0;
@@ -4961,11 +5103,21 @@
// than the view width, zoom in to fill the view
if (viewportWidth > 0 && viewportWidth < width) {
scale = (float) width / viewportWidth;
+ } else {
+ if (settings.getUseWideViewPort()) {
+ mInZoomOverview = ENABLE_DOUBLETAP_ZOOM;
+ }
}
+ } else if (initialScale < 0) {
+ // this should only happen when
+ // ENABLE_DOUBLETAP_ZOOM is true
+ mInZoomOverview = true;
+ scale = -initialScale / 100.0f;
} else {
scale = initialScale / 100.0f;
}
}
+ mLastScale = scale;
setNewZoomScale(scale, false);
// As we are on a new page, remove the WebTextView. This
// is necessary for page loads driven by webkit, and in
@@ -4973,6 +5125,7 @@
// the WebTextView was visible.
clearTextEntry();
break;
+ }
case MOVE_OUT_OF_PLUGIN:
if (nativePluginEatsNavKey()) {
navHandledKey(msg.arg1, 1, false, 0, true);
@@ -5542,4 +5695,7 @@
private native void nativeUpdateCachedTextfield(String updatedText,
int generation);
private native void nativeUpdatePluginReceivesEvents();
+ // return NO_LEFTEDGE means failure.
+ private static final int NO_LEFTEDGE = -1;
+ private native int nativeGetBlockLeftEdge(int x, int y);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4993fcf..36c5f0c8 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -96,7 +96,8 @@
private boolean mViewportUserScalable = true;
- private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
+ private int mRestoredScale = 0;
+ private int mRestoredScreenWidthScale = 0;
private int mRestoredX = 0;
private int mRestoredY = 0;
@@ -1340,9 +1341,8 @@
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
}
- if (mSettings.getUseWideViewPort()
- && (w < mViewportWidth || mViewportWidth == -1)) {
- int width = mViewportWidth;
+ if (mSettings.getUseWideViewPort()) {
+ int width;
if (mViewportWidth == -1) {
if (mSettings.getLayoutAlgorithm() ==
WebSettings.LayoutAlgorithm.NORMAL) {
@@ -1362,9 +1362,15 @@
*/
width = Math.max(w, nativeGetContentMinPrefWidth());
}
+ } else {
+ width = Math.max(w, mViewportWidth);
}
- nativeSetSize(width, Math.round((float) width * h / w), w, scale,
- w, h);
+ // while in zoom overview mode, the text are wrapped to the screen
+ // width matching mWebView.mLastScale. So that we don't trigger
+ // re-flow while toggling between overview mode and normal mode.
+ nativeSetSize(width, Math.round((float) width * h / w),
+ Math.round(mWebView.mInZoomOverview ? w * scale
+ / mWebView.mLastScale : w), scale, w, h);
} else {
nativeSetSize(w, h, w, scale, w, h);
}
@@ -1409,6 +1415,7 @@
public Region mInvalRegion;
public Point mViewPoint;
public Point mWidthHeight;
+ public int mMinPrefWidth;
}
private void webkitDraw() {
@@ -1424,6 +1431,9 @@
// Send the native view size that was used during the most recent
// layout.
draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
+ if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
+ draw.mMinPrefWidth = nativeGetContentMinPrefWidth();
+ }
if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
Message.obtain(mWebView.mPrivateHandler,
WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
@@ -1734,9 +1744,10 @@
if (mRestoredScale > 0) {
Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
+ WebView.DID_FIRST_LAYOUT_MSG_ID,
+ mRestoredScreenWidthScale > 0 ?
+ -mRestoredScreenWidthScale : mRestoredScale, 0,
scaleLimit).sendToTarget();
- mRestoredScale = 0;
} else {
// if standardLoad is true, use mViewportInitialScale, otherwise
// pass -1 to the WebView to indicate no change of the scale.
@@ -1764,8 +1775,8 @@
}
}
- // reset restored offset
- mRestoredX = mRestoredY = 0;
+ // reset restored offset, scale
+ mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0;
}
}
@@ -1777,6 +1788,17 @@
}
// called by JNI
+ private void restoreScreenWidthScale(int scale) {
+ if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) {
+ return;
+ }
+
+ if (mBrowserFrame.firstLayoutDone() == false) {
+ mRestoredScreenWidthScale = scale;
+ }
+ }
+
+ // called by JNI
private void needTouchEvents(boolean need) {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index f829b08..2b9e448 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -96,6 +96,7 @@
native private int nAllocationCreatePredefSized(int predef, int count);
native private int nAllocationCreateSized(int elem, int count);
native private int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
+ native private int nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
native private void nAllocationUploadToTexture(int alloc, int baseMioLevel);
native private void nAllocationDestroy(int alloc);
@@ -529,7 +530,12 @@
}
public Allocation allocationCreateFromBitmap(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
- int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+ int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+ return new Allocation(id);
+ }
+
+ public Allocation allocationCreateFromBitmapBoxed(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
+ int id = nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
return new Allocation(id);
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 573610c..6f781a0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -291,6 +291,29 @@
return 0;
}
+static int
+nAllocationCreateFromBitmapBoxed(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+
+ RsElementPredefined e = SkBitmapToPredefined(config);
+
+ if (e != RS_ELEMENT_USER_U8) {
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* ptr = bitmap.getPixels();
+ jint id = (jint)rsAllocationCreateFromBitmapBoxed(w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
static void
nAllocationDestroy(JNIEnv *_env, jobject _this, jint a)
@@ -994,6 +1017,7 @@
{"nAllocationCreatePredefSized", "(II)I", (void*)nAllocationCreatePredefSized },
{"nAllocationCreateSized", "(II)I", (void*)nAllocationCreateSized },
{"nAllocationCreateFromBitmap", "(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap },
+{"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmapBoxed },
{"nAllocationUploadToTexture", "(II)V", (void*)nAllocationUploadToTexture },
{"nAllocationDestroy", "(I)V", (void*)nAllocationDestroy },
{"nAllocationData", "(I[I)V", (void*)nAllocationData_i },
diff --git a/include/media/stagefright/OMXDecoder.h b/include/media/stagefright/OMXDecoder.h
index 0859457..e76fd4c 100644
--- a/include/media/stagefright/OMXDecoder.h
+++ b/include/media/stagefright/OMXDecoder.h
@@ -26,6 +26,8 @@
#include <utils/List.h>
#include <utils/threads.h>
+#include <OMX_Video.h>
+
namespace android {
class OMXMediaBuffer;
@@ -35,10 +37,8 @@
public MediaBufferObserver {
public:
static OMXDecoder *Create(
- OMXClient *client, const sp<MetaData> &data);
-
- static OMXDecoder *CreateEncoder(
- OMXClient *client, const sp<MetaData> &data);
+ OMXClient *client, const sp<MetaData> &data,
+ bool createEncoder = false);
virtual ~OMXDecoder();
@@ -68,10 +68,23 @@
};
enum PortStatus {
- kPortStatusActive = 0,
- kPortStatusDisabled = 1,
- kPortStatusShutdown = 2,
- kPortStatusFlushing = 3
+ kPortStatusActive = 0,
+ kPortStatusDisabled = 1,
+ kPortStatusShutdown = 2,
+ kPortStatusFlushing = 3,
+ kPortStatusFlushingToDisabled = 4,
+ kPortStatusFlushingToShutdown = 5,
+ };
+
+ enum Quirks {
+ kWantsRawNALFrames = 1,
+ kDoesntReturnBuffersOnDisable = 2,
+ kDoesntFlushOnExecutingToIdle = 4,
+ kDoesntProperlyFlushAllPortsAtOnce = 8,
+ kRequiresAllocateBufferOnInputPorts = 16,
+ kRequiresAllocateBufferOnOutputPorts = 32,
+ kRequiresLoadedToIdleAfterAllocation = 64,
+ kMeasuresTimeInMilliseconds = 128,
};
OMXClient *mClient;
@@ -79,6 +92,8 @@
IOMX::node_id mNode;
char *mComponentName;
bool mIsMP3;
+ bool mIsAVC;
+ uint32_t mQuirks;
MediaSource *mSource;
sp<MetaData> mOutputFormat;
@@ -116,7 +131,8 @@
bool mReachedEndOfInput;
OMXDecoder(OMXClient *client, IOMX::node_id node,
- const char *mime, const char *codec);
+ const char *mime, const char *codec,
+ uint32_t quirks);
void setPortStatus(OMX_U32 port_index, PortStatus status);
PortStatus getPortStatus(OMX_U32 port_index) const;
@@ -125,7 +141,13 @@
void setAMRFormat();
void setAACFormat();
- void setVideoOutputFormat(OMX_U32 width, OMX_U32 height);
+
+ status_t setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat);
+
+ void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
void setup();
void dumpPortDefinition(OMX_U32 port_index);
@@ -144,6 +166,7 @@
void freeInputBuffer(IOMX::buffer_id buffer);
void freeOutputBuffer(IOMX::buffer_id buffer);
+ void freePortBuffers(OMX_U32 port_index);
void postStart();
void postEmptyBufferDone(IOMX::buffer_id buffer);
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..f7fa81b
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 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 TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+ TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~TIHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<Overlay> mOverlay;
+ Vector<void *> mOverlayAddresses;
+ size_t mIndex;
+
+ TIHardwareRenderer(const TIHardwareRenderer &);
+ TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // TI_HARDWARE_RENDERER_H_
+
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 855ea63..1d14f70 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -146,26 +146,26 @@
};
enum RsBlendSrcFunc {
- RS_BLEND_SRC_ZERO,
- RS_BLEND_SRC_ONE,
- RS_BLEND_SRC_DST_COLOR,
- RS_BLEND_SRC_ONE_MINUS_DST_COLOR,
- RS_BLEND_SRC_SRC_ALPHA,
- RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,
- RS_BLEND_SRC_DST_ALPHA,
- RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,
- RS_BLEND_SRC_SRC_ALPHA_SATURATE
+ RS_BLEND_SRC_ZERO, // 0
+ RS_BLEND_SRC_ONE, // 1
+ RS_BLEND_SRC_DST_COLOR, // 2
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3
+ RS_BLEND_SRC_SRC_ALPHA, // 4
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_SRC_DST_ALPHA, // 6
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8
};
enum RsBlendDstFunc {
- RS_BLEND_DST_ZERO,
- RS_BLEND_DST_ONE,
- RS_BLEND_DST_SRC_COLOR,
- RS_BLEND_DST_ONE_MINUS_SRC_COLOR,
- RS_BLEND_DST_SRC_ALPHA,
- RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
- RS_BLEND_DST_DST_ALPHA,
- RS_BLEND_DST_ONE_MINUS_DST_ALPHA
+ RS_BLEND_DST_ZERO, // 0
+ RS_BLEND_DST_ONE, // 1
+ RS_BLEND_DST_SRC_COLOR, // 2
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3
+ RS_BLEND_DST_SRC_ALPHA, // 4
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_DST_DST_ALPHA, // 6
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7
};
enum RsTexEnvMode {
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 0789301..7a5556e 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -30,11 +30,3 @@
#define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16
#define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
-//typedef int (*rsc_RunScript)(uint32_t launchIndex, const rsc_FunctionTable *);
-
-
-/* EnableCap */
-#define GL_LIGHTING 0x0B50
-
-/* LightName */
-#define GL_LIGHT0 0x4000
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
index 6885251..495fe55 100644
--- a/libs/rs/java/Film/res/raw/filmstrip.c
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -11,29 +11,29 @@
int32_t triangleOffsets[64];
float triangleOffsetsTex[64];
int32_t triangleOffsetsCount;
-} FilmScriptUserEnv;
-*/
+} FilmScriptUserEnv;
+*/
+
+#define POS_TRANSLATE 0
+#define POS_ROTATE 1
+#define POS_FOCUS 2
+
+#define STATE_TRIANGLE_OFFSET_COUNT 0
+#define STATE_LAST_FOCUS 1
+
// The script enviroment has 3 env allocations.
// bank0: (r) The enviroment structure
// bank1: (r) The position information
// bank2: (rw) The temporary texture state
-int main(int index)
+int main(int index)
{
int f1,f2,f3,f4, f5,f6,f7,f8, f9,f10,f11,f12, f13,f14,f15,f16;
int g1,g2,g3,g4, g5,g6,g7,g8, g9,g10,g11,g12, g13,g14,g15,g16;
- float trans;
- float rot;
- int x;
- float focusPos; // float
- int focusID;
- int lastFocusID;
- int imgCount;
- trans = loadF(1, 0);
- rot = loadF(1, 1);
-
+ float trans = loadF(1, POS_TRANSLATE);
+ float rot = loadF(1, POS_ROTATE);
matrixLoadScale(&f16, 2.f, 2.f, 2.f);
matrixTranslate(&f16, 0.f, 0.f, trans);
matrixRotate(&f16, 90.f, 0.f, 0.f, 1.f);
@@ -46,24 +46,18 @@
drawTriangleMesh(NAMED_mesh);
-
- //int imgId = 0;
-
+ // Start of images.
bindProgramFragmentStore(NAMED_PFImages);
bindProgramFragment(NAMED_PFSImages);
bindProgramVertex(NAMED_PVImages);
- //focusPos = loadF(1, 2);
- //focusID = 0;
- //lastFocusID = loadI32(2, 0);
- //imgCount = 13;
+ float focusPos = loadF(1, POS_FOCUS);
+ int focusID = 0;
+ int lastFocusID = loadI32(2, STATE_LAST_FOCUS);
+ int imgCount = 13;
- /*
- disable(GL_LIGHTING);
-
-
- if (trans > (-.3)) {
- focusID = -1.0 - focusPos;
+ if (trans > (-.3f)) {
+ focusID = -1.0f - focusPos;
if (focusID >= imgCount) {
focusID = -1;
}
@@ -71,6 +65,7 @@
focusID = -1;
}
+ /*
if (focusID != lastFocusID) {
if (lastFocusID >= 0) {
uploadToTexture(con, env->tex[lastFocusID], 1);
@@ -79,36 +74,38 @@
uploadToTexture(con, env->tex[focusID], 0);
}
}
- storeEnvI32(con, 2, 0, focusID);
+ */
+ storeI32(2, STATE_LAST_FOCUS, focusID);
+ int triangleOffsetsCount = loadI32(2, STATE_TRIANGLE_OFFSET_COUNT);
+ int imgId = 0;
for (imgId=1; imgId <= imgCount; imgId++) {
- float pos = focusPos + imgId + .4f;
- int offset = (int)floor(pos*2);
- pos -= 0.75;
-
- offset += env->triangleOffsetsCount / 2;
-
- if ((offset < 0) || (offset >= env->triangleOffsetsCount)) {
- continue;
+ float pos = focusPos + imgId + 0.4f;
+ int offset = (int)floorf(pos * 2.f);
+ pos = pos - 0.75f;
+
+ offset = offset + triangleOffsetsCount / 2;
+
+ if (!((offset < 0) || (offset >= triangleOffsetsCount))) {
+ int start = offset -2;
+ int end = offset + 2;
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end > triangleOffsetsCount) {
+ end = triangleOffsetsCount;
+ }
+
+ bindTexture(NAMED_PFImages, 0, loadI32(0, imgId - 1));
+ /*
+ matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
+ storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
+ renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
+ */
}
-
- int start = offset -2;
- int end = offset + 2;
-
- if (start < 0) {
- start = 0;
- }
- if (end > env->triangleOffsetsCount) {
- end = env->triangleOffsetsCount;
- }
-
- programFragmentBindTexture(con, env->fpImages, 0, env->tex[imgId - 1]);
- matrixLoadTranslate(con, &m, -pos - env->triangleOffsetsTex[env->triangleOffsetsCount / 2], 0, 0);
- storeEnvMatrix(con, 3, RS_PROGRAM_VERTEX_TEXTURE_OFFSET, &m);
- renderTriangleMeshRange(con, env->mesh, env->triangleOffsets[start], env->triangleOffsets[end] - env->triangleOffsets[start]);
- }
-*/
+ }
return 0;
}
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index fca0818..395bd35 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -38,6 +39,12 @@
import android.view.MotionEvent;
public class FilmRS {
+ private final int POS_TRANSLATE = 0;
+ private final int POS_ROTATE = 1;
+ private final int POS_FOCUS = 2;
+
+ private final int STATE_TRIANGLE_OFFSET_COUNT = 0;
+ private final int STATE_LAST_FOCUS = 1;
public FilmRS() {
}
@@ -56,11 +63,11 @@
if (x > 270) {
x = 270;
}
-
+
float anim = ((float)x-50) / 270.f;
- mBufferPos[0] = 2f * anim + 0.5f; // translation
- mBufferPos[1] = (anim * 40); // rotation
- mBufferPos[2] = ((float)y) / 16.f - 8; // focusPos
+ mBufferPos[POS_TRANSLATE] = 2f * anim + 0.5f; // translation
+ mBufferPos[POS_ROTATE] = (anim * 40); // rotation
+ mBufferPos[POS_FOCUS] = ((float)y) / 16.f - 8; // focusPos
mAllocPos.data(mBufferPos);
}
@@ -80,15 +87,19 @@
private RenderScript.ProgramVertex mPVImages;
private ProgramVertexAlloc mPVA;
- private RenderScript.Allocation mAllocEnv;
+ private RenderScript.Allocation mImages[];
+ private RenderScript.Allocation mAllocIDs;
private RenderScript.Allocation mAllocPos;
private RenderScript.Allocation mAllocState;
private RenderScript.Allocation mAllocPV;
private RenderScript.TriangleMesh mMesh;
private RenderScript.Light mLight;
- private float[] mBufferPos;
- private float[] mBufferPV;
+ private FilmStripMesh mFSM;
+
+ private int[] mBufferIDs;
+ private float[] mBufferPos = new float[3];
+ private int[] mBufferState;
private void initSamplers() {
mRS.samplerBegin();
@@ -112,7 +123,7 @@
mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.EQUAL);
mRS.programFragmentStoreDitherEnable(false);
mRS.programFragmentStoreDepthMask(false);
- mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
RenderScript.BlendDstFunc.ONE);
mPFSImages = mRS.programFragmentStoreCreate();
mPFSImages.setName("PFSImages");
@@ -148,7 +159,75 @@
}
- int mParams[] = new int[10];
+ private void loadImages() {
+ mBufferIDs = new int[13];
+ mImages = new RenderScript.Allocation[13];
+ mAllocIDs = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_FLOAT,
+ mBufferIDs.length);
+
+ Bitmap b;
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScaled = false;
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p01, opts);
+ mImages[0] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p02, opts);
+ mImages[1] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p03, opts);
+ mImages[2] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p04, opts);
+ mImages[3] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p05, opts);
+ mImages[4] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p06, opts);
+ mImages[5] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p07, opts);
+ mImages[6] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p08, opts);
+ mImages[7] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p09, opts);
+ mImages[8] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p10, opts);
+ mImages[9] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p11, opts);
+ mImages[10] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p12, opts);
+ mImages[11] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.drawable.p13, opts);
+ mImages[12] = mRS.allocationCreateFromBitmapBoxed(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ for(int ct=0; ct < mImages.length; ct++) {
+ mImages[ct].uploadToTexture(1);
+ mBufferIDs[ct] = mImages[ct].getID();
+ }
+ mAllocIDs.data(mBufferIDs);
+ }
+
+ private void initState()
+ {
+ mBufferState = new int[10];
+ mAllocState = mRS.allocationCreatePredefSized(
+ RenderScript.ElementPredefined.USER_FLOAT,
+ mBufferState.length);
+
+ mBufferState[STATE_TRIANGLE_OFFSET_COUNT] = mFSM.mTriangleOffsetsCount;
+ mBufferState[STATE_LAST_FOCUS] = -1;
+
+ mAllocState.data(mBufferState);
+ }
private void initRS() {
mElementVertex = mRS.elementGetPredefined(
@@ -157,8 +236,8 @@
RenderScript.ElementPredefined.INDEX_16);
mRS.triangleMeshBegin(mElementVertex, mElementIndex);
- FilmStripMesh fsm = new FilmStripMesh();
- fsm.init(mRS);
+ mFSM = new FilmStripMesh();
+ mFSM.init(mRS);
mMesh = mRS.triangleMeshCreate();
mMesh.setName("mesh");
@@ -176,19 +255,22 @@
mRS.scriptCSetRoot(true);
mScriptStrip = mRS.scriptCCreate();
- mBufferPos = new float[3];
mAllocPos = mRS.allocationCreatePredefSized(
- RenderScript.ElementPredefined.USER_FLOAT,
+ RenderScript.ElementPredefined.USER_FLOAT,
mBufferPos.length);
+ loadImages();
+ initState();
+
mPVA = new ProgramVertexAlloc(mRS);
mPVBackground.bindAllocation(0, mPVA.mAlloc);
mPVImages.bindAllocation(0, mPVA.mAlloc);
mPVA.setupProjectionNormalized(320, 480);
+ mScriptStrip.bindAllocation(mAllocIDs, 0);
mScriptStrip.bindAllocation(mAllocPos, 1);
- //mScriptStrip.bindAllocation(gStateAlloc, 2);
+ mScriptStrip.bindAllocation(mAllocState, 2);
mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
index d338d0d..960fdf0 100644
--- a/libs/rs/java/Rollo/res/raw/rollo.c
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -51,7 +51,7 @@
float touchCut = 1.f;
if (loadI32(0, STATE_TOUCH)) {
- touchCut = 5.f;
+ touchCut = 4.f;
}
@@ -60,14 +60,17 @@
storeF(2, SCRATCH_ZOOM, zoom);
float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
- float rot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
- storeF(2, SCRATCH_ROT, rot);
+ float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, drawRot);
- float diam = 8.f;// + curve * 2.f;
+ float diam = 10.f;
float scale = 1.0f / zoom;
- rot = rot * scale;
- float rotStep = 20.0f / 180.0f * 3.14f * scale;
+ // Bug makes 1.0f alpha fail.
+ color(1.0f, 1.0f, 1.0f, 0.99f);
+
+ float rot = drawRot * scale;
+ float rotStep = 16.0f / 180.0f * 3.14f * scale;
rowCount = 4;
int index = 0;
int iconCount = loadI32(0, STATE_COUNT);
@@ -82,24 +85,55 @@
int y;
for (y = rowCount -1; (y >= 0) && iconCount; y--) {
- float ty1 = ((y * 3.0f) - 4.5f) * scale;
+ float ty1 = ((y * 3.5f) - 6.f) * scale;
float ty2 = ty1 + scale * 2.f;
- bindTexture(NAMED_PF, 0, loadI32(1, y));
- color(1.0f, 1.0f, 1.0f, 1.0f);
- if (done && (index != selectedID)) {
- color(0.4f, 0.4f, 0.4f, 1.0f);
- }
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ //if (done && (index != selectedID)) {
+ //color(0.4f, 0.4f, 0.4f, 1.0f);
+ //}
drawQuad(tx1, ty1, tz1,
tx2, ty1, tz2,
tx2, ty2, tz2,
tx1, ty2, tz1);
+
iconCount--;
index++;
}
rot = rot + rotStep;
}
- return 0;
+ // Draw the selected icon
+ color(1.0f, 1.0f, 1.0f, 0.9f);
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ if (index == selectedID) {
+
+ float tmpSin = sinf(rot) * scale;
+ float tmpCos = cosf(rot) * scale;
+ float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
+ float tx2 = tx1 + (tmpCos * 4.f);
+ float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
+ float tz2 = tz1 - (tmpSin * 4.f);
+
+ float ty1 = ((y * 3.5f) - 5.f) * scale;
+ float ty2 = ty1 + scale * 4.f;
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ return 1;
}
diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c
index b04ea73..256fa3c 100644
--- a/libs/rs/java/Rollo/res/raw/rollo2.c
+++ b/libs/rs/java/Rollo/res/raw/rollo2.c
@@ -3,65 +3,153 @@
#pragma stateFragment(PF)
#pragma stateFragmentStore(PFS)
-void drawLoop(int x, int y, int z, int rot)
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+float filter(float val, float target, float str)
{
- int ct;
- int tx;
- int ty;
- int tmpSin;
- int tmpCos;
- int sz;
-
- for (ct = 0; ct < 10; ct ++) {
- tmpSin = sinx((ct * 36 + rot) * 0x10000);
- tmpCos = cosx((ct * 36 + rot) * 0x10000);
-
- ty = y + tmpCos * 4;
- tx = x + tmpSin * 4;
- pfBindTexture(NAMED_PF, 0, loadI32(1, ct & 3));
-
- sz = 0xc000;
- drawQuad(tx - sz, ty - sz, z,
- tx + sz, ty - sz, z,
- tx + sz, ty + sz, z,
- tx - sz, ty + sz, z);
- }
+ float delta = (target - val);
+ return val + delta * str;
}
+
int main(void* con, int ft, int launchID)
{
int rowCount;
- int x;
- int y;
- int row;
- int col;
int imageID;
- int tx1;
- int ty1;
- int tz1;
- int tx2;
- int ty2;
- int tz2;
- int tmpSin;
- int tmpCos;
- int iconCount;
- int pressure;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+ int iconCount = loadI32(0, STATE_COUNT);
- int ringCount;
+ float f = loadF(2, 0);
+ float iconSize = 1.f;
+ float iconSpacing = 0.2f;
+ float z = 4.f;
-
- rotStep = 16 * 0x10000;
- pressure = loadI32(0, 2);
- rowCount = 4;
-
- iconCount = loadI32(0, 1);
- rot = (-20 + loadI32(0, 0)) * 0x10000;
-
- for (ringCount = 0; ringCount < 5; ringCount++) {
- drawLoop(0, 0, 0x90000 + (ringCount * 0x80000));
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
}
- return 0;
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 5.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetPos = loadI32(0, STATE_FIRST_VISIBLE) / (-20.0f);
+ float pos = filter(loadF(2, SCRATCH_ROT), targetPos, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, pos);
+ pos = pos - 1.f;
+
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+
+
+ // Draw flat icons first
+ int index = ((int)pos) * 4;
+ int row;
+ int col;
+ float xoffset = -0.3f;
+ float gridSize = iconSize * 4.f + iconSpacing * 3.f;
+ float yoffset = (pos - ((int)pos));
+ for (row = 0; row < 4; row ++) {
+ float ty1 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + iconSize;
+
+ for (col = 0; (col < 4) && (index < iconCount); col ++) {
+ if (index >= 0) {
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ float fcol = col;
+ float tx1 = xoffset + (-gridSize / 2.f) + (fcol * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ drawQuad(tx1, ty1, z,
+ tx2, ty1, z,
+ tx2, ty2, z,
+ tx1, ty2, z);
+ }
+ index++;
+ }
+ }
+
+ // bottom roller
+ {
+ float roll = (1.f - yoffset) * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty2 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing);
+ float ty1 = ty2 - tmpCos * iconSize;
+
+ float tz1 = z + tmpSin * iconSize;
+ float tz2 = z;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+ // Top roller
+ {
+ index = (((int)pos) * 4) - 4;
+ float roll = yoffset * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty1 = (gridSize / 2.f) - ((float)-1.f - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + tmpCos * iconSize;
+
+ float tz1 = z;
+ float tz2 = z + tmpSin * iconSize;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+
+
+
+ return 1;
}
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
index 8f48335..14afaf8 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -18,6 +18,7 @@
import java.io.Writer;
+import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;
import android.renderscript.ProgramVertexAlloc;
@@ -95,8 +96,11 @@
private RenderScript.ProgramFragment mPFImages;
private RenderScript.ProgramVertex mPV;
private ProgramVertexAlloc mPVAlloc;
+ private RenderScript.ProgramVertex mPVOrtho;
+ private ProgramVertexAlloc mPVOrthoAlloc;
private RenderScript.Allocation[] mIcons;
private RenderScript.Allocation mIconPlate;
+ private RenderScript.Allocation mBackground;
private int[] mAllocStateBuf;
private RenderScript.Allocation mAllocState;
@@ -130,23 +134,28 @@
mRS.programFragmentStoreBegin(null, null);
mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.LESS);
mRS.programFragmentStoreDitherEnable(false);
- mRS.programFragmentStoreDepthMask(false);
- mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.ONE,
- RenderScript.BlendDstFunc.ONE);
+ mRS.programFragmentStoreDepthMask(true);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA,
+ RenderScript.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
mPFSBackground = mRS.programFragmentStoreCreate();
mPFSBackground.setName("PFS");
mPVAlloc = new ProgramVertexAlloc(mRS);
mRS.programVertexBegin(null, null);
- mRS.programVertexSetTextureMatrixEnable(true);
+ mRS.programVertexSetTextureMatrixEnable(false);
mPV = mRS.programVertexCreate();
mPV.setName("PV");
mPV.bindAllocation(0, mPVAlloc.mAlloc);
-
-
-
mPVAlloc.setupProjectionNormalized(320, 480);
- //mPVAlloc.setupOrthoNormalized(320, 480);
+
+ mPVOrthoAlloc = new ProgramVertexAlloc(mRS);
+ mRS.programVertexBegin(null, null);
+ mRS.programVertexSetTextureMatrixEnable(true);
+ mPVOrtho = mRS.programVertexCreate();
+ mPVOrtho.setName("PVOrtho");
+ mPVOrtho.bindAllocation(0, mPVOrthoAlloc.mAlloc);
+ mPVOrthoAlloc.setupOrthoWindow(320, 480);
+
mRS.contextBindProgramVertex(mPV);
mAllocScratchBuf = new int[32];
@@ -162,16 +171,21 @@
{
- mIcons = new RenderScript.Allocation[4];
+ mIcons = new RenderScript.Allocation[29];
mAllocIconIDBuf = new int[mIcons.length];
mAllocIconID = mRS.allocationCreatePredefSized(
RenderScript.ElementPredefined.USER_I32, mAllocIconIDBuf.length);
-
+
Bitmap b;
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;
+ b = BitmapFactory.decodeResource(mRes, R.raw.cf_background, opts);
+ mBackground = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+ mBackground.setName("TexBk");
+
+
b = BitmapFactory.decodeResource(mRes, R.raw.browser, opts);
mIcons[0] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
@@ -184,6 +198,112 @@
b = BitmapFactory.decodeResource(mRes, R.raw.settings, opts);
mIcons[3] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+/*
+ b = BitmapFactory.decodeResource(mRes, R.raw.assasins_creed, opts);
+ mIcons[4] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.bankofamerica, opts);
+ mIcons[5] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.chess, opts);
+ mIcons[6] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.dictionary, opts);
+ mIcons[7] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.facebook, opts);
+ mIcons[8] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.flashlight, opts);
+ mIcons[9] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.flight_control, opts);
+ mIcons[10] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.google_earth, opts);
+ mIcons[11] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.harry_potter, opts);
+ mIcons[12] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.movies, opts);
+ mIcons[13] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.nytimes, opts);
+ mIcons[14] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.pandora, opts);
+ mIcons[15] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.public_radio, opts);
+ mIcons[16] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.shazam, opts);
+ mIcons[17] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.skype, opts);
+ mIcons[18] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.solitaire, opts);
+ mIcons[19] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.sudoku, opts);
+ mIcons[20] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.taptaprevenge, opts);
+ mIcons[21] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.tetris, opts);
+ mIcons[22] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.tictactoe, opts);
+ mIcons[23] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.tweetie, opts);
+ mIcons[24] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.urbanspoon, opts);
+ mIcons[25] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.waterslide_extreme, opts);
+ mIcons[26] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.weather_channel, opts);
+ mIcons[27] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+
+ b = BitmapFactory.decodeResource(mRes, R.raw.zippo, opts);
+ mIcons[28] = mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGB_565, true);
+*/
+ mIcons[4] = mIcons[3];
+ mIcons[5] = mIcons[2];
+ mIcons[6] = mIcons[1];
+ mIcons[7] = mIcons[0];
+ mIcons[8] = mIcons[1];
+ mIcons[9] = mIcons[2];
+ mIcons[10] = mIcons[3];
+ mIcons[11] = mIcons[2];
+ mIcons[12] = mIcons[1];
+ mIcons[13] = mIcons[0];
+ mIcons[14] = mIcons[1];
+ mIcons[15] = mIcons[2];
+ mIcons[16] = mIcons[3];
+ mIcons[17] = mIcons[2];
+ mIcons[18] = mIcons[1];
+ mIcons[19] = mIcons[0];
+ mIcons[20] = mIcons[1];
+ mIcons[21] = mIcons[2];
+ mIcons[22] = mIcons[3];
+ mIcons[23] = mIcons[2];
+ mIcons[24] = mIcons[1];
+ mIcons[25] = mIcons[0];
+ mIcons[26] = mIcons[1];
+ mIcons[27] = mIcons[2];
+ mIcons[28] = mIcons[3];
+
+
+
for(int ct=0; ct < mIcons.length; ct++) {
mIcons[ct].uploadToTexture(0);
mAllocIconIDBuf[ct] = mIcons[ct].getID();
@@ -221,6 +341,11 @@
}
+ private void makeTextBitmap() {
+ //Bitmap.createBitmap(width, height, Bitmap.Config);
+ //new Canvas(theBitmap);
+ //canvas.drawText();
+ }
private void initRS() {
@@ -232,7 +357,7 @@
//mRS.scriptCSetClearDepth(0);
mScript = mRS.scriptCCreate();
- mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, 0, 0, 38, 0, 0};
+ mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
mAllocState = mRS.allocationCreatePredefSized(
RenderScript.ElementPredefined.USER_I32, mAllocStateBuf.length);
mScript.bindAllocation(mAllocState, 0);
@@ -248,4 +373,3 @@
}
-
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
index b5e02af..27f1584 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -76,7 +76,7 @@
float mOldColumn;
float mZoom = 1;
- int mIconCount = 38;
+ int mIconCount = 29;
int mRows = 4;
int mColumns = (mIconCount + mRows - 1) / mRows;
@@ -101,7 +101,7 @@
void computeSelection(float x, float y)
{
- float col = mColumn + (x - 0.5f) * 3;
+ float col = mColumn + (x - 0.5f) * 4 + 1;
int iCol = (int)(col + 0.25f);
float row = (y / 0.8f) * mRows;
@@ -158,13 +158,14 @@
mZoom = zoom;
mFlingX = nx;
mRender.setZoom(zoom);
- } else {
- if(mControlMode && (mZoom < 1.01f)) {
+ if(mZoom < 1.01f) {
computeSelection(nx, ny);
}
+ } else {
mControlMode = false;
mColumn = mOldColumn;
mRender.setZoom(1.f);
+ mRender.setSelected(-1);
}
} else {
// Do something with corners here....
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 2f99808..45e6d1b 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -99,6 +99,16 @@
ret RsAllocation
}
+AllocationCreateFromBitmapBoxed {
+ param uint32_t width
+ param uint32_t height
+ param RsElementPredefined dstFmt
+ param RsElementPredefined srcFmt
+ param bool genMips
+ param const void * data
+ ret RsAllocation
+ }
+
AllocationUploadToTexture {
param RsAllocation alloc
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index c143307..a2e3babc 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -301,14 +301,18 @@
return elementConverter_cpy_32;
}
- LOGE("pickConverter, unsuported combo");
+ LOGE("pickConverter, unsuported combo, src %i, dst %i", srcFmt, dstFmt);
return 0;
}
RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
{
- rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ rsAssert(!(w & (w-1)));
+ rsAssert(!(h & (h-1)));
+
+ //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, dstFmt));
rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
if (genMips) {
@@ -340,6 +344,42 @@
return texAlloc;
}
+static uint32_t fmtToBits(RsElementPredefined fmt)
+{
+ return 16;
+}
+
+RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ uint32_t w2 = rsHigherPow2(w);
+ uint32_t h2 = rsHigherPow2(h);
+
+ if ((w2 == w) && (h2 == h)) {
+ return rsi_AllocationCreateFromBitmap(rsc, w, h, dstFmt, srcFmt, genMips, data);
+ }
+
+ uint32_t bpp = fmtToBits(srcFmt) >> 3;
+ size_t size = w2 * h2 * bpp;
+ uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
+ memset(tmp, 0, size);
+
+ const uint8_t * src = static_cast<const uint8_t *>(data);
+ for (uint32_t y = 0; y < h; y++) {
+ uint8_t * ydst = &tmp[y + ((h2 - h) >> 1)];
+ memcpy(&ydst[(w2 - w) >> 1], src, w * bpp);
+ src += h * bpp;
+ }
+
+ RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, dstFmt, srcFmt, genMips, tmp);
+ free(tmp);
+ return ret;
+
+
+
+
+}
+
+
RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips)
{
bool use32bpp = false;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 78b8bf8..e52b0e0 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -79,8 +79,7 @@
mFragment.set(frag);
mVertex.set(vtx);
mFragmentStore.set(store);
- return true;
-
+ return ret;
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 497dbcf..a00b8e8 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -83,6 +83,7 @@
const ProgramFragment * getFragment() {return mFragment.get();}
const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+ const ProgramVertex * getVertex() {return mVertex.get();}
void setupCheck();
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 417ba6a..792135d 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -55,8 +55,6 @@
glLoadIdentity();
}
-
- LOGE("lights %i ", mLightCount);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (mLightCount) {
@@ -103,6 +101,25 @@
}
}
+void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants[0]->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
+}
+
+
ProgramVertexState::ProgramVertexState()
{
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index ac15b70..da5ed81 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -41,6 +41,10 @@
void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
void addLight(const Light *);
+ void setProjectionMatrix(const rsc_Matrix *) const;
+ void setModelviewMatrix(const rsc_Matrix *) const;
+ void setTextureMatrix(const rsc_Matrix *) const;
+
protected:
bool mDirty;
uint32_t mLightCount;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 129b19f..10d1120 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -135,7 +135,6 @@
-
//////////////////////////////////////////////////////////////////////////////
// Matrix routines
//////////////////////////////////////////////////////////////////////////////
@@ -257,6 +256,24 @@
}
//////////////////////////////////////////////////////////////////////////////
+// VP
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setModelviewMatrix(m);
+}
+
+static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setTextureMatrix(m);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
// Drawing
//////////////////////////////////////////////////////////////////////////////
@@ -343,20 +360,12 @@
//
//////////////////////////////////////////////////////////////////////////////
-extern "C" const void * loadVp(uint32_t bank, uint32_t offset)
-{
- GET_TLS();
- return &static_cast<const uint8_t *>(sc->mSlots[bank]->getPtr())[offset];
-}
-
-
-
static void SC_color(float r, float g, float b, float a)
{
glColor4f(r, g, b, a);
}
-
+/*
extern "C" void materialDiffuse(float r, float g, float b, float a)
{
float v[] = {r, g, b, a};
@@ -369,35 +378,18 @@
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
}
-extern "C" void lightPosition(float x, float y, float z, float w)
-{
- float v[] = {x, y, z, w};
- glLightfv(GL_LIGHT0, GL_POSITION, v);
-}
-
extern "C" void materialShininess(float s)
{
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
}
+*/
-extern "C" void uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
{
GET_TLS();
rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
}
-extern "C" void enable(uint32_t p)
-{
- glEnable(p);
-}
-
-extern "C" void disable(uint32_t p)
-{
- glDisable(p);
-}
-
-
-
static void SC_ClearColor(float r, float g, float b, float a)
{
//LOGE("c %f %f %f %f", r, g, b, a);
@@ -408,6 +400,16 @@
sc->mEnviroment.mClearColor[3] = a;
}
+static void SC_debugF(const char *s, float f)
+{
+ LOGE("%s %f", s, f);
+}
+
+static void SC_debugI32(const char *s, int32_t i)
+{
+ LOGE("%s %i", s, i);
+}
+
//////////////////////////////////////////////////////////////////////////////
@@ -444,6 +446,10 @@
"float", "(float)" },
{ "randf", (void *)&SC_randf,
"float", "(float)" },
+ { "floorf", (void *)&floorf,
+ "float", "(float)" },
+ { "ceilf", (void *)&ceilf,
+ "float", "(float)" },
// matrix
{ "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
@@ -481,6 +487,14 @@
{ "bindTexture", (void *)&SC_bindTexture,
"void", "(int, int, int)" },
+ // vp
+ { "vpLoadModelMatrix", (void *)&SC_bindProgramFragment,
+ "void", "(void *)" },
+ { "vpLoadTextureMatrix", (void *)&SC_bindProgramFragmentStore,
+ "void", "(void *)" },
+
+
+
// drawing
{ "drawQuad", (void *)&SC_drawQuad,
"void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
@@ -495,10 +509,19 @@
// misc
{ "pfClearColor", (void *)&SC_ClearColor,
"void", "(float, float, float, float)" },
-
{ "color", (void *)&SC_color,
"void", "(float, float, float, float)" },
+ { "uploadToTexture", (void *)&SC_uploadToTexture,
+ "void", "(int, int)" },
+
+
+ { "debugF", (void *)&SC_debugF,
+ "void", "(void *, float)" },
+ { "debugI32", (void *)&SC_debugI32,
+ "void", "(void *, int)" },
+
+
{ NULL, NULL, NULL, NULL }
};
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1d960c5..95d61cd 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -59,6 +59,8 @@
#include <media/PVPlayer.h>
#include "TestPlayerStub.h"
+//#undef USE_STAGEFRIGHT
+
#if USE_STAGEFRIGHT
#include "StagefrightPlayer.h"
#endif
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5944d9c..5be9224 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -26,6 +26,7 @@
SurfaceRenderer.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
+ TIHardwareRenderer.cpp \
Utils.cpp \
AudioPlayer.cpp \
ESDS.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 17c72b9..d547556 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -87,7 +87,10 @@
} else {
mAudioTrack = new AudioTrack(
AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
- numChannels, 8192, 0, &AudioCallback, this, 0);
+ (numChannels == 2)
+ ? AudioSystem::CHANNEL_OUT_STEREO
+ : AudioSystem::CHANNEL_OUT_MONO,
+ 8192, 0, &AudioCallback, this, 0);
assert(mAudioTrack->initCheck() == OK);
@@ -217,8 +220,10 @@
Mutex::Autolock autoLock(mLock);
mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
mPositionTimeRealUs =
- ((mNumFramesPlayed + size_done / 4) * 1000000) / mSampleRate; // XXX
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
}
if (mInputBuffer->range_length() == 0) {
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 6b47a38..01cb2d9 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -73,8 +73,6 @@
if (bitrate_index == 0 || bitrate_index == 0x0f) {
// Disallow "free" bitrate.
-
- LOGE("We disallow 'free' bitrate for now.");
return false;
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index caaec06..4c883c6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -73,6 +73,8 @@
bool mNeedsNALFraming;
+ uint8_t *mSrcBuffer;
+
MPEG4Source(const MPEG4Source &);
MPEG4Source &operator=(const MPEG4Source &);
};
@@ -743,7 +745,8 @@
mBuffer(NULL),
mBufferOffset(0),
mBufferSizeRemaining(0),
- mNeedsNALFraming(false) {
+ mNeedsNALFraming(false),
+ mSrcBuffer(NULL) {
const char *mime;
bool success = mFormat->findCString(kKeyMIMEType, &mime);
assert(success);
@@ -777,8 +780,13 @@
status_t err = mSampleTable->getMaxSampleSize(&max_size);
assert(err == OK);
- // Add padding for de-framing of AVC content just in case.
- mGroup->add_buffer(new MediaBuffer(max_size + 2));
+ // Assume that a given buffer only contains at most 10 fragments,
+ // each fragment originally prefixed with a 2 byte length will
+ // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+ // and thus will grow by 2 bytes per fragment.
+ mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+ mSrcBuffer = new uint8_t[max_size];
mStarted = true;
@@ -793,6 +801,9 @@
mBuffer = NULL;
}
+ delete[] mSrcBuffer;
+ mSrcBuffer = NULL;
+
delete mGroup;
mGroup = NULL;
@@ -832,33 +843,31 @@
// fall through
}
- if (mBuffer == NULL) {
- off_t offset;
- size_t size;
- status_t err = mSampleTable->getSampleOffsetAndSize(
- mCurrentSampleIndex, &offset, &size);
+ off_t offset;
+ size_t size;
+ status_t err = mSampleTable->getSampleOffsetAndSize(
+ mCurrentSampleIndex, &offset, &size);
- if (err != OK) {
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
- uint32_t dts;
- err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+ uint32_t dts;
+ err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
- if (err != OK) {
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
- err = mGroup->acquire_buffer(&mBuffer);
- if (err != OK) {
- assert(mBuffer == NULL);
- return err;
- }
+ err = mGroup->acquire_buffer(&mBuffer);
+ if (err != OK) {
+ assert(mBuffer == NULL);
+ return err;
+ }
- assert(mBuffer->size() + 2 >= size);
-
+ if (!mIsAVC || !mNeedsNALFraming) {
ssize_t num_bytes_read =
- mDataSource->read_at(offset, (uint8_t *)mBuffer->data() + 2, size);
+ mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
@@ -867,50 +876,62 @@
return err;
}
- mBuffer->set_range(2, size);
+ mBuffer->set_range(0, size);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
-
++mCurrentSampleIndex;
- mBufferOffset = 2;
- mBufferSizeRemaining = size;
- }
-
- if (!mIsAVC) {
*out = mBuffer;
mBuffer = NULL;
return OK;
}
- uint8_t *data = (uint8_t *)mBuffer->data() + mBufferOffset;
- assert(mBufferSizeRemaining >= 2);
+ ssize_t num_bytes_read =
+ mDataSource->read_at(offset, mSrcBuffer, size);
- size_t nal_length = (data[0] << 8) | data[1];
- assert(mBufferSizeRemaining >= 2 + nal_length);
-
- if (mNeedsNALFraming) {
- // Insert marker.
- data[-2] = data[-1] = data[0] = 0;
- data[1] = 1;
-
- mBuffer->set_range(mBufferOffset - 2, nal_length + 4);
- } else {
- mBuffer->set_range(mBufferOffset + 2, nal_length);
- }
-
- mBufferOffset += nal_length + 2;
- mBufferSizeRemaining -= nal_length + 2;
-
- if (mBufferSizeRemaining > 0) {
- *out = mBuffer->clone();
- } else {
- *out = mBuffer;
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
mBuffer = NULL;
+
+ return err;
}
+ uint8_t *dstData = (uint8_t *)mBuffer->data();
+ size_t srcOffset = 0;
+ size_t dstOffset = 0;
+ while (srcOffset < size) {
+ assert(srcOffset + 1 < size);
+ size_t nalLength =
+ (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+ assert(srcOffset + 1 + nalLength < size);
+ srcOffset += 2;
+
+ if (nalLength == 0) {
+ continue;
+ }
+
+ assert(dstOffset + 4 <= mBuffer->size());
+
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 1;
+ memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+ srcOffset += nalLength;
+ dstOffset += nalLength;
+ }
+
+ mBuffer->set_range(0, dstOffset);
+ mBuffer->meta_data()->clear();
+ mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+ mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ ++mCurrentSampleIndex;
+
+ *out = mBuffer;
+ mBuffer = NULL;
+
return OK;
}
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 78fcdee..04c9a11 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -40,6 +40,7 @@
#include <media/stagefright/SoftwareRenderer.h>
#include <media/stagefright/SurfaceRenderer.h>
#include <media/stagefright/TimeSource.h>
+#include <media/stagefright/TIHardwareRenderer.h>
#include <ui/PixelFormat.h>
#include <ui/Surface.h>
@@ -311,6 +312,9 @@
{
Mutex::Autolock autoLock(mLock);
mVideoPosition = pts_us;
+
+ LOGV("now_video = %.2f secs (%lld ms)",
+ pts_us / 1E6, (pts_us + 500) / 1000);
}
if (seeking && mAudioPlayer != NULL) {
@@ -344,6 +348,7 @@
if (mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
mTimeSourceDeltaUs = realtime_us - mediatime_us;
+ LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
}
int64_t now_us = mTimeSource->getRealTimeUs();
@@ -436,6 +441,7 @@
}
void MediaPlayerImpl::setAudioSource(MediaSource *source) {
+ LOGI("setAudioSource");
mAudioSource = source;
sp<MetaData> meta = source->getFormat();
@@ -646,17 +652,28 @@
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
assert(success);
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
if (mSurface.get() != NULL) {
+ LOGW("Using SurfaceRenderer.");
mRenderer =
new SurfaceRenderer(
mSurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
- } else if (format == OMX_COLOR_FormatYUV420Planar
- && !strncasecmp(component, "OMX.qcom.video.decoder.", 23)) {
+ } else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+ && !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
+ LOGW("Using QComHardwareRenderer.");
mRenderer =
new QComHardwareRenderer(
mISurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
+ } else if (format == OMX_COLOR_FormatCbYCrY
+ && !strcmp(component, "OMX.TI.Video.Decoder")) {
+ LOGW("Using TIHardwareRenderer.");
+ mRenderer =
+ new TIHardwareRenderer(
+ mISurface, mVideoWidth, mVideoHeight,
+ decodedWidth, decodedHeight);
} else {
LOGW("Using software renderer.");
mRenderer = new SoftwareRenderer(
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index c059a9d..5e44999 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -20,6 +20,7 @@
#undef NDEBUG
#include <assert.h>
+#include <ctype.h>
#include <OMX_Component.h>
@@ -54,14 +55,20 @@
};
static const CodecInfo kDecoderInfo[] = {
+ { "audio/mpeg", "OMX.TI.MP3.decode" },
{ "audio/mpeg", "OMX.PV.mp3dec" },
+ { "audio/3gpp", "OMX.TI.AMR.decode" },
{ "audio/3gpp", "OMX.PV.amrdec" },
+ { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
{ "audio/mp4a-latm", "OMX.PV.aacdec" },
{ "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+ { "video/mp4v-es", "OMX.TI.Video.Decoder" },
{ "video/mp4v-es", "OMX.PV.mpeg4dec" },
{ "video/3gpp", "OMX.qcom.video.decoder.h263" },
+ { "video/3gpp", "OMX.TI.Video.Decoder" },
{ "video/3gpp", "OMX.PV.h263dec" },
{ "video/avc", "OMX.qcom.video.decoder.avc" },
+ { "video/avc", "OMX.TI.Video.Decoder" },
{ "video/avc", "OMX.PV.avcdec" },
};
@@ -92,7 +99,9 @@
}
// static
-OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
+OMXDecoder *OMXDecoder::Create(
+ OMXClient *client, const sp<MetaData> &meta,
+ bool createEncoder) {
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
assert(success);
@@ -102,9 +111,15 @@
const char *codec = NULL;
IOMX::node_id node = 0;
for (int index = 0;; ++index) {
- codec = GetCodec(
- kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
+ if (createEncoder) {
+ codec = GetCodec(
+ kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+ mime, index);
+ } else {
+ codec = GetCodec(
+ kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+ mime, index);
+ }
if (!codec) {
return NULL;
@@ -118,7 +133,33 @@
}
}
- OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec);
+ uint32_t quirks = 0;
+ if (!strcmp(codec, "OMX.PV.avcdec")) {
+ quirks |= kWantsRawNALFrames;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")
+ || !strcmp(codec, "OMX.TI.MP3.decode")) {
+ quirks |= kDoesntReturnBuffersOnDisable;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")) {
+ quirks |= kDoesntFlushOnExecutingToIdle;
+ quirks |= kDoesntProperlyFlushAllPortsAtOnce;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ if (!strncmp(codec, "OMX.qcom.video.", 15)) {
+ quirks |= kRequiresLoadedToIdleAfterAllocation;
+ }
+ if (!strcmp(codec, "OMX.TI.AAC.decode")
+ || !strcmp(codec, "OMX.TI.MP3.decode")) {
+ quirks |= kMeasuresTimeInMilliseconds;
+ }
+
+ OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
uint32_t type;
const void *data;
@@ -169,52 +210,22 @@
return decoder;
}
-// static
-OMXDecoder *OMXDecoder::CreateEncoder(
- OMXClient *client, const sp<MetaData> &meta) {
- const char *mime;
- bool success = meta->findCString(kKeyMIMEType, &mime);
- assert(success);
-
- sp<IOMX> omx = client->interface();
-
- const char *codec = NULL;
- IOMX::node_id node = 0;
- for (int index = 0;; ++index) {
- codec = GetCodec(
- kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
-
- if (!codec) {
- return NULL;
- }
-
- LOGI("Attempting to allocate OMX node '%s'", codec);
-
- status_t err = omx->allocate_node(codec, &node);
- if (err == OK) {
- break;
- }
- }
-
- OMXDecoder *encoder = new OMXDecoder(client, node, mime, codec);
-
- return encoder;
-}
-
OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
- const char *mime, const char *codec)
+ const char *mime, const char *codec,
+ uint32_t quirks)
: mClient(client),
mOMX(mClient->interface()),
mNode(node),
mComponentName(strdup(codec)),
mIsMP3(!strcasecmp(mime, "audio/mpeg")),
+ mIsAVC(!strcasecmp(mime, "video/avc")),
+ mQuirks(quirks),
mSource(NULL),
mCodecSpecificDataIterator(mCodecSpecificData.begin()),
mState(OMX_StateLoaded),
mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
mShutdownInitiated(false),
- mDealer(new MemoryDealer(3 * 1024 * 1024)),
+ mDealer(new MemoryDealer(5 * 1024 * 1024)),
mSeeking(false),
mStarted(false),
mErrorCondition(OK),
@@ -261,7 +272,7 @@
// mDealer->dump("Decoder Dealer");
sp<MetaData> params = new MetaData;
- if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+ if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
params->setInt32(kKeyNeedsNALFraming, true);
}
@@ -297,7 +308,7 @@
}
int attempt = 1;
- while (mState != OMX_StateLoaded && attempt < 10) {
+ while (mState != OMX_StateLoaded && attempt < 20) {
usleep(100000);
++attempt;
@@ -366,7 +377,11 @@
mOutputBuffers.erase(mOutputBuffers.begin());
}
- status_t err = mOMX->send_command(mNode, OMX_CommandFlush, -1);
+ // XXX One of TI's decoders appears to ignore a flush if it doesn't
+ // currently hold on to any buffers on the port in question and
+ // never sends the completion event... FIXME
+
+ status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
assert(err == OK);
// Once flushing is completed buffers will again be scheduled to be
@@ -472,9 +487,121 @@
assert(err == NO_ERROR);
}
-void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
+status_t OMXDecoder::setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat) {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = portIndex;
+ format.nIndex = 0;
+ bool found = false;
+
+ OMX_U32 index = 0;
+ for (;;) {
+ format.nIndex = index;
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ if (err != OK) {
+ return err;
+ }
+
+ // The following assertion is violated by TI's video decoder.
+ // assert(format.nIndex == index);
+
+ if (format.eCompressionFormat == compressionFormat
+ && format.eColorFormat == colorFormat) {
+ found = true;
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!found) {
+ return UNKNOWN_ERROR;
+ }
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ return err;
+}
+
+#if 1
+void OMXDecoder::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+#if 1
+ // Enabling this code appears to be the right thing(tm), but,...
+ // the TI decoder then loses the ability to output YUV420 and only outputs
+ // YCbYCr (16bit)
+ if (!strcasecmp("video/avc", mime)) {
+ OMX_PARAM_COMPONENTROLETYPE role;
+ role.nSize = sizeof(role);
+ role.nVersion.s.nVersionMajor = 1;
+ role.nVersion.s.nVersionMinor = 1;
+ strncpy((char *)role.cRole, "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamStandardComponentRole,
+ &role, sizeof(role));
+ assert(err == OK);
+ }
+#endif
+
+ OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+ if (!strcasecmp("video/avc", mime)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ compressionFormat = OMX_VIDEO_CodingH263;
+ } else {
+ assert(!"Should not be here. Not a supported video mime type.");
+ }
+
+ setVideoPortFormatType(
+ kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+
+ assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+ || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+ }
+#endif
+
OMX_PARAM_PORTDEFINITIONTYPE def;
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
@@ -502,7 +629,7 @@
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
- // video_def.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
video_def->eColorFormat = OMX_COLOR_FormatUnused;
err = mOMX->set_parameter(
@@ -522,21 +649,189 @@
assert(def.eDomain == OMX_PortDomainVideo);
+#if 0
def.nBufferSize =
(((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
+#endif
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
- video_def->nStride = width;
- // video_def->nSliceHeight = height;
- video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
-// video_def->eColorFormat = OMX_COLOR_FormatYUV420Planar;
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == NO_ERROR);
}
+#else
+static void hexdump(const void *_data, size_t size) {
+ char line[256];
+ char tmp[16];
+
+ const uint8_t *data = (const uint8_t *)_data;
+ size_t offset = 0;
+ while (offset < size) {
+ sprintf(line, "0x%04x ", offset);
+
+ size_t n = size - offset;
+ if (n > 16) {
+ n = 16;
+ }
+
+ for (size_t i = 0; i < 16; ++i) {
+ if (i == 8) {
+ strcat(line, " ");
+ }
+
+ if (offset + i < size) {
+ sprintf(tmp, "%02x ", data[offset + i]);
+ strcat(line, tmp);
+ } else {
+ strcat(line, " ");
+ }
+ }
+
+ strcat(line, " ");
+
+ for (size_t i = 0; i < n; ++i) {
+ if (isprint(data[offset + i])) {
+ sprintf(tmp, "%c", data[offset + i]);
+ strcat(line, tmp);
+ } else {
+ strcat(line, ".");
+ }
+ }
+
+ LOGI(line);
+
+ offset += 16;
+ }
+}
+
+static void DumpPortDefinitionType(const void *_param) {
+ OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;
+
+ LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
+ param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);
+
+ if (param->eDomain == OMX_PortDomainVideo) {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video = ¶m->format.video;
+ LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
+ video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
+ } else {
+ hexdump(param, param->nSize);
+ }
+}
+
+void OMXDecoder::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+#if 0
+ // Enabling this code appears to be the right thing(tm), but,...
+ // the decoder then loses the ability to output YUV420 and only outputs
+ // YCbYCr (16bit)
+ {
+ OMX_PARAM_COMPONENTROLETYPE role;
+ role.nSize = sizeof(role);
+ role.nVersion.s.nVersionMajor = 1;
+ role.nVersion.s.nVersionMinor = 1;
+ strncpy((char *)role.cRole, "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamStandardComponentRole,
+ &role, sizeof(role));
+ assert(err == OK);
+ }
+#endif
+
+ setVideoPortFormatType(
+ kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
+
+#if 1
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
+ hexdump(&format, format.nSize);
+
+ assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
+ assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY);
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ assert(err == OK);
+ }
+#endif
+
+ OMX_PORT_PARAM_TYPE ptype;
+ ptype.nSize = sizeof(ptype);
+ ptype.nVersion.s.nVersionMajor = 1;
+ ptype.nVersion.s.nVersionMinor = 1;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
+ hexdump(&ptype, ptype.nSize);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+ DumpPortDefinitionType(&def);
+
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ def.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+
+ LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
+ DumpPortDefinitionType(&def);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ assert(err == OK);
+}
+
+#endif
+
void OMXDecoder::setup() {
const sp<MetaData> &meta = mSource->getFormat();
@@ -554,7 +849,7 @@
success = success && meta->findInt32(kKeyHeight, &height);
assert(success);
- setVideoOutputFormat(width, height);
+ setVideoOutputFormat(mime, width, height);
}
// dumpPortDefinition(0);
@@ -644,10 +939,7 @@
}
void OMXDecoder::onStart() {
- bool needs_qcom_hack =
- !strncmp(mComponentName, "OMX.qcom.video.", 15);
-
- if (!needs_qcom_hack) {
+ if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
assert(err == NO_ERROR);
@@ -656,7 +948,7 @@
allocateBuffers(kPortIndexInput);
allocateBuffers(kPortIndexOutput);
- if (needs_qcom_hack) {
+ if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
// XXX this should happen before AllocateBuffers, but qcom's
// h264 vdec disagrees.
status_t err =
@@ -691,13 +983,17 @@
for (OMX_U32 i = 0; i < num_buffers; ++i) {
sp<IMemory> mem = mDealer->allocate(buffer_size);
+ if (mem.get() == NULL) {
+ LOGE("[%s] allocating IMemory of size %ld FAILED.",
+ mComponentName, buffer_size);
+ }
assert(mem.get() != NULL);
IOMX::buffer_id buffer;
status_t err;
if (port_index == kPortIndexInput
- && !strncmp(mComponentName, "OMX.qcom.video.encoder.", 23)) {
+ && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
// qcom's H.263 encoder appears to want to allocate its own input
// buffers.
err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
@@ -706,7 +1002,7 @@
mComponentName, err);
}
} else if (port_index == kPortIndexOutput
- && !strncmp(mComponentName, "OMX.qcom.video.decoder.", 23)) {
+ && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
#if 1
err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
#else
@@ -817,18 +1113,59 @@
case OMX_CommandFlush: {
OMX_U32 port_index = data;
LOGV("Port %ld flush complete.", port_index);
- assert(getPortStatus(port_index) == kPortStatusFlushing);
- setPortStatus(port_index, kPortStatusActive);
- BufferList *buffers = &mBuffers.editItemAt(port_index);
- while (!buffers->empty()) {
- IOMX::buffer_id buffer = *buffers->begin();
- buffers->erase(buffers->begin());
+ PortStatus status = getPortStatus(port_index);
- if (port_index == kPortIndexInput) {
- postEmptyBufferDone(buffer);
- } else {
- postInitialFillBuffer(buffer);
+ assert(status == kPortStatusFlushing
+ || status == kPortStatusFlushingToDisabled
+ || status == kPortStatusFlushingToShutdown);
+
+ switch (status) {
+ case kPortStatusFlushing:
+ {
+ // This happens when we're flushing before a seek.
+ setPortStatus(port_index, kPortStatusActive);
+ BufferList *buffers = &mBuffers.editItemAt(port_index);
+ while (!buffers->empty()) {
+ IOMX::buffer_id buffer = *buffers->begin();
+ buffers->erase(buffers->begin());
+
+ if (port_index == kPortIndexInput) {
+ postEmptyBufferDone(buffer);
+ } else {
+ postInitialFillBuffer(buffer);
+ }
+ }
+ break;
+ }
+
+ case kPortStatusFlushingToDisabled:
+ {
+ // Port settings have changed and the (buggy) OMX component
+ // does not properly return buffers on disabling, we need to
+ // do a flush first and _then_ disable the port in question.
+
+ setPortStatus(port_index, kPortStatusDisabled);
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandPortDisable, port_index);
+ assert(err == OK);
+
+ freePortBuffers(port_index);
+ break;
+ }
+
+ default:
+ {
+ assert(status == kPortStatusFlushingToShutdown);
+
+ setPortStatus(port_index, kPortStatusShutdown);
+ if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
+ && getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateIdle);
+ assert(err == OK);
+ }
+ break;
}
}
break;
@@ -841,10 +1178,22 @@
void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
assert(getPortStatus(port_index) == kPortStatusActive);
- setPortStatus(port_index, kPortStatusDisabled);
- status_t err =
- mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+ status_t err;
+
+ if (mQuirks & kDoesntReturnBuffersOnDisable) {
+ // Decoder does not properly return our buffers when disabled...
+ // Need to flush port instead and _then_ disable.
+
+ setPortStatus(port_index, kPortStatusFlushingToDisabled);
+
+ err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
+ } else {
+ setPortStatus(port_index, kPortStatusDisabled);
+
+ err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
+ }
+
assert(err == NO_ERROR);
}
@@ -894,19 +1243,8 @@
mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
assert(err == NO_ERROR);
- BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
- for (BufferList::iterator it = ibuffers->begin();
- it != ibuffers->end(); ++it) {
- freeInputBuffer(*it);
- }
- ibuffers->clear();
-
- BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
- for (BufferList::iterator it = obuffers->begin();
- it != obuffers->end(); ++it) {
- freeOutputBuffer(*it);
- }
- obuffers->clear();
+ freePortBuffers(kPortIndexInput);
+ freePortBuffers(kPortIndexOutput);
}
}
@@ -925,26 +1263,41 @@
mShutdownInitiated = true;
- status_t err =
- mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
- assert(err == NO_ERROR);
+ status_t err;
+ if (mQuirks & kDoesntFlushOnExecutingToIdle) {
+ if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
+ err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
+ assert(err == OK);
- setPortStatus(kPortIndexInput, kPortStatusShutdown);
- setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+ err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
+ } else {
+ err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
+ }
+
+ setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
+ setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
+ } else {
+ err = mClient->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateIdle);
+
+ setPortStatus(kPortIndexInput, kPortStatusShutdown);
+ setPortStatus(kPortIndexOutput, kPortStatusShutdown);
+ }
+ assert(err == OK);
}
void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
- int shift = 2 * port_index;
+ int shift = 3 * port_index;
- mPortStatusMask &= ~(3 << shift);
+ mPortStatusMask &= ~(7 << shift);
mPortStatusMask |= status << shift;
}
OMXDecoder::PortStatus OMXDecoder::getPortStatus(
OMX_U32 port_index) const {
- int shift = 2 * port_index;
+ int shift = 3 * port_index;
- return static_cast<PortStatus>((mPortStatusMask >> shift) & 3);
+ return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
}
void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
@@ -964,6 +1317,8 @@
break;
case kPortStatusFlushing:
+ case kPortStatusFlushingToDisabled:
+ case kPortStatusFlushingToShutdown:
LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
err = NO_ERROR;
@@ -980,7 +1335,9 @@
void OMXDecoder::onFillBufferDone(const omx_message &msg) {
IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
- LOGV("[%s] onFillBufferDone (%p)", mComponentName, buffer);
+ LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
+ msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
+ buffer, msg.u.extended_buffer_data.range_length);
status_t err;
switch (getPortStatus(kPortIndexOutput)) {
@@ -995,6 +1352,8 @@
break;
case kPortStatusFlushing:
+ case kPortStatusFlushingToDisabled:
+ case kPortStatusFlushingToShutdown:
LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
err = NO_ERROR;
@@ -1035,7 +1394,7 @@
size_t range_length = 0;
- if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
+ if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
memcpy(mem->pointer(), kNALStartCode, 4);
@@ -1142,15 +1501,18 @@
OMX_TICKS timestamp = 0;
if (success) {
- // XXX units should be microseconds but PV treats them as milliseconds.
- timestamp = ((OMX_S64)units * 1000) / scale;
+ if (mQuirks & kMeasuresTimeInMilliseconds) {
+ timestamp = ((OMX_S64)units * 1000) / scale;
+ } else {
+ timestamp = ((OMX_S64)units * 1000000) / scale;
+ }
}
input_buffer->release();
input_buffer = NULL;
- LOGV("[%s] Calling EmptyBuffer on buffer %p",
- mComponentName, buffer);
+ LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
+ mComponentName, buffer, src_length, flags);
status_t err2 = mClient->emptyBuffer(
mNode, buffer, 0, src_length, flags, timestamp);
@@ -1169,8 +1531,16 @@
media_buffer->meta_data()->clear();
- media_buffer->meta_data()->setInt32(
- kKeyTimeUnits, msg.u.extended_buffer_data.timestamp);
+ if (mQuirks & kMeasuresTimeInMilliseconds) {
+ media_buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ msg.u.extended_buffer_data.timestamp);
+ } else {
+ media_buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+ }
+
media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
@@ -1198,7 +1568,9 @@
PortStatus outputStatus = getPortStatus(kPortIndexOutput);
if (outputStatus == kPortStatusShutdown
- || outputStatus == kPortStatusFlushing) {
+ || outputStatus == kPortStatusFlushing
+ || outputStatus == kPortStatusFlushingToDisabled
+ || outputStatus == kPortStatusFlushingToShutdown) {
mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
} else {
LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
@@ -1326,4 +1698,18 @@
postMessage(msg);
}
+void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
+ BufferList *buffers = &mBuffers.editItemAt(port_index);
+ while (!buffers->empty()) {
+ IOMX::buffer_id buffer = *buffers->begin();
+ buffers->erase(buffers->begin());
+
+ if (port_index == kPortIndexInput) {
+ freeInputBuffer(buffer);
+ } else {
+ freeOutputBuffer(buffer);
+ }
+ }
+}
+
} // namespace android
diff --git a/media/libstagefright/TIHardwareRenderer.cpp b/media/libstagefright/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ba42ef4
--- /dev/null
+++ b/media/libstagefright/TIHardwareRenderer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 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_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+ assert(mISurface.get() != NULL);
+ assert(mDecodedWidth > 0);
+ assert(mDecodedHeight > 0);
+
+ sp<OverlayRef> ref = mISurface->createOverlay(
+ mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+ if (ref.get() == NULL) {
+ LOGE("Unable to create the overlay!");
+ return;
+ }
+
+ mOverlay = new Overlay(ref);
+
+ for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) {
+ mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i));
+ }
+ mIndex = mOverlayAddresses.size() - 1;
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+ if (mOverlay.get() != NULL) {
+ mOverlay->destroy();
+ mOverlay.clear();
+
+ // XXX apparently destroying an overlay is an asynchronous process...
+ sleep(1);
+ }
+}
+
+void TIHardwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ // assert(size == mFrameSize);
+
+ if (mOverlay.get() == NULL) {
+ return;
+ }
+
+#if 0
+ overlay_buffer_t buffer;
+ if (mOverlay->dequeueBuffer(&buffer) == OK) {
+ void *addr = mOverlay->getBufferAddress(buffer);
+
+ memcpy(addr, data, size);
+
+ mOverlay->queueBuffer(buffer);
+ }
+#else
+ memcpy(mOverlayAddresses[mIndex], data, size);
+ mOverlay->queueBuffer((void *)mIndex);
+
+ if (mIndex-- == 0) {
+ mIndex = mOverlayAddresses.size() - 1;
+ }
+#endif
+}
+
+} // namespace android
+
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 79d78ad1..a3c3436 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -29,6 +29,10 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
@@ -58,7 +62,8 @@
import java.util.Observable;
import java.util.Observer;
-class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
+class PowerManagerService extends IPowerManager.Stub
+ implements LocalPowerManager,Watchdog.Monitor, SensorEventListener {
private static final String TAG = "PowerManagerService";
static final String PARTIAL_NAME = "PowerManagerService";
@@ -72,7 +77,8 @@
private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.SCREEN_DIM_WAKE_LOCK
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.FULL_WAKE_LOCK;
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
// time since last state: time since last event:
// The short keylight delay comes from Gservices; this is the default.
@@ -138,6 +144,7 @@
private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private int[] mBroadcastWhy = new int[3];
private int mPartialCount = 0;
+ private int mProximityCount = 0;
private int mPowerState;
private boolean mOffBecauseOfUser;
private int mUserState;
@@ -175,6 +182,8 @@
private IActivityManager mActivityService;
private IBatteryStats mBatteryStats;
private BatteryService mBatteryService;
+ private SensorManager mSensorManager;
+ private Sensor mProximitySensor;
private boolean mDimScreen = true;
private long mNextTimeout;
private volatile int mPokey = 0;
@@ -536,6 +545,7 @@
wl.minState = SCREEN_DIM;
break;
case PowerManager.PARTIAL_WAKE_LOCK:
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
// just log and bail. we're in the server, so don't
@@ -583,6 +593,11 @@
}
}
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
+ } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount++;
+ if (mProximityCount == 1) {
+ enableProximityLockLocked();
+ }
}
if (newlock) {
acquireUid = wl.uid;
@@ -639,6 +654,11 @@
if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
Power.releaseWakeLock(PARTIAL_NAME);
}
+ } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount--;
+ if (mProximityCount == 0) {
+ disableProximityLockLocked();
+ }
}
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
@@ -1996,4 +2016,47 @@
public void monitor() {
synchronized (mLocks) { }
}
+
+ public int getSupportedWakeLockFlags() {
+ int result = PowerManager.PARTIAL_WAKE_LOCK
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.SCREEN_DIM_WAKE_LOCK;
+
+ // call getSensorManager() to make sure mProximitySensor is initialized
+ getSensorManager();
+ if (mProximitySensor != null) {
+ result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
+ }
+
+ return result;
+ }
+
+ private SensorManager getSensorManager() {
+ if (mSensorManager == null) {
+ mSensorManager = new SensorManager(mHandlerThread.getLooper());
+ mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ }
+ return mSensorManager;
+ }
+
+ private void enableProximityLockLocked() {
+ mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ private void disableProximityLockLocked() {
+ mSensorManager.unregisterListener(this);
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ long milliseconds = event.timestamp / 1000000;
+ if (event.values[0] == 0.0) {
+ goToSleep(milliseconds);
+ } else {
+ userActivity(milliseconds, false);
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // ignore
+ }
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a03490d..2eecef8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,6 +16,9 @@
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.AdbUtils;
+import com.android.dumprendertree.forwarder.ForwardServer;
+
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
@@ -42,7 +45,7 @@
private BufferedOutputStream mBufferedOutputFailedStream;
private BufferedOutputStream mBufferedOutputNoresultStream;
private BufferedOutputStream mBufferedOutputTimedoutStream;
-
+
public void passed(String layout_file) {
try {
mBufferedOutputPassedStream.write(layout_file.getBytes());
@@ -52,7 +55,7 @@
e.printStackTrace();
}
}
-
+
public void failed(String layout_file) {
try {
mBufferedOutputFailedStream.write(layout_file.getBytes());
@@ -62,7 +65,7 @@
e.printStackTrace();
}
}
-
+
public void noresult(String layout_file) {
try {
mBufferedOutputNoresultStream.write(layout_file.getBytes());
@@ -72,7 +75,7 @@
e.printStackTrace();
}
}
-
+
public void timedout(String url) {
try {
mBufferedOutputTimedoutStream.write(url.getBytes());
@@ -82,14 +85,14 @@
e.printStackTrace();
}
}
-
+
public MyTestRecorder(boolean resume) {
try {
File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
-
+
mBufferedOutputPassedStream =
new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
mBufferedOutputFailedStream =
@@ -102,7 +105,7 @@
e.printStackTrace();
}
}
-
+
public void close() {
try {
mBufferedOutputPassedStream.close();
@@ -120,7 +123,7 @@
private static final String LOGTAG = "LayoutTests";
static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-
+
static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
@@ -139,14 +142,35 @@
static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
+ static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+ static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+ static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+ static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+ static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
+
+ private ForwardServer fs8000, fs8080, fs8443;
+
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
private String mTestPathPrefix;
private boolean mFinished;
-
+
public LayoutTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
+
+ int addr = -1;
+ try {
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.e(LOGTAG, "failed to resolve server address.", ioe);
+ }
+ if(addr != -1) {
+ fs8000 = new ForwardServer(8000, addr, 8000);
+ fs8080 = new ForwardServer(8080, addr, 8080);
+ fs8443 = new ForwardServer(8443, addr, 8443);
+ }
}
// This function writes the result of the layout test to
@@ -157,7 +181,7 @@
bundle.putBoolean(file, result);
inst.sendStatus(0, bundle);
}
-
+
private void getTestList() {
// Read test list.
try {
@@ -174,7 +198,7 @@
Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
}
}
-
+
private void resumeTestList() {
// read out the test name it stoped last time.
try {
@@ -189,7 +213,7 @@
Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
}
}
-
+
private void clearTestStatus() {
// Delete TEST_STATUS_FILE
try {
@@ -208,13 +232,13 @@
// Write actual results to result directory.
return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
}
-
+
private String getExpectedResultFile(String test) {
int pos = test.lastIndexOf('.');
if(pos == -1)
return null;
String shortName = test.substring(0, pos);
- return shortName + "-expected.txt";
+ return shortName + "-expected.txt";
}
private String getAndroidExpectedResultFile(String expectedResultFile) {
@@ -224,7 +248,7 @@
// Wrap up
private void failedCase(String file) {
Log.w("Layout test: ", file + " failed");
- mResultRecorder.failed(file);
+ mResultRecorder.failed(file);
}
private void passedCase(String file) {
@@ -236,7 +260,7 @@
Log.v("Layout test:", file + " no expected result");
mResultRecorder.noresult(file);
}
-
+
private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
Log.v(LOGTAG, " Processing result: " + testFile);
@@ -257,13 +281,13 @@
break;
}
}
-
+
if (passing) {
passedCase(testFile);
} else {
failedCase(testFile);
}
-
+
fe.close();
fr.close();
} catch (FileNotFoundException ex) {
@@ -278,7 +302,7 @@
noresultCase(testFile);
}
}
-
+
private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
activity.setCallback(new TestShellCallback() {
public void finished() {
@@ -287,7 +311,7 @@
LayoutTestsAutoTest.this.notifyAll();
}
}
-
+
public void timedOut(String url) {
}
});
@@ -306,16 +330,16 @@
resultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
mFinished = false;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(activity, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
activity.startActivity(intent);
-
+
// Wait until done.
synchronized (this) {
while(!mFinished){
@@ -324,18 +348,18 @@
} catch (InterruptedException e) { }
}
}
-
+
if (!mRebaselineResults) {
String expectedResultFile = getExpectedResultFile(test);
File f = new File(expectedResultFile);
if (!f.exists()) {
expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
processResult(test, resultFile, expectedResultFile);
}
- }
-
+ }
+
// Invokes running of layout tests
// and waits till it has finished running.
public void executeLayoutTests(boolean resume) {
@@ -348,28 +372,28 @@
}
this.mTestList = new Vector<String>();
-
+
// Read settings
try {
this.mTestPathPrefix =
(new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
- } catch (IOException e) {
+ } catch (IOException e) {
Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
return;
}
-
+
this.mRebaselineResults = runner.mRebaseline;
-
+
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {
timeout = DEFAULT_TIMEOUT_IN_MILLIS;
}
-
+
this.mResultRecorder = new MyTestRecorder(resume);
-
+
if (!resume)
clearTestStatus();
-
+
getTestList();
if (resume)
resumeTestList();
@@ -377,6 +401,15 @@
TestShellActivity activity = (TestShellActivity) getActivity();
// Run tests.
+ int addr = -1;
+ try{
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while resolving test host name", ioe);
+ }
+ if(addr == -1) {
+ Log.w(LOGTAG, "failed to resolve test host. http tests will fail.");
+ }
for (int i = 0; i < mTestList.size(); i++) {
String s = mTestList.elementAt(i);
FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
@@ -385,10 +418,48 @@
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-
+ if(fs8000 != null)
+ fs8000.stop();
+ if(fs8080 != null)
+ fs8080.stop();
+ if(fs8443 != null)
+ fs8443.stop();
+
activity.finish();
}
+ private void startForwardServerIfNeeded() {
+ try {
+ if(fs8000 != null)
+ fs8000.start();
+ if(fs8080 != null)
+ fs8080.start();
+ if(fs8443 != null)
+ fs8443.start();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+ }
+ }
+
+ private String getTestUrl(String path) {
+ String url = null;
+ if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+ url = "file://" + path;
+ } else {
+ startForwardServerIfNeeded();
+ if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+ // still cut the URL after "http/tests/"
+ url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+ && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+ && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else {
+ url = "file://" + path;
+ }
+ }
+ return url;
+ }
private String getTestPath() {
LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
@@ -403,10 +474,10 @@
Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
}
Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-
+
return test_path;
}
-
+
public void generateTestList() {
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
@@ -431,7 +502,7 @@
} catch (Exception e) {
e.printStackTrace();
}
-
+
executeLayoutTests(false);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 48c1e5d..4483a8e 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -531,6 +531,12 @@
}
@Override
+ public boolean onJsTimeout() {
+ Log.v(LOGTAG, "JavaScript timeout");
+ return false;
+ }
+
+ @Override
public void onExceededDatabaseQuota(String url_str,
String databaseIdentifier, long currentQuota,
WebStorage.QuotaUpdater callback) {
@@ -614,6 +620,9 @@
}
WebSettings settings = webview.getSettings();
+ settings.setAppCacheEnabled(true);
+ settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
+ settings.setAppCacheMaxSize(Long.MAX_VALUE);
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setSupportMultipleWindows(true);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
new file mode 100644
index 0000000..9a3e9c2
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -0,0 +1,112 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class AdbUtils {
+
+ private static final String ADB_OK = "OKAY";
+ private static final int ADB_PORT = 5037;
+ private static final String ADB_HOST = "127.0.0.1";
+ private static final int ADB_RESPONSE_SIZE = 4;
+
+ private static final String LOGTAG = "AdbUtils";
+
+ /**
+ *
+ * Convert integer format IP into xxx.xxx.xxx.xxx format
+ *
+ * @param host IP address in integer format
+ * @return human readable format
+ */
+ public static String convert(int host) {
+ return ((host >> 24) & 0xFF) + "."
+ + ((host >> 16) & 0xFF) + "."
+ + ((host >> 8) & 0xFF) + "."
+ + (host & 0xFF);
+ }
+
+ /**
+ *
+ * Resolve DNS name into IP address
+ *
+ * @param host DNS name
+ * @return IP address in integer format
+ * @throws IOException
+ */
+ public static int resolve(String host) throws IOException {
+ Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
+ DataInputStream dis = new DataInputStream(localSocket.getInputStream());
+ OutputStream os = localSocket.getOutputStream();
+ int count_read = 0;
+ byte[] buf = new byte[128];
+
+ if (localSocket == null || dis == null || os == null)
+ return -1;
+ String cmd = "dns:" + host;
+
+ if(!sendAdbCmd(dis, os, cmd))
+ return -1;
+
+ count_read = dis.readInt();
+ localSocket.close();
+ return count_read;
+ }
+
+ /**
+ *
+ * Send an ADB command using existing socket connection
+ *
+ * the streams provided must be from a socket connected to adbd already
+ *
+ * @param is input stream of the socket connection
+ * @param os output stream of the socket
+ * @param cmd the adb command to send
+ * @return if adb gave a success response
+ * @throws IOException
+ */
+ public static boolean sendAdbCmd(InputStream is, OutputStream os,
+ String cmd) throws IOException {
+ byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+ cmd = String.format("%04X", cmd.length()) + cmd;
+ os.write(cmd.getBytes());
+ int read = is.read(buf);
+ if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+ Log.w(LOGTAG, "adb cmd faild.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Get a tcp socket connection to specified IP address and port proxied by adb
+ *
+ * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+ * read from as if it is directly connected to the target
+ *
+ * @param remoteAddress IP address of the host to connect to
+ * @param remotePort port of the host to connect to
+ * @return a valid Socket instance if successful, null otherwise
+ */
+ public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
+ try {
+ Socket socket = new Socket(ADB_HOST, ADB_PORT);
+ String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
+ if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error creating adb socket", ioe);
+ return null;
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
new file mode 100644
index 0000000..74e018e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -0,0 +1,117 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * A port forwarding server. Listens at specified local port and forward the tcp communications to
+ * external host/port via adb networking proxy.
+ *
+ */
+public class ForwardServer {
+
+ private static final String LOGTAG = "ForwardServer";
+
+ private int remotePort;
+ private int remoteAddress;
+ private int localPort;
+ private ServerSocket serverSocket;
+ private boolean started;
+
+ private Set<Forwarder> forwarders;
+
+ public ForwardServer(int localPort, int remoteAddress, int remotePort) {
+ this.localPort = localPort;
+ this.remoteAddress = remoteAddress;
+ this.remotePort = remotePort;
+ started = false;
+ forwarders = new HashSet<Forwarder>();
+ }
+
+ public synchronized void start() throws IOException {
+ if(!started) {
+ serverSocket = new ServerSocket(localPort);
+ Thread serverThread = new Thread(new ServerRunner(serverSocket));
+ serverThread.setName(LOGTAG);
+ serverThread.start();
+ started = true;
+ }
+ }
+
+ public synchronized void stop() {
+ if(started) {
+ synchronized (forwarders) {
+ for(Forwarder forwarder : forwarders)
+ forwarder.stop();
+ forwarders.clear();
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException ioe) {
+ Log.v(LOGTAG, "exception while closing", ioe);
+ } finally {
+ started = false;
+ }
+ }
+ }
+
+ public synchronized boolean isRunning() {
+ return started;
+ }
+
+ private class ServerRunner implements Runnable {
+
+ private ServerSocket socket;
+
+ public ServerRunner(ServerSocket socket) {
+ this.socket = socket;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ Socket localSocket = socket.accept();
+ Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
+ if(remoteSocket == null) {
+ try {
+ localSocket.close();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while closing socket", ioe);
+ } finally {
+ Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
+ }
+ } else {
+ Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
+ ForwardServer.this);
+ forwarder.start();
+ }
+ }
+ } catch (IOException ioe) {
+ return;
+ }
+ }
+ }
+
+ public void register(Forwarder forwarder) {
+ synchronized (forwarders) {
+ if(!forwarders.contains(forwarder)) {
+ forwarders.add(forwarder);
+ }
+ }
+ }
+
+ public void unregister(Forwarder recyclable) {
+ synchronized (forwarders) {
+ if(forwarders.contains(recyclable)) {
+ recyclable.stop();
+ forwarders.remove(recyclable);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
new file mode 100644
index 0000000..e1e04a7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -0,0 +1,92 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ *
+ * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ *
+ */
+public class Forwarder {
+
+ private ForwardServer server;
+ private Socket from, to;
+
+ private static final String LOGTAG = "Forwarder";
+
+ public Forwarder (Socket from, Socket to, ForwardServer server) {
+ this.server = server;
+ this.from = from;
+ this.to = to;
+ server.register(this);
+ }
+
+ public void start() {
+ Thread outgoing = new Thread(new SocketPipe(from, to));
+ Thread incoming = new Thread(new SocketPipe(to, from));
+ outgoing.setName(LOGTAG);
+ incoming.setName(LOGTAG);
+ outgoing.start();
+ incoming.start();
+ }
+
+ public void stop() {
+ shutdown(from);
+ shutdown(to);
+ }
+
+ private void shutdown(Socket socket) {
+ try {
+ socket.shutdownInput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownInput", e);
+ }
+ try {
+ socket.shutdownOutput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownOutput", e);
+ }
+ try {
+ socket.close();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#close", e);
+ }
+ }
+
+ private class SocketPipe implements Runnable {
+
+ private Socket in, out;
+
+ public SocketPipe(Socket in, Socket out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ int length;
+ InputStream is = in.getInputStream();
+ OutputStream os = out.getOutputStream();
+ byte[] buffer = new byte[4096];
+ while ((length = is.read(buffer)) > 0) {
+ os.write(buffer, 0, length);
+ }
+ } catch (IOException ioe) {
+ } finally {
+ server.unregister(Forwarder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SocketPipe{" + in + "=>" + out + "}";
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 12abce5..083cda3 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1467,6 +1467,7 @@
public synchronized boolean restart() {
if (mRunState == RUN_STATE_STOPPED) {
mRunState = RUN_STATE_STARTING;
+ resetInterface(true);
return WifiNative.startDriverCommand();
} else if (mRunState == RUN_STATE_STOPPING) {
mRunState = RUN_STATE_STARTING;