am 39268ffc: Format default locale the same way as those stored in prefs.
* commit '39268ffcb74f4c177e5e7427b66480c77743f928':
Format default locale the same way as those stored in prefs.
diff --git a/api/current.txt b/api/current.txt
index 92969f6..ffa46ec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6782,6 +6782,13 @@
method public abstract boolean onMove(int, int);
}
+ public class CrossProcessCursorWrapper extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
+ ctor public CrossProcessCursorWrapper(android.database.Cursor);
+ method public void fillWindow(int, android.database.CursorWindow);
+ method public android.database.CursorWindow getWindow();
+ method public boolean onMove(int, int);
+ }
+
public abstract interface Cursor {
method public abstract void close();
method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -6851,7 +6858,8 @@
}
public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
- ctor public CursorWindow(boolean);
+ ctor public CursorWindow(java.lang.String);
+ ctor public deprecated CursorWindow(boolean);
method public boolean allocRow();
method public void clear();
method public void close();
@@ -24082,6 +24090,8 @@
method public int getCurrentItemIndex();
method public int getFromIndex();
method public int getItemCount();
+ method public int getMaxScrollX();
+ method public int getMaxScrollY();
method public android.os.Parcelable getParcelableData();
method public int getRemovedCount();
method public int getScrollX();
@@ -24108,6 +24118,8 @@
method public void setFromIndex(int);
method public void setFullScreen(boolean);
method public void setItemCount(int);
+ method public void setMaxScrollX(int);
+ method public void setMaxScrollY(int);
method public void setParcelableData(android.os.Parcelable);
method public void setPassword(boolean);
method public void setRemovedCount(int);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 528d197..7cb8f62 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -30,7 +30,6 @@
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ALooper.h>
-#include "include/ARTSPController.h"
#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
#include <media/stagefright/AudioPlayer.h>
@@ -636,7 +635,6 @@
gDisplayHistogram = false;
sp<ALooper> looper;
- sp<ARTSPController> rtspController;
sp<LiveSession> liveSession;
int res;
@@ -948,7 +946,6 @@
sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
if (strncasecmp(filename, "sine:", 5)
- && strncasecmp(filename, "rtsp://", 7)
&& strncasecmp(filename, "httplive://", 11)
&& dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
@@ -984,23 +981,7 @@
} else {
sp<MediaExtractor> extractor;
- if (!strncasecmp("rtsp://", filename, 7)) {
- if (looper == NULL) {
- looper = new ALooper;
- looper->start();
- }
-
- rtspController = new ARTSPController(looper);
- status_t err = rtspController->connect(filename);
- if (err != OK) {
- fprintf(stderr, "could not connect to rtsp server.\n");
- return -1;
- }
-
- extractor = rtspController.get();
-
- syncInfoPresent = false;
- } else if (!strncasecmp("httplive://", filename, 11)) {
+ if (!strncasecmp("httplive://", filename, 11)) {
String8 uri("http://");
uri.append(filename + 11);
@@ -1021,6 +1002,7 @@
syncInfoPresent = false;
} else {
extractor = MediaExtractor::Create(dataSource);
+
if (extractor == NULL) {
fprintf(stderr, "could not create extractor.\n");
return -1;
@@ -1116,13 +1098,6 @@
} else {
playSource(&client, mediaSource);
}
-
- if (rtspController != NULL) {
- rtspController->disconnect();
- rtspController.clear();
-
- sleep(3);
- }
}
if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3290b9d..3aa159e 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -498,8 +499,24 @@
ComponentName launchActivity,
Bundle appSearchData,
boolean globalSearch) {
+ startSearch(initialQuery, selectInitialQuery, launchActivity,
+ appSearchData, globalSearch, null);
+ }
+
+ /**
+ * As {@link #startSearch(String, boolean, ComponentName, Bundle, boolean)} but including
+ * source bounds for the global search intent.
+ *
+ * @hide
+ */
+ public void startSearch(String initialQuery,
+ boolean selectInitialQuery,
+ ComponentName launchActivity,
+ Bundle appSearchData,
+ boolean globalSearch,
+ Rect sourceBounds) {
if (globalSearch) {
- startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
+ startGlobalSearch(initialQuery, selectInitialQuery, appSearchData, sourceBounds);
return;
}
@@ -520,7 +537,7 @@
* Starts the global search activity.
*/
/* package */ void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
- Bundle appSearchData) {
+ Bundle appSearchData, Rect sourceBounds) {
ComponentName globalSearchActivity = getGlobalSearchActivity();
if (globalSearchActivity == null) {
Log.w(TAG, "No global search activity found.");
@@ -546,6 +563,7 @@
if (selectInitialQuery) {
intent.putExtra(EXTRA_SELECT_QUERY, selectInitialQuery);
}
+ intent.setSourceBounds(sourceBounds);
try {
if (DBG) Log.d(TAG, "Starting global search: " + intent.toUri(0));
mContext.startActivity(intent);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e923349..cc3219b 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -26,6 +26,7 @@
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.database.IContentObserver;
@@ -1568,7 +1569,7 @@
samplePercent);
}
- private final class CursorWrapperInner extends CursorWrapper {
+ private final class CursorWrapperInner extends CrossProcessCursorWrapper {
private final IContentProvider mContentProvider;
public static final String TAG="CursorWrapperInner";
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index ee6aec6..74fef29 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -53,7 +53,10 @@
abstract public boolean isNull(int column);
public int getType(int column) {
- throw new UnsupportedOperationException();
+ // Reflects the assumption that all commonly used field types (meaning everything
+ // but blobs) are convertible to strings so it should be safe to call
+ // getString to retrieve them.
+ return FIELD_TYPE_STRING;
}
// TODO implement getBlob in all cursor types
@@ -185,46 +188,9 @@
return result;
}
- /**
- * Copy data from cursor to CursorWindow
- * @param position start position of data
- * @param window
- */
+ @Override
public void fillWindow(int position, CursorWindow window) {
- if (position < 0 || position >= getCount()) {
- return;
- }
- window.acquireReference();
- try {
- int oldpos = mPos;
- mPos = position - 1;
- window.clear();
- window.setStartPosition(position);
- int columnNum = getColumnCount();
- window.setNumColumns(columnNum);
- while (moveToNext() && window.allocRow()) {
- for (int i = 0; i < columnNum; i++) {
- String field = getString(i);
- if (field != null) {
- if (!window.putString(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- } else {
- if (!window.putNull(mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- }
- }
-
- mPos = oldpos;
- } catch (IllegalStateException e){
- // simply ignore it
- } finally {
- window.releaseReference();
- }
+ DatabaseUtils.cursorFillWindow(this, position, window);
}
public final boolean move(int offset) {
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index d0aedd2..083485f 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -188,15 +188,14 @@
/**
* If there is a window, clear it.
- * Otherwise, creates a local window.
+ * Otherwise, creates a new window.
*
* @param name The window name.
* @hide
*/
- protected void clearOrCreateLocalWindow(String name) {
+ protected void clearOrCreateWindow(String name) {
if (mWindow == null) {
- // If there isn't a window set already it will only be accessed locally
- mWindow = new CursorWindow(name, true /* the window is local only */);
+ mWindow = new CursorWindow(name);
} else {
mWindow.clear();
}
diff --git a/core/java/android/database/CrossProcessCursor.java b/core/java/android/database/CrossProcessCursor.java
index 8e6a5aa..26379cc 100644
--- a/core/java/android/database/CrossProcessCursor.java
+++ b/core/java/android/database/CrossProcessCursor.java
@@ -16,27 +16,63 @@
package android.database;
+/**
+ * A cross process cursor is an extension of a {@link Cursor} that also supports
+ * usage from remote processes.
+ * <p>
+ * The contents of a cross process cursor are marshalled to the remote process by
+ * filling {@link CursorWindow} objects using {@link #fillWindow}. As an optimization,
+ * the cursor can provide a pre-filled window to use via {@link #getWindow} thereby
+ * obviating the need to copy the data to yet another cursor window.
+ */
public interface CrossProcessCursor extends Cursor {
/**
- * returns a pre-filled window, return NULL if no such window
+ * Returns a pre-filled window that contains the data within this cursor.
+ * <p>
+ * In particular, the window contains the row indicated by {@link Cursor#getPosition}.
+ * The window's contents are automatically scrolled whenever the current
+ * row moved outside the range covered by the window.
+ * </p>
+ *
+ * @return The pre-filled window, or null if none.
*/
CursorWindow getWindow();
/**
- * copies cursor data into the window start at pos
+ * Copies cursor data into the window.
+ * <p>
+ * Clears the window and fills it with data beginning at the requested
+ * row position until all of the data in the cursor is exhausted
+ * or the window runs out of space.
+ * </p><p>
+ * The filled window uses the same row indices as the original cursor.
+ * For example, if you fill a window starting from row 5 from the cursor,
+ * you can query the contents of row 5 from the window just by asking it
+ * for row 5 because there is a direct correspondence between the row indices
+ * used by the cursor and the window.
+ * </p><p>
+ * The current position of the cursor, as returned by {@link #getPosition},
+ * is not changed by this method.
+ * </p>
+ *
+ * @param position The zero-based index of the first row to copy into the window.
+ * @param window The window to fill.
*/
- void fillWindow(int pos, CursorWindow winow);
+ void fillWindow(int position, CursorWindow window);
/**
* This function is called every time the cursor is successfully scrolled
* to a new position, giving the subclass a chance to update any state it
- * may have. If it returns false the move function will also do so and the
+ * may have. If it returns false the move function will also do so and the
* cursor will scroll to the beforeFirst position.
+ * <p>
+ * This function should be called by methods such as {@link #moveToPosition(int)},
+ * so it will typically not be called from outside of the cursor class itself.
+ * </p>
*
- * @param oldPosition the position that we're moving from
- * @param newPosition the position that we're moving to
- * @return true if the move is successful, false otherwise
+ * @param oldPosition The position that we're moving from.
+ * @param newPosition The position that we're moving to.
+ * @return True if the move is successful, false otherwise.
*/
boolean onMove(int oldPosition, int newPosition);
-
}
diff --git a/core/java/android/database/CrossProcessCursorWrapper.java b/core/java/android/database/CrossProcessCursorWrapper.java
new file mode 100644
index 0000000..8c250b8
--- /dev/null
+++ b/core/java/android/database/CrossProcessCursorWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.database;
+
+import android.database.CrossProcessCursor;
+import android.database.Cursor;
+import android.database.CursorWindow;
+import android.database.CursorWrapper;
+
+/**
+ * Cursor wrapper that implements {@link CrossProcessCursor}.
+ * <p>
+ * If the wrapper cursor implemented {@link CrossProcessCursor}, then delegates
+ * {@link #fillWindow}, {@link #getWindow()} and {@link #onMove} to it. Otherwise,
+ * provides default implementations of these methods that traverse the contents
+ * of the cursor similar to {@link AbstractCursor#fillWindow}.
+ * </p><p>
+ * This wrapper can be used to adapt an ordinary {@link Cursor} into a
+ * {@link CrossProcessCursor}.
+ * </p>
+ */
+public class CrossProcessCursorWrapper extends CursorWrapper implements CrossProcessCursor {
+ /**
+ * Creates a cross process cursor wrapper.
+ * @param cursor The underlying cursor to wrap.
+ */
+ public CrossProcessCursorWrapper(Cursor cursor) {
+ super(cursor);
+ }
+
+ @Override
+ public void fillWindow(int position, CursorWindow window) {
+ if (mCursor instanceof CrossProcessCursor) {
+ final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+ crossProcessCursor.fillWindow(position, window);
+ return;
+ }
+
+ DatabaseUtils.cursorFillWindow(mCursor, position, window);
+ }
+
+ @Override
+ public CursorWindow getWindow() {
+ if (mCursor instanceof CrossProcessCursor) {
+ final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+ return crossProcessCursor.getWindow();
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean onMove(int oldPosition, int newPosition) {
+ if (mCursor instanceof CrossProcessCursor) {
+ final CrossProcessCursor crossProcessCursor = (CrossProcessCursor)mCursor;
+ return crossProcessCursor.onMove(oldPosition, newPosition);
+ }
+
+ return true;
+ }
+}
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index dd2c9b7..215035d 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -25,9 +25,9 @@
/**
* Wraps a BulkCursor around an existing Cursor making it remotable.
* <p>
- * If the wrapped cursor is a {@link AbstractWindowedCursor} then it owns
- * the cursor window. Otherwise, the adaptor takes ownership of the
- * cursor itself and ensures it gets closed as needed during deactivation
+ * If the wrapped cursor returns non-null from {@link CrossProcessCursor#getWindow}
+ * then it is assumed to own the window. Otherwise, the adaptor provides a
+ * window to be filled and ensures it gets closed as needed during deactivation
* and requeries.
* </p>
*
@@ -48,12 +48,11 @@
private CrossProcessCursor mCursor;
/**
- * The cursor window used by the cross process cursor.
- * This field is always null for abstract windowed cursors since they are responsible
- * for managing the lifetime of their window.
+ * The cursor window that was filled by the cross process cursor in the
+ * case where the cursor does not support getWindow.
+ * This field is only ever non-null when the window has actually be filled.
*/
- private CursorWindow mWindowForNonWindowedCursor;
- private boolean mWindowForNonWindowedCursorWasFilled;
+ private CursorWindow mFilledWindow;
private static final class ContentObserverProxy extends ContentObserver {
protected IContentObserver mRemote;
@@ -90,11 +89,10 @@
public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer,
String providerName) {
- try {
- mCursor = (CrossProcessCursor) cursor;
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException(
- "Only CrossProcessCursor cursors are supported across process for now", e);
+ if (cursor instanceof CrossProcessCursor) {
+ mCursor = (CrossProcessCursor)cursor;
+ } else {
+ mCursor = new CrossProcessCursorWrapper(cursor);
}
mProviderName = providerName;
@@ -103,11 +101,10 @@
}
}
- private void closeWindowForNonWindowedCursorLocked() {
- if (mWindowForNonWindowedCursor != null) {
- mWindowForNonWindowedCursor.close();
- mWindowForNonWindowedCursor = null;
- mWindowForNonWindowedCursorWasFilled = false;
+ private void closeFilledWindowLocked() {
+ if (mFilledWindow != null) {
+ mFilledWindow.close();
+ mFilledWindow = null;
}
}
@@ -118,7 +115,7 @@
mCursor = null;
}
- closeWindowForNonWindowedCursorLocked();
+ closeFilledWindowLocked();
}
private void throwIfCursorIsClosed() {
@@ -139,30 +136,24 @@
synchronized (mLock) {
throwIfCursorIsClosed();
- CursorWindow window;
- if (mCursor instanceof AbstractWindowedCursor) {
- AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor)mCursor;
- window = windowedCursor.getWindow();
- if (window == null) {
- window = new CursorWindow(mProviderName, false /*localOnly*/);
- windowedCursor.setWindow(window);
- }
+ if (!mCursor.moveToPosition(startPos)) {
+ closeFilledWindowLocked();
+ return null;
+ }
- mCursor.moveToPosition(startPos);
+ CursorWindow window = mCursor.getWindow();
+ if (window != null) {
+ closeFilledWindowLocked();
} else {
- window = mWindowForNonWindowedCursor;
+ window = mFilledWindow;
if (window == null) {
- window = new CursorWindow(mProviderName, false /*localOnly*/);
- mWindowForNonWindowedCursor = window;
- }
-
- mCursor.moveToPosition(startPos);
-
- if (!mWindowForNonWindowedCursorWasFilled
- || startPos < window.getStartPosition()
- || startPos >= window.getStartPosition() + window.getNumRows()) {
+ mFilledWindow = new CursorWindow(mProviderName);
+ window = mFilledWindow;
mCursor.fillWindow(startPos, window);
- mWindowForNonWindowedCursorWasFilled = true;
+ } else if (startPos < window.getStartPosition()
+ || startPos >= window.getStartPosition() + window.getNumRows()) {
+ window.clear();
+ mCursor.fillWindow(startPos, window);
}
}
@@ -211,7 +202,7 @@
mCursor.deactivate();
}
- closeWindowForNonWindowedCursorLocked();
+ closeFilledWindowLocked();
}
}
@@ -227,7 +218,7 @@
synchronized (mLock) {
throwIfCursorIsClosed();
- closeWindowForNonWindowedCursorLocked();
+ closeFilledWindowLocked();
try {
if (!mCursor.requery()) {
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index a18a721..9c93324 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -31,8 +31,8 @@
/**
* A buffer containing multiple cursor rows.
* <p>
- * A {@link CursorWindow} is read-write when created and used locally. When sent
- * to a remote process (by writing it to a {@link Parcel}), the remote process
+ * A {@link CursorWindow} is read-write when initially created and used locally.
+ * When sent to a remote process (by writing it to a {@link Parcel}), the remote process
* receives a read-only view of the cursor window. Typically the cursor window
* will be allocated by the producer, filled with data, and then sent to the
* consumer for reading.
@@ -58,8 +58,7 @@
private final CloseGuard mCloseGuard = CloseGuard.get();
- private static native int nativeCreate(String name,
- int cursorWindowSize, boolean localOnly);
+ private static native int nativeCreate(String name, int cursorWindowSize);
private static native int nativeCreateFromParcel(Parcel parcel);
private static native void nativeDispose(int windowPtr);
private static native void nativeWriteToParcel(int windowPtr, Parcel parcel);
@@ -93,14 +92,10 @@
* </p>
*
* @param name The name of the cursor window, or null if none.
- * @param localWindow True if this window will be used in this process only,
- * false if it might be sent to another processes.
- *
- * @hide
*/
- public CursorWindow(String name, boolean localWindow) {
+ public CursorWindow(String name) {
mStartPos = 0;
- mWindowPtr = nativeCreate(name, sCursorWindowSize, localWindow);
+ mWindowPtr = nativeCreate(name, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
(sCursorWindowSize / 1024) + " kb failed. " + printStats());
@@ -117,10 +112,14 @@
* </p>
*
* @param localWindow True if this window will be used in this process only,
- * false if it might be sent to another processes.
+ * false if it might be sent to another processes. This argument is ignored.
+ *
+ * @deprecated There is no longer a distinction between local and remote
+ * cursor windows. Use the {@link #CursorWindow(String)} constructor instead.
*/
+ @Deprecated
public CursorWindow(boolean localWindow) {
- this(null, localWindow);
+ this((String)null);
}
private CursorWindow(Parcel source) {
@@ -272,8 +271,7 @@
* Returns true if the field at the specified row and column index
* has type {@link Cursor#FIELD_TYPE_NULL}.
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}.
* @deprecated Use {@link #getType(int, int)} instead.
@@ -287,8 +285,7 @@
* Returns true if the field at the specified row and column index
* has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}.
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or
* {@link Cursor#FIELD_TYPE_NULL}.
@@ -304,8 +301,7 @@
* Returns true if the field at the specified row and column index
* has type {@link Cursor#FIELD_TYPE_INTEGER}.
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}.
* @deprecated Use {@link #getType(int, int)} instead.
@@ -319,8 +315,7 @@
* Returns true if the field at the specified row and column index
* has type {@link Cursor#FIELD_TYPE_FLOAT}.
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}.
* @deprecated Use {@link #getType(int, int)} instead.
@@ -334,8 +329,7 @@
* Returns true if the field at the specified row and column index
* has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}.
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if the field has type {@link Cursor#FIELD_TYPE_STRING}
* or {@link Cursor#FIELD_TYPE_NULL}.
@@ -360,8 +354,7 @@
* </ul>
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The field type.
*/
@@ -391,8 +384,7 @@
* </ul>
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as a byte array.
*/
@@ -427,8 +419,7 @@
* </ul>
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as a string.
*/
@@ -466,8 +457,7 @@
* </ul>
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @param buffer The {@link CharArrayBuffer} to hold the string. It is automatically
* resized if the requested string is larger than the buffer's current capacity.
@@ -502,8 +492,7 @@
* </ul>
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as a <code>long</code>.
*/
@@ -535,8 +524,7 @@
* </ul>
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as a <code>double</code>.
*/
@@ -557,8 +545,7 @@
* result to <code>short</code>.
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as a <code>short</code>.
*/
@@ -574,8 +561,7 @@
* result to <code>int</code>.
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as an <code>int</code>.
*/
@@ -591,8 +577,7 @@
* result to <code>float</code>.
* </p>
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return The value of the field as an <code>float</code>.
*/
@@ -604,8 +589,7 @@
* Copies a byte array into the field at the specified row and column index.
*
* @param value The value to store.
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
@@ -622,8 +606,7 @@
* Copies a string into the field at the specified row and column index.
*
* @param value The value to store.
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
@@ -640,8 +623,7 @@
* Puts a long integer into the field at the specified row and column index.
*
* @param value The value to store.
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
@@ -659,8 +641,7 @@
* specified row and column index.
*
* @param value The value to store.
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
@@ -676,8 +657,7 @@
/**
* Puts a null value into the field at the specified row and column index.
*
- * @param row The zero-based row index, relative to the cursor window's
- * start position ({@link #getStartPosition()}).
+ * @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 320733e..7baeb8c 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -25,9 +25,13 @@
* use for this class is to extend a cursor while overriding only a subset of its methods.
*/
public class CursorWrapper implements Cursor {
+ /** @hide */
+ protected final Cursor mCursor;
- private final Cursor mCursor;
-
+ /**
+ * Creates a cursor wrapper.
+ * @param cursor The underlying cursor to wrap.
+ */
public CursorWrapper(Cursor cursor) {
mCursor = cursor;
}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 8e6f699..a10ca15 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -237,7 +237,8 @@
return Cursor.FIELD_TYPE_BLOB;
} else if (obj instanceof Float || obj instanceof Double) {
return Cursor.FIELD_TYPE_FLOAT;
- } else if (obj instanceof Long || obj instanceof Integer) {
+ } else if (obj instanceof Long || obj instanceof Integer
+ || obj instanceof Short || obj instanceof Byte) {
return Cursor.FIELD_TYPE_INTEGER;
} else {
return Cursor.FIELD_TYPE_STRING;
@@ -245,6 +246,82 @@
}
/**
+ * Fills the specified cursor window by iterating over the contents of the cursor.
+ * The window is filled until the cursor is exhausted or the window runs out
+ * of space.
+ *
+ * The original position of the cursor is left unchanged by this operation.
+ *
+ * @param cursor The cursor that contains the data to put in the window.
+ * @param position The start position for filling the window.
+ * @param window The window to fill.
+ * @hide
+ */
+ public static void cursorFillWindow(final Cursor cursor,
+ int position, final CursorWindow window) {
+ if (position < 0 || position >= cursor.getCount()) {
+ return;
+ }
+ window.acquireReference();
+ try {
+ final int oldPos = cursor.getPosition();
+ final int numColumns = cursor.getColumnCount();
+ window.clear();
+ window.setStartPosition(position);
+ window.setNumColumns(numColumns);
+ if (cursor.moveToPosition(position)) {
+ do {
+ if (!window.allocRow()) {
+ break;
+ }
+ for (int i = 0; i < numColumns; i++) {
+ final int type = cursor.getType(i);
+ final boolean success;
+ switch (type) {
+ case Cursor.FIELD_TYPE_NULL:
+ success = window.putNull(position, i);
+ break;
+
+ case Cursor.FIELD_TYPE_INTEGER:
+ success = window.putLong(cursor.getLong(i), position, i);
+ break;
+
+ case Cursor.FIELD_TYPE_FLOAT:
+ success = window.putDouble(cursor.getDouble(i), position, i);
+ break;
+
+ case Cursor.FIELD_TYPE_BLOB: {
+ final byte[] value = cursor.getBlob(i);
+ success = value != null ? window.putBlob(value, position, i)
+ : window.putNull(position, i);
+ break;
+ }
+
+ default: // assume value is convertible to String
+ case Cursor.FIELD_TYPE_STRING: {
+ final String value = cursor.getString(i);
+ success = value != null ? window.putString(value, position, i)
+ : window.putNull(position, i);
+ break;
+ }
+ }
+ if (!success) {
+ window.freeLastRow();
+ break;
+ }
+ }
+ position += 1;
+ } while (cursor.moveToNext());
+ }
+ cursor.moveToPosition(oldPos);
+ } catch (IllegalStateException e){
+ // simply ignore it
+ } finally {
+ window.releaseReference();
+ }
+ }
+
+ /**
* Appends an SQL string to the given StringBuilder, including the opening
* and closing single quotes. Any single quotes internal to sqlString will
* be escaped.
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index a1c36e2..9574300 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -155,7 +155,7 @@
}
private void fillWindow(int startPos) {
- clearOrCreateLocalWindow(getDatabase().getPath());
+ clearOrCreateWindow(getDatabase().getPath());
mWindow.setStartPosition(startPos);
int count = getQuery().fillWindow(mWindow);
if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index fe0106d..33310df 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -768,61 +768,6 @@
}
/**
- * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
- * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback}
- * @hide
- */
- @Deprecated
- public interface NdefPushCallback {
- /**
- * @deprecated use {@link CreateNdefMessageCallback} instead
- */
- @Deprecated
- NdefMessage createMessage();
- /**
- * @deprecated use{@link OnNdefPushCompleteCallback} instead
- */
- @Deprecated
- void onMessagePushed();
- }
-
- /**
- * TODO: Remove this
- * Converts new callbacks to old callbacks.
- */
- static final class LegacyCallbackWrapper implements CreateNdefMessageCallback,
- OnNdefPushCompleteCallback {
- final NdefPushCallback mLegacyCallback;
- LegacyCallbackWrapper(NdefPushCallback legacyCallback) {
- mLegacyCallback = legacyCallback;
- }
- @Override
- public void onNdefPushComplete(NfcEvent event) {
- mLegacyCallback.onMessagePushed();
- }
- @Override
- public NdefMessage createNdefMessage(NfcEvent event) {
- return mLegacyCallback.createMessage();
- }
- }
-
- /**
- * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
- * @deprecated use {@link #setNdefPushMessageCallback} instead
- * @hide
- */
- @Deprecated
- public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) {
- if (activity == null || callback == null) {
- throw new NullPointerException();
- }
- enforceResumed(activity);
- LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback);
- mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper);
- mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper);
- }
-
- /**
* Enable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 4d7a9bb..cc2fa85 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -35,7 +35,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -902,15 +901,13 @@
return false;
}
+ // Thread policy controls BlockGuard.
int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
StrictMode.DETECT_DISK_READ |
StrictMode.DETECT_NETWORK;
if (!IS_USER_BUILD) {
threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
- if (IS_ENG_BUILD) {
- threadPolicyMask |= StrictMode.PENALTY_LOG;
- }
}
if (doFlashes) {
threadPolicyMask |= StrictMode.PENALTY_FLASH;
@@ -918,6 +915,8 @@
StrictMode.setThreadPolicyMask(threadPolicyMask);
+ // VM Policy controls CloseGuard, detection of Activity leaks,
+ // and instance counting.
if (IS_USER_BUILD) {
setCloseGuardEnabled(false);
} else {
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 4b4d308..d7060c1 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -300,8 +300,25 @@
public static final String CALENDAR_COLOR = "calendar_color";
/**
+ * An index for looking up a color from the {@link Colors} table. NULL
+ * or an empty string are reserved for indicating that the calendar does
+ * not use an index for looking up the color. The provider will update
+ * {@link #CALENDAR_COLOR} automatically when a valid index is written
+ * to this column. @see Colors
+ * <P>
+ * Type: TEXT
+ * </P>
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final String CALENDAR_COLOR_INDEX = "calendar_color_index";
+
+ /**
* The display name of the calendar. Column name.
- * <P>Type: TEXT</P>
+ * <P>
+ * Type: TEXT
+ * </P>
*/
public static final String CALENDAR_DISPLAY_NAME = "calendar_displayName";
@@ -392,6 +409,34 @@
* <P>Type: TEXT</P>
*/
public static final String ALLOWED_REMINDERS = "allowedReminders";
+
+ /**
+ * A comma separated list of availability types supported for this
+ * calendar in the format "#,#,#". Valid types are
+ * {@link Events#AVAILABILITY_BUSY}, {@link Events#AVAILABILITY_FREE},
+ * {@link Events#AVAILABILITY_TENTATIVE}. Setting this field to only
+ * {@link Events#AVAILABILITY_BUSY} should be used to indicate that
+ * changing the availability is not supported.
+ *
+ * TODO UNHIDE, Update Calendars doc
+ *
+ * @hide
+ */
+ public static final String ALLOWED_AVAILABILITY = "allowedAvailability";
+
+ /**
+ * A comma separated list of attendee types supported for this calendar
+ * in the format "#,#,#". Valid types are {@link Attendees#TYPE_NONE},
+ * {@link Attendees#TYPE_OPTIONAL}, {@link Attendees#TYPE_REQUIRED},
+ * {@link Attendees#TYPE_RESOURCE}. Setting this field to only
+ * {@link Attendees#TYPE_NONE} should be used to indicate that changing
+ * the attendee type is not supported.
+ *
+ * TODO UNHIDE, Update Calendars doc
+ *
+ * @hide
+ */
+ public static final String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes";
}
/**
@@ -688,13 +733,22 @@
/**
* The type of attendee. Column name.
- * <P>Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL})</P>
+ * <P>
+ * Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL}
+ * </P>
*/
public static final String ATTENDEE_TYPE = "attendeeType";
public static final int TYPE_NONE = 0;
public static final int TYPE_REQUIRED = 1;
public static final int TYPE_OPTIONAL = 2;
+ /**
+ * This specifies that an attendee is a resource, such as a room, and
+ * not an actual person. TODO UNHIDE and add to ATTENDEE_TYPE comment
+ *
+ * @hide
+ */
+ public static final int TYPE_RESOURCE = 3;
/**
* The attendance status of the attendee. Column name.
@@ -787,13 +841,26 @@
public static final String EVENT_LOCATION = "eventLocation";
/**
- * A secondary color for the individual event. Reserved for future use.
- * Column name.
+ * A secondary color for the individual event. This should only be
+ * updated by the sync adapter for a given account.
* <P>Type: INTEGER</P>
*/
public static final String EVENT_COLOR = "eventColor";
/**
+ * A secondary color index for the individual event. NULL or an empty
+ * string are reserved for indicating that the event does not use an
+ * index for looking up the color. The provider will update
+ * {@link #EVENT_COLOR} automatically when a valid index is written to
+ * this column. @see Colors
+ * <P>Type: TEXT</P>
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final String EVENT_COLOR_INDEX = "eventColor_index";
+
+ /**
* The event status. Column name.
* <P>Type: INTEGER (one of {@link #STATUS_TENTATIVE}...)</P>
*/
@@ -964,6 +1031,15 @@
* other events.
*/
public static final int AVAILABILITY_FREE = 1;
+ /**
+ * Indicates that the owner's availability may change, but should be
+ * considered busy time that will conflict.
+ *
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final int AVAILABILITY_TENTATIVE = 2;
/**
* Whether the event has an alarm or not. Column name.
@@ -2224,6 +2300,91 @@
}
}
+ /**
+ * @hide
+ * TODO UNHIDE
+ */
+ protected interface ColorsColumns extends SyncStateContract.Columns {
+
+ /**
+ * The type of color, which describes how it should be used. Valid types
+ * are {@link #TYPE_CALENDAR} and {@link #TYPE_EVENT}. Column name.
+ * <P>
+ * Type: INTEGER (NOT NULL)
+ * </P>
+ */
+ public static final String COLOR_TYPE = "color_type";
+
+ /**
+ * This indicateds a color that can be used for calendars.
+ */
+ public static final int TYPE_CALENDAR = 0;
+ /**
+ * This indicates a color that can be used for events.
+ */
+ public static final int TYPE_EVENT = 1;
+
+ /**
+ * The index used to reference this color. This can be any non-empty
+ * string, but must be unique for a given {@link #ACCOUNT_TYPE} and
+ * {@link #ACCOUNT_NAME} . Column name.
+ * <P>
+ * Type: TEXT
+ * </P>
+ */
+ public static final String COLOR_INDEX = "color_index";
+
+ /**
+ * The version of this color that will work with dark text as an 8-bit
+ * ARGB integer value. Colors should specify alpha as fully opaque (eg
+ * 0xFF993322) as the alpha may be ignored or modified for display.
+ * Column name.
+ * <P>
+ * Type: INTEGER (NOT NULL)
+ * </P>
+ */
+ public static final String COLOR_LIGHT = "color_light";
+
+ /**
+ * The version of this color that will work with light text as an 8-bit
+ * ARGB integer value. Colors should specify alpha as fully opaque (eg
+ * 0xFF993322) as the alpha may be ignored or modified for display.
+ * Column name.
+ * <P>
+ * Type: INTEGER (NOT NULL)
+ * </P>
+ */
+ public static final String COLOR_DARK = "color_dark";
+
+ }
+
+ /**
+ * Fields for accessing colors available for a given account. Colors are
+ * referenced by {@link #COLOR_INDEX} which must be unique for a given
+ * account name/type. These values should only be updated by the sync
+ * adapter.
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final class Colors implements ColorsColumns {
+ /**
+ * @hide
+ */
+ public static final String TABLE_NAME = "Colors";
+ /**
+ * The Uri for querying color information
+ */
+ @SuppressWarnings("hiding")
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/colors");
+
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Colors() {
+ }
+ }
+
protected interface ExtendedPropertiesColumns {
/**
* The event the extended property belongs to. Column name.
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index e93039b..4ec4bc4 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -197,16 +197,18 @@
@Override
protected boolean leftWord(TextView widget, Spannable buffer) {
final int selectionEnd = widget.getSelectionEnd();
- mWordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
- return Selection.moveToPreceding(buffer, mWordIterator, isSelecting(buffer));
+ final WordIterator wordIterator = widget.getWordIterator();
+ wordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
+ return Selection.moveToPreceding(buffer, wordIterator, isSelecting(buffer));
}
/** {@hide} */
@Override
protected boolean rightWord(TextView widget, Spannable buffer) {
final int selectionEnd = widget.getSelectionEnd();
- mWordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
- return Selection.moveToFollowing(buffer, mWordIterator, isSelecting(buffer));
+ final WordIterator wordIterator = widget.getWordIterator();
+ wordIterator.setCharSequence(buffer, selectionEnd, selectionEnd);
+ return Selection.moveToFollowing(buffer, wordIterator, isSelecting(buffer));
}
@Override
@@ -322,8 +324,6 @@
return sInstance;
}
- private WordIterator mWordIterator = new WordIterator();
-
private static final Object LAST_TAP_DOWN = new Object();
private static ArrowKeyMovementMethod sInstance;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7eae739..b9e0fe8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -425,20 +425,17 @@
}
}
+ CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
+ mTranslator = compatibilityInfo.getTranslator();
+
// If the application owns the surface, don't enable hardware acceleration
if (mSurfaceHolder == null) {
enableHardwareAcceleration(attrs);
}
- CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
- mTranslator = compatibilityInfo.getTranslator();
-
- if (mTranslator != null) {
- mSurface.setCompatibilityTranslator(mTranslator);
- }
-
boolean restore = false;
if (mTranslator != null) {
+ mSurface.setCompatibilityTranslator(mTranslator);
restore = true;
attrs.backup();
mTranslator.translateWindowLayout(attrs);
@@ -590,6 +587,9 @@
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
+ // Don't enable hardware acceleration when the application is in compatibility mode
+ if (mTranslator != null) return;
+
// Try to enable hardware acceleration if requested
final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index fe06d98..a4e0688 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -391,8 +391,6 @@
* Gets the max scroll offset of the source left edge in pixels.
*
* @return The max scroll.
- *
- * @hide
*/
public int getMaxScrollX() {
return mMaxScrollX;
@@ -401,8 +399,6 @@
* Sets the max scroll offset of the source left edge in pixels.
*
* @param maxScrollX The max scroll.
- *
- * @hide
*/
public void setMaxScrollX(int maxScrollX) {
enforceNotSealed();
@@ -413,8 +409,6 @@
* Gets the max scroll offset of the source top edge in pixels.
*
* @return The max scroll.
- *
- * @hide
*/
public int getMaxScrollY() {
return mMaxScrollY;
@@ -424,8 +418,6 @@
* Sets the max scroll offset of the source top edge in pixels.
*
* @param maxScrollY The max scroll.
- *
- * @hide
*/
public void setMaxScrollY(int maxScrollY) {
enforceNotSealed();
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index ae40ded..3d129f7 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -95,27 +95,33 @@
public void onHideCustomView() {}
/**
- * Request the host application to create a new Webview. The host
- * application should handle placement of the new WebView in the view
- * system. The default behavior returns null.
- * @param view The WebView that initiated the callback.
- * @param dialog True if the new window is meant to be a small dialog
- * window.
- * @param userGesture True if the request was initiated by a user gesture
- * such as clicking a link.
- * @param resultMsg The message to send when done creating a new WebView.
- * Set the new WebView through resultMsg.obj which is
- * WebView.WebViewTransport() and then call
- * resultMsg.sendToTarget();
- * @return Similar to javscript dialogs, this method should return true if
- * the client is going to handle creating a new WebView. Note that
- * the WebView will halt processing if this method returns true so
- * make sure to call resultMsg.sendToTarget(). It is undefined
- * behavior to call resultMsg.sendToTarget() after returning false
- * from this method.
+ * Request the host application to create a new window. If the host
+ * application chooses to honor this request, it should return true from
+ * this method, create a new WebView to host the window, insert it into the
+ * View system and send the supplied resultMsg message to its target with
+ * the new WebView as an argument. If the host application chooses not to
+ * honor the request, it should return false from this method. The default
+ * implementation of this method does nothing and hence returns false.
+ * @param view The WebView from which the request for a new window
+ * originated.
+ * @param isDialog True if the new window should be a dialog, rather than
+ * a full-size window.
+ * @param isUserGesture True if the request was initiated by a user gesture,
+ * such as the user clicking a link.
+ * @param resultMsg The message to send when once a new WebView has been
+ * created. resultMsg.obj is a
+ * {@link WebView.WebViewTransport} object. This should be
+ * used to transport the new WebView, by calling
+ * {@link WebView.WebViewTransport#setWebView(WebView)
+ * WebView.WebViewTransport.setWebView(WebView)}.
+ * @return This method should return true if the host application will
+ * create a new window, in which case resultMsg should be sent to
+ * its target. Otherwise, this method should return false. Returning
+ * false from this method but also sending resultMsg will result in
+ * undefined behavior.
*/
- public boolean onCreateWindow(WebView view, boolean dialog,
- boolean userGesture, Message resultMsg) {
+ public boolean onCreateWindow(WebView view, boolean isDialog,
+ boolean isUserGesture, Message resultMsg) {
return false;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 48615bd..cf6e187 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2003,15 +2003,18 @@
}
/**
- * Load the given url with the extra headers.
- * @param url The url of the resource to load.
- * @param extraHeaders The extra headers sent with this url. This should not
- * include the common headers like "user-agent". If it does, it
- * will be replaced by the intrinsic value of the WebView.
+ * Load the given URL with the specified additional HTTP headers.
+ * @param url The URL of the resource to load.
+ * @param additionalHttpHeaders The additional headers to be used in the
+ * HTTP request for this URL, specified as a map from name to
+ * value. Note that if this map contains any of the headers
+ * that are set by default by the WebView, such as those
+ * controlling caching, accept types or the User-Agent, their
+ * values may be overriden by the WebView's defaults.
*/
- public void loadUrl(String url, Map<String, String> extraHeaders) {
+ public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
checkThread();
- loadUrlImpl(url, extraHeaders);
+ loadUrlImpl(url, additionalHttpHeaders);
}
private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
@@ -2024,8 +2027,8 @@
}
/**
- * Load the given url.
- * @param url The url of the resource to load.
+ * Load the given URL.
+ * @param url The URL of the resource to load.
*/
public void loadUrl(String url) {
checkThread();
@@ -4501,6 +4504,9 @@
if (mHeldMotionless == MOTIONLESS_FALSE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(AWAKEN_SCROLL_BARS),
+ ViewConfiguration.getScrollDefaultDelay());
mHeldMotionless = MOTIONLESS_PENDING;
}
}
@@ -5998,6 +6004,7 @@
mTouchMode = TOUCH_DRAG_START_MODE;
mConfirmMove = true;
mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
+ nativeSetIsScrolling(false);
} else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
@@ -6280,9 +6287,16 @@
}
mLastTouchX = x;
mLastTouchY = y;
- if ((deltaX | deltaY) != 0) {
+
+ if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) {
mHeldMotionless = MOTIONLESS_FALSE;
+ nativeSetIsScrolling(true);
+ } else {
+ mHeldMotionless = MOTIONLESS_TRUE;
+ nativeSetIsScrolling(false);
+ keepScrollBarsVisible = true;
}
+
mLastTouchTime = eventTime;
}
@@ -6298,9 +6312,15 @@
// keep the scrollbar on the screen even there is no scroll
awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
false);
+ // Post a message so that we'll keep them alive while we're not scrolling.
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(AWAKEN_SCROLL_BARS),
+ ViewConfiguration.getScrollDefaultDelay());
// return false to indicate that we can't pan out of the
// view space
return !done;
+ } else {
+ mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
}
break;
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 510e2d4..5fbbe4d 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -32,6 +32,7 @@
import com.android.internal.util.ArrayUtils;
import java.text.BreakIterator;
+import java.util.Locale;
/**
@@ -45,7 +46,7 @@
private final TextView mTextView;
- final SpellCheckerSession mSpellCheckerSession;
+ SpellCheckerSession mSpellCheckerSession;
final int mCookie;
// Paired arrays for the (id, spellCheckSpan) pair. A negative id means the associated
@@ -61,23 +62,54 @@
private int mSpanSequenceCounter = 0;
+ private Locale mCurrentLocale;
+
+ // Shared by all SpellParsers. Cannot be shared with TextView since it may be used
+ // concurrently due to the asynchronous nature of onGetSuggestions.
+ private WordIterator mWordIterator;
+
public SpellChecker(TextView textView) {
mTextView = textView;
- final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
- getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
- mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
- null /* not currently used by the textServicesManager */,
- null /* null locale means use the languages defined in Settings
- if referToSpellCheckerLanguageSettings is true */,
- this, true /* means use the languages defined in Settings */);
- mCookie = hashCode();
-
- // Arbitrary: 4 simultaneous spell check spans. Will automatically double size on demand
+ // Arbitrary: these arrays will automatically double their sizes on demand
final int size = ArrayUtils.idealObjectArraySize(1);
mIds = new int[size];
mSpellCheckSpans = new SpellCheckSpan[size];
+
+ setLocale(mTextView.getLocale());
+
+ mCookie = hashCode();
+ }
+
+ private void setLocale(Locale locale) {
+ final TextServicesManager textServicesManager = (TextServicesManager)
+ mTextView.getContext().getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+ mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
+ null /* Bundle not currently used by the textServicesManager */,
+ locale, this, false /* means any available languages from current spell checker */);
+ mCurrentLocale = locale;
+
+ // Restore SpellCheckSpans in pool
+ for (int i = 0; i < mLength; i++) {
+ mSpellCheckSpans[i].setSpellCheckInProgress(false);
+ mIds[i] = -1;
+ }
mLength = 0;
+
+ // Change SpellParsers' wordIterator locale
+ mWordIterator = new WordIterator(locale);
+
+ // Stop all SpellParsers
+ final int length = mSpellParsers.length;
+ for (int i = 0; i < length; i++) {
+ mSpellParsers[i].finish();
+ }
+
+ // Remove existing misspelled SuggestionSpans
+ mTextView.removeMisspelledSpans((Editable) mTextView.getText());
+
+ // This class is the listener for locale change: warn other locale-aware objects
+ mTextView.onLocaleChanged();
}
/**
@@ -95,7 +127,7 @@
final int length = mSpellParsers.length;
for (int i = 0; i < length; i++) {
- mSpellParsers[i].close();
+ mSpellParsers[i].finish();
}
}
@@ -140,12 +172,20 @@
}
public void spellCheck(int start, int end) {
+ final Locale locale = mTextView.getLocale();
+ if (mCurrentLocale == null || (!(mCurrentLocale.equals(locale)))) {
+ setLocale(locale);
+ // Re-check the entire text
+ start = 0;
+ end = mTextView.getText().length();
+ }
+
if (!isSessionActive()) return;
final int length = mSpellParsers.length;
for (int i = 0; i < length; i++) {
final SpellParser spellParser = mSpellParsers[i];
- if (spellParser.isDone()) {
+ if (spellParser.isFinished()) {
spellParser.init(start, end);
spellParser.parse();
return;
@@ -229,7 +269,7 @@
final int length = mSpellParsers.length;
for (int i = 0; i < length; i++) {
final SpellParser spellParser = mSpellParsers[i];
- if (!spellParser.isDone()) {
+ if (!spellParser.isFinished()) {
spellParser.parse();
}
}
@@ -239,6 +279,7 @@
SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
final int start = editable.getSpanStart(spellCheckSpan);
final int end = editable.getSpanEnd(spellCheckSpan);
+ if (start < 0 || end < 0) return; // span was removed in the meantime
// Other suggestion spans may exist on that region, with identical suggestions, filter
// them out to avoid duplicates. First, filter suggestion spans on that exact region.
@@ -249,7 +290,6 @@
final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
if (spanStart != start || spanEnd != end) {
suggestionSpans[i] = null;
- break;
}
}
@@ -301,7 +341,6 @@
}
private class SpellParser {
- private WordIterator mWordIterator = new WordIterator(/*TODO Locale*/);
private Object mRange = new Object();
public void init(int start, int end) {
@@ -309,11 +348,11 @@
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- public void close() {
+ public void finish() {
((Editable) mTextView.getText()).removeSpan(mRange);
}
- public boolean isDone() {
+ public boolean isFinished() {
return ((Editable) mTextView.getText()).getSpanStart(mRange) < 0;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a21a087..55e49ea 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -132,6 +132,7 @@
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.RemoteViews.RemoteView;
@@ -147,6 +148,7 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.Locale;
/**
* Displays text to the user and optionally allows them to edit it. A TextView
@@ -357,6 +359,8 @@
private SpellChecker mSpellChecker;
+ private boolean mShowSoftInputOnFocus = true;
+
// The alignment to pass to Layout, or null if not resolved.
private Layout.Alignment mLayoutAlignment;
@@ -605,6 +609,12 @@
mLinksClickable = a.getBoolean(attr, true);
break;
+// TODO uncomment when this attribute is made public in the next release
+// also add TextView_showSoftInputOnFocus to the list of attributes above
+// case com.android.internal.R.styleable.TextView_showSoftInputOnFocus:
+// setShowSoftInputOnFocus(a.getBoolean(attr, true));
+// break;
+
case com.android.internal.R.styleable.TextView_drawableLeft:
drawableLeft = a.getDrawable(attr);
break;
@@ -2368,6 +2378,29 @@
}
/**
+ * Sets whether the soft input method will be made visible when this
+ * TextView gets focused. The default is true.
+ *
+ * @attr ref android.R.styleable#TextView_showSoftInputOnFocus
+ * @hide
+ */
+ @android.view.RemotableViewMethod
+ public final void setShowSoftInputOnFocus(boolean show) {
+ mShowSoftInputOnFocus = show;
+ }
+
+ /**
+ * Returns whether the soft input method will be made visible when this
+ * TextView gets focused. The default is true.
+ *
+ * @attr ref android.R.styleable#TextView_showSoftInputOnFocus
+ * @hide
+ */
+ public final boolean getShowSoftInputOnFocus() {
+ return mShowSoftInputOnFocus;
+ }
+
+ /**
* Returns the list of URLSpans attached to the text
* (by {@link Linkify} or otherwise) if any. You can call
* {@link URLSpan#getURL} on them to find where they link to
@@ -2942,15 +2975,7 @@
sp.removeSpan(cw);
}
- SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);
- for (int i = 0; i < suggestionSpans.length; i++) {
- int flags = suggestionSpans[i].getFlags();
- if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
- && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
- sp.removeSpan(suggestionSpans[i]);
- }
- }
-
+ removeMisspelledSpans(sp);
sp.removeSpan(mSuggestionRangeSpan);
ss.text = sp;
@@ -2970,6 +2995,18 @@
return superState;
}
+ void removeMisspelledSpans(Spannable spannable) {
+ SuggestionSpan[] suggestionSpans = spannable.getSpans(0, spannable.length(),
+ SuggestionSpan.class);
+ for (int i = 0; i < suggestionSpans.length; i++) {
+ int flags = suggestionSpans[i].getFlags();
+ if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
+ && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+ spannable.removeSpan(suggestionSpans[i]);
+ }
+ }
+ }
+
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
@@ -5465,7 +5502,7 @@
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
viewClicked(imm);
- if (imm != null) {
+ if (imm != null && mShowSoftInputOnFocus) {
imm.showSoftInput(this, 0);
}
}
@@ -8207,6 +8244,9 @@
}
hideControllers();
+ if (mSuggestionsPopupWindow != null) {
+ mSuggestionsPopupWindow.onParentLostFocus();
+ }
}
startStopMarquee(hasWindowFocus);
@@ -8304,7 +8344,7 @@
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();
viewClicked(imm);
- if (!mTextIsSelectable) {
+ if (!mTextIsSelectable && mShowSoftInputOnFocus) {
handled |= imm != null && imm.showSoftInput(this, 0);
}
@@ -8840,15 +8880,13 @@
selectionStart = ((Spanned) mText).getSpanStart(urlSpan);
selectionEnd = ((Spanned) mText).getSpanEnd(urlSpan);
} else {
- if (mWordIterator == null) {
- mWordIterator = new WordIterator();
- }
- mWordIterator.setCharSequence(mText, minOffset, maxOffset);
+ final WordIterator wordIterator = getWordIterator();
+ wordIterator.setCharSequence(mText, minOffset, maxOffset);
- selectionStart = mWordIterator.getBeginning(minOffset);
+ selectionStart = wordIterator.getBeginning(minOffset);
if (selectionStart == BreakIterator.DONE) return false;
- selectionEnd = mWordIterator.getEnd(maxOffset);
+ selectionEnd = wordIterator.getEnd(maxOffset);
if (selectionEnd == BreakIterator.DONE) return false;
if (selectionStart == selectionEnd) {
@@ -8863,6 +8901,43 @@
return selectionEnd > selectionStart;
}
+ /**
+ * This is a temporary method. Future versions may support multi-locale text.
+ *
+ * @return The current locale used in this TextView, based on the current IME's locale,
+ * or the system default locale if this is not defined.
+ * @hide
+ */
+ public Locale getLocale() {
+ Locale locale = Locale.getDefault();
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ final InputMethodSubtype currentInputMethodSubtype = imm.getCurrentInputMethodSubtype();
+ if (currentInputMethodSubtype != null) {
+ String localeString = currentInputMethodSubtype.getLocale();
+ if (!TextUtils.isEmpty(localeString)) {
+ locale = new Locale(localeString);
+ }
+ }
+ }
+ return locale;
+ }
+
+ void onLocaleChanged() {
+ // Will be re-created on demand in getWordIterator with the proper new locale
+ mWordIterator = null;
+ }
+
+ /**
+ * @hide
+ */
+ public WordIterator getWordIterator() {
+ if (mWordIterator == null) {
+ mWordIterator = new WordIterator(getLocale());
+ }
+ return mWordIterator;
+ }
+
private long getCharRange(int offset) {
final int textLength = mText.length();
if (offset + 1 < textLength) {
@@ -9547,6 +9622,7 @@
private SuggestionInfo[] mSuggestionInfos;
private int mNumberOfSuggestions;
private boolean mCursorWasVisibleBeforeSuggestions;
+ private boolean mIsShowingUp = false;
private SuggestionAdapter mSuggestionsAdapter;
private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
private final HashMap<SuggestionSpan, Integer> mSpansLengths;
@@ -9602,6 +9678,14 @@
}
}
+ public boolean isShowingUp() {
+ return mIsShowingUp;
+ }
+
+ public void onParentLostFocus() {
+ mIsShowingUp = false;
+ }
+
private class SuggestionInfo {
int suggestionStart, suggestionEnd; // range of actual suggestion within text
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
@@ -9609,15 +9693,6 @@
SpannableStringBuilder text = new SpannableStringBuilder();
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext,
android.R.style.TextAppearance_SuggestionHighlight);
-
- void removeMisspelledFlag() {
- int suggestionSpanFlags = suggestionSpan.getFlags();
- if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
- suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
- suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
- suggestionSpan.setFlags(suggestionSpanFlags);
- }
- }
}
private class SuggestionAdapter extends BaseAdapter {
@@ -9714,6 +9789,7 @@
updateSuggestions();
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
setCursorVisible(false);
+ mIsShowingUp = true;
super.show();
}
@@ -9891,14 +9967,16 @@
if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
final int spanUnionStart = editable.getSpanStart(mSuggestionRangeSpan);
int spanUnionEnd = editable.getSpanEnd(mSuggestionRangeSpan);
- // Do not leave two adjacent spaces after deletion, or one at beginning of text
- if (spanUnionEnd < editable.length() &&
- Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
- (spanUnionStart == 0 ||
- Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
+ if (spanUnionStart >= 0 && spanUnionEnd > spanUnionStart) {
+ // Do not leave two adjacent spaces after deletion, or one at beginning of text
+ if (spanUnionEnd < editable.length() &&
+ Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
+ (spanUnionStart == 0 ||
+ Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
spanUnionEnd = spanUnionEnd + 1;
+ }
+ editable.replace(spanUnionStart, spanUnionEnd, "");
}
- editable.replace(spanUnionStart, spanUnionEnd, "");
hide();
return;
}
@@ -9933,6 +10011,14 @@
suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
+
+ // Remove potential misspelled flags
+ int suggestionSpanFlags = suggestionSpan.getFlags();
+ if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
+ suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
+ suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
+ suggestionSpan.setFlags(suggestionSpanFlags);
+ }
}
final int suggestionStart = suggestionInfo.suggestionStart;
@@ -9941,8 +10027,6 @@
suggestionStart, suggestionEnd).toString();
editable.replace(spanStart, spanEnd, suggestion);
- suggestionInfo.removeMisspelledFlag();
-
// Notify source IME of the suggestion pick. Do this before swaping texts.
if (!TextUtils.isEmpty(
suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
@@ -10118,7 +10202,7 @@
final boolean selectionStarted = mSelectionActionMode != null ||
extractedTextModeWillBeStartedFullScreen;
- if (selectionStarted && !mTextIsSelectable && imm != null) {
+ if (selectionStarted && !mTextIsSelectable && imm != null && mShowSoftInputOnFocus) {
// Show the IME to be able to replace text, except when selecting non editable text.
imm.showSoftInput(this, 0, null);
}
@@ -11118,6 +11202,10 @@
}
private void hideCursorControllers() {
+ if (mSuggestionsPopupWindow != null && !mSuggestionsPopupWindow.isShowingUp()) {
+ // Should be done before hide insertion point controller since it triggers a show of it
+ mSuggestionsPopupWindow.hide();
+ }
hideInsertionPointCursorController();
stopSelectionActionMode();
}
diff --git a/core/java/com/android/internal/view/menu/ExpandedMenuView.java b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
index 723ece4..47058ad 100644
--- a/core/java/com/android/internal/view/menu/ExpandedMenuView.java
+++ b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
@@ -63,11 +63,6 @@
setChildrenDrawingCacheEnabled(false);
}
- @Override
- protected boolean recycleOnMeasure() {
- return false;
- }
-
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index a1e16d4..df579c69 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -34,6 +34,7 @@
* The item view for each item in the ListView-based MenuViews.
*/
public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
+ private static final String TAG = "ListMenuItemView";
private MenuItemImpl mItemData;
private ImageView mIconView;
@@ -121,27 +122,25 @@
}
public void setCheckable(boolean checkable) {
-
if (!checkable && mRadioButton == null && mCheckBox == null) {
return;
}
- if (mRadioButton == null) {
- insertRadioButton();
- }
- if (mCheckBox == null) {
- insertCheckBox();
- }
-
// Depending on whether its exclusive check or not, the checkbox or
// radio button will be the one in use (and the other will be otherCompoundButton)
final CompoundButton compoundButton;
final CompoundButton otherCompoundButton;
if (mItemData.isExclusiveCheckable()) {
+ if (mRadioButton == null) {
+ insertRadioButton();
+ }
compoundButton = mRadioButton;
otherCompoundButton = mCheckBox;
} else {
+ if (mCheckBox == null) {
+ insertCheckBox();
+ }
compoundButton = mCheckBox;
otherCompoundButton = mRadioButton;
}
@@ -155,12 +154,12 @@
}
// Make sure the other compound button isn't visible
- if (otherCompoundButton.getVisibility() != GONE) {
+ if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) {
otherCompoundButton.setVisibility(GONE);
}
} else {
- mCheckBox.setVisibility(GONE);
- mRadioButton.setVisibility(GONE);
+ if (mCheckBox != null) mCheckBox.setVisibility(GONE);
+ if (mRadioButton != null) mRadioButton.setVisibility(GONE);
}
}
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 722aeea..4a9fcf2 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -57,8 +57,7 @@
jniThrowException(env, "java/lang/IllegalStateException", msg.string());
}
-static jint nativeCreate(JNIEnv* env, jclass clazz,
- jstring nameObj, jint cursorWindowSize, jboolean localOnly) {
+static jint nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
String8 name;
if (nameObj) {
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
@@ -70,7 +69,7 @@
}
CursorWindow* window;
- status_t status = CursorWindow::create(name, cursorWindowSize, localOnly, &window);
+ status_t status = CursorWindow::create(name, cursorWindowSize, &window);
if (status || !window) {
LOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
name.string(), cursorWindowSize, status);
@@ -477,7 +476,7 @@
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
- { "nativeCreate", "(Ljava/lang/String;IZ)I",
+ { "nativeCreate", "(Ljava/lang/String;I)I",
(void*)nativeCreate },
{ "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",
(void*)nativeCreateFromParcel },
diff --git a/core/tests/coretests/src/android/database/CursorWindowTest.java b/core/tests/coretests/src/android/database/CursorWindowTest.java
index 07e75cb..8c8081c 100644
--- a/core/tests/coretests/src/android/database/CursorWindowTest.java
+++ b/core/tests/coretests/src/android/database/CursorWindowTest.java
@@ -16,17 +16,11 @@
package android.database;
-import android.database.AbstractCursor;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.common.ArrayListCursor;
import android.database.CursorWindow;
import android.test.PerformanceTestCase;
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Random;
import junit.framework.TestCase;
@@ -41,48 +35,6 @@
}
@SmallTest
- public void testWriteCursorToWindow() throws Exception {
- // create cursor
- String[] colNames = new String[]{"name", "number", "profit"};
- int colsize = colNames.length;
- ArrayList<ArrayList> list = createTestList(10, colsize);
- AbstractCursor cursor = new ArrayListCursor(colNames, (ArrayList<ArrayList>) list);
-
- // fill window
- CursorWindow window = new CursorWindow(false);
- cursor.fillWindow(0, window);
-
- // read from cursor window
- for (int i = 0; i < list.size(); i++) {
- ArrayList<Integer> col = list.get(i);
- for (int j = 0; j < colsize; j++) {
- String s = window.getString(i, j);
- int r2 = col.get(j);
- int r1 = Integer.parseInt(s);
- assertEquals(r2, r1);
- }
- }
-
- // test cursor window handle startpos != 0
- window.clear();
- cursor.fillWindow(1, window);
- // read from cursor from window
- for (int i = 1; i < list.size(); i++) {
- ArrayList<Integer> col = list.get(i);
- for (int j = 0; j < colsize; j++) {
- String s = window.getString(i, j);
- int r2 = col.get(j);
- int r1 = Integer.parseInt(s);
- assertEquals(r2, r1);
- }
- }
-
- // Clear the window and make sure it's empty
- window.clear();
- assertEquals(0, window.getNumRows());
- }
-
- @SmallTest
public void testValuesLocalWindow() {
doTestValues(new CursorWindow(true));
}
@@ -124,50 +76,4 @@
assertTrue(window.putBlob(blob, 0, 6));
assertTrue(Arrays.equals(blob, window.getBlob(0, 6)));
}
-
- @SmallTest
- public void testNull() {
- CursorWindow window = getOneByOneWindow();
-
- // Put in a null value and read it back as various types
- assertTrue(window.putNull(0, 0));
- assertNull(window.getString(0, 0));
- assertEquals(0, window.getLong(0, 0));
- assertEquals(0.0, window.getDouble(0, 0));
- assertNull(window.getBlob(0, 0));
- }
-
- @SmallTest
- public void testEmptyString() {
- CursorWindow window = getOneByOneWindow();
-
- // put size 0 string and read it back as various types
- assertTrue(window.putString("", 0, 0));
- assertEquals("", window.getString(0, 0));
- assertEquals(0, window.getLong(0, 0));
- assertEquals(0.0, window.getDouble(0, 0));
- }
-
- private CursorWindow getOneByOneWindow() {
- CursorWindow window = new CursorWindow(false);
- assertTrue(window.setNumColumns(1));
- assertTrue(window.allocRow());
- return window;
- }
-
- private static ArrayList<ArrayList> createTestList(int rows, int cols) {
- ArrayList<ArrayList> list = Lists.newArrayList();
- Random generator = new Random();
-
- for (int i = 0; i < rows; i++) {
- ArrayList<Integer> col = Lists.newArrayList();
- list.add(col);
- for (int j = 0; j < cols; j++) {
- // generate random number
- Integer r = generator.nextInt();
- col.add(r);
- }
- }
- return list;
- }
}
diff --git a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
index 2ed7c52..417a85f 100644
--- a/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
+++ b/core/tests/coretests/src/android/webkit/AccessibilityInjectorTest.java
@@ -1677,7 +1677,7 @@
}
});
}
- mWebView.loadData(html, "text/html", "utf-8");
+ mWebView.loadData(html, "text/html", null);
}
});
synchronized (sTestLock) {
diff --git a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
index 7726f02..62466f1 100644
--- a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
@@ -16,11 +16,11 @@
package android.widget;
-import com.android.common.ArrayListCursor;
import com.google.android.collect.Lists;
import android.content.Context;
import android.database.Cursor;
+import android.database.MatrixCursor;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -52,14 +52,14 @@
super.setUp();
// all the pieces needed for the various tests
- mFrom = new String[]{"Column1", "Column2"};
+ mFrom = new String[]{"Column1", "Column2", "_id"};
mTo = new int[]{com.android.internal.R.id.text1, com.android.internal.R.id.text2};
mLayout = com.android.internal.R.layout.simple_list_item_2;
mContext = getContext();
// raw data for building a basic test cursor
mData2x2 = createTestList(2, 2);
- mCursor2x2 = new ArrayListCursor(mFrom, mData2x2);
+ mCursor2x2 = createCursor(mFrom, mData2x2);
}
/**
@@ -77,6 +77,7 @@
Integer r = generator.nextInt();
col.add(r);
}
+ col.add(i);
}
return list;
}
@@ -115,7 +116,7 @@
// now put in a different cursor (5 rows)
ArrayList<ArrayList> data2 = createTestList(5, 2);
- Cursor c2 = new ArrayListCursor(mFrom, data2);
+ Cursor c2 = createCursor(mFrom, data2);
ca.changeCursor(c2);
// Now see if we can pull 5 rows from the adapter
@@ -155,8 +156,8 @@
assertEquals(columns[1], 1);
// Now make a new cursor with similar data but rearrange the columns
- String[] swappedFrom = new String[]{"Column2", "Column1"};
- Cursor c2 = new ArrayListCursor(swappedFrom, mData2x2);
+ String[] swappedFrom = new String[]{"Column2", "Column1", "_id"};
+ Cursor c2 = createCursor(swappedFrom, mData2x2);
ca.changeCursor(c2);
assertEquals(2, ca.getCount());
@@ -235,7 +236,15 @@
assertEquals(1, viewIds.length);
assertEquals(com.android.internal.R.id.text2, viewIds[0]);
}
-
+
+ private static MatrixCursor createCursor(String[] columns, ArrayList<ArrayList> list) {
+ MatrixCursor cursor = new MatrixCursor(columns, list.size());
+ for (ArrayList row : list) {
+ cursor.addRow(row);
+ }
+ return cursor;
+ }
+
/**
* This is simply a way to sneak a look at the protected mFrom() array. A more API-
* friendly way to do this would be to mock out a View and a ViewBinder and exercise
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
index 5de4ad5..5c891f9 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
@@ -120,7 +120,6 @@
}
final String mimeType = "text/html";
- final String encoding = "utf-8";
@Override
@@ -137,7 +136,7 @@
subject.setText(message.getSubject());
WebView body = (WebView) messageUi.findViewById(R.id.body);
- body.loadData(message.getBody(), mimeType, encoding);
+ body.loadData(message.getBody(), mimeType, null);
// body.setText(message.getBody());
body.setFocusable(message.isFocusable());
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index 564f41c..c964961 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -24,6 +24,3 @@
PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\
frameworks/base/data/keyboards/$(file):system/usr/idc/$(file))
-
-PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs)
-
diff --git a/docs/html/guide/topics/fundamentals/fragments.jd b/docs/html/guide/topics/fundamentals/fragments.jd
index 8f61945..d34a798 100644
--- a/docs/html/guide/topics/fundamentals/fragments.jd
+++ b/docs/html/guide/topics/fundamentals/fragments.jd
@@ -117,7 +117,7 @@
two
fragments in <em>Activity A</em>, when running on an extra large screen (a tablet, for example).
However, on a normal-sized screen (a phone, for example),
-there's not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
+there would not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
the list of articles, and when the user selects an article, it starts <em>Activity B</em>, which
includes the fragment to read the article. Thus, the application supports both design patterns
suggested in figure 1.</p>
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index 5d490ed..f0284de 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -80,8 +80,7 @@
~CursorWindow();
- static status_t create(const String8& name, size_t size, bool localOnly,
- CursorWindow** outCursorWindow);
+ static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow);
static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);
status_t writeToParcel(Parcel* parcel);
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 3e48459..2eb259e 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -31,7 +31,9 @@
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
-extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG; // layer III
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
@@ -47,6 +49,7 @@
extern const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index ea022a6..1242e49 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -83,7 +83,11 @@
eOrientationUnchanged = 4,
eOrientationSwapMask = 0x01
};
-
+
+ enum {
+ eSynchronous = 0x01,
+ };
+
enum {
eElectronBeamAnimationOn = 0x01,
eElectronBeamAnimationOff = 0x10
@@ -103,7 +107,7 @@
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual void setTransactionState(const Vector<ComposerState>& state,
- int orientation) = 0;
+ int orientation, uint32_t flags) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -142,8 +146,6 @@
GET_CBLK,
SET_TRANSACTION_STATE,
SET_ORIENTATION,
- FREEZE_DISPLAY,
- UNFREEZE_DISPLAY,
CAPTURE_SCREEN,
TURN_ELECTRON_BEAM_OFF,
TURN_ELECTRON_BEAM_ON,
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 14e5b23..8226abe 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -112,7 +112,7 @@
static void openGlobalTransaction();
//! Close a composer transaction on all active SurfaceComposerClients.
- static void closeGlobalTransaction();
+ static void closeGlobalTransaction(bool synchronous = false);
//! Freeze the specified display but not transactions.
static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0);
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index e1ee8eb..a42ce21 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -20,12 +20,13 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
+#include <cutils/compiler.h>
namespace android {
// ---------------------------------------------------------------------------
template <typename TYPE>
-class Singleton
+class ANDROID_API Singleton
{
public:
static TYPE& getInstance() {
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index 1b85a71..bf8d7a6 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -40,11 +40,9 @@
::close(mAshmemFd);
}
-status_t CursorWindow::create(const String8& name, size_t size, bool localOnly,
- CursorWindow** outCursorWindow) {
+status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
String8 ashmemName("CursorWindow: ");
ashmemName.append(name);
- ashmemName.append(localOnly ? " (local)" : " (remote)");
status_t result;
int ashmemFd = ashmem_create_region(ashmemName.string(), size);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index eb90147..86bc62a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -79,7 +79,7 @@
}
virtual void setTransactionState(const Vector<ComposerState>& state,
- int orientation)
+ int orientation, uint32_t flags)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -90,6 +90,7 @@
b->write(data);
}
data.writeInt32(orientation);
+ data.writeInt32(flags);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -204,7 +205,8 @@
state.add(s);
}
int orientation = data.readInt32();
- setTransactionState(state, orientation);
+ uint32_t flags = data.readInt32();
+ setTransactionState(state, orientation, flags);
} break;
case BOOT_FINISHED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5f3d608..4ad6c22 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -92,11 +92,14 @@
mutable Mutex mLock;
SortedVector<ComposerState> mStates;
int mOrientation;
+ uint32_t mForceSynchronous;
Composer() : Singleton<Composer>(),
- mOrientation(ISurfaceComposer::eOrientationUnchanged) { }
+ mOrientation(ISurfaceComposer::eOrientationUnchanged),
+ mForceSynchronous(0)
+ { }
- void closeGlobalTransactionImpl();
+ void closeGlobalTransactionImpl(bool synchronous);
layer_state_t* getLayerStateLocked(
const sp<SurfaceComposerClient>& client, SurfaceID id);
@@ -123,8 +126,8 @@
uint32_t tint);
status_t setOrientation(int orientation);
- static void closeGlobalTransaction() {
- Composer::getInstance().closeGlobalTransactionImpl();
+ static void closeGlobalTransaction(bool synchronous) {
+ Composer::getInstance().closeGlobalTransactionImpl(synchronous);
}
};
@@ -132,11 +135,12 @@
// ---------------------------------------------------------------------------
-void Composer::closeGlobalTransactionImpl() {
+void Composer::closeGlobalTransactionImpl(bool synchronous) {
sp<ISurfaceComposer> sm(getComposerService());
Vector<ComposerState> transaction;
int orientation;
+ uint32_t flags = 0;
{ // scope for the lock
Mutex::Autolock _l(mLock);
@@ -145,9 +149,14 @@
orientation = mOrientation;
mOrientation = ISurfaceComposer::eOrientationUnchanged;
+
+ if (synchronous || mForceSynchronous) {
+ flags |= ISurfaceComposer::eSynchronous;
+ }
+ mForceSynchronous = false;
}
- sm->setTransactionState(transaction, orientation);
+ sm->setTransactionState(transaction, orientation, flags);
}
layer_state_t* Composer::getLayerStateLocked(
@@ -188,6 +197,10 @@
s->what |= ISurfaceComposer::eSizeChanged;
s->w = w;
s->h = h;
+
+ // Resizing a surface makes the transaction synchronous.
+ mForceSynchronous = true;
+
return NO_ERROR;
}
@@ -270,6 +283,10 @@
status_t Composer::setOrientation(int orientation) {
Mutex::Autolock _l(mLock);
mOrientation = orientation;
+
+ // Changing the orientation makes the transaction synchronous.
+ mForceSynchronous = true;
+
return NO_ERROR;
}
@@ -375,8 +392,8 @@
// Currently a no-op
}
-void SurfaceComposerClient::closeGlobalTransaction() {
- Composer::closeGlobalTransaction();
+void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
+ Composer::closeGlobalTransaction(synchronous);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a98e4cd..9bfc94c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -39,6 +39,7 @@
external/skia/include/utils
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+ LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
LOCAL_MODULE := libhwui
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index cdcbf21..9b0d7c6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -23,6 +23,8 @@
#include <utils/Singleton.h>
+#include <cutils/compiler.h>
+
#include "Extensions.h"
#include "FontRenderer.h"
#include "GammaFontRenderer.h"
@@ -82,7 +84,7 @@
// Caches
///////////////////////////////////////////////////////////////////////////////
-class Caches: public Singleton<Caches> {
+class ANDROID_API Caches: public Singleton<Caches> {
Caches();
~Caches();
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
index bf16f29..5d689bb 100644
--- a/libs/hwui/DisplayListLogBuffer.h
+++ b/libs/hwui/DisplayListLogBuffer.h
@@ -18,6 +18,7 @@
#define ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
#include <utils/Singleton.h>
+
#include <stdio.h>
namespace android {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 8cd7fea..ab475bf 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -26,6 +26,8 @@
#include <SkTDArray.h>
#include <SkTSearch.h>
+#include <cutils/compiler.h>
+
#include "DisplayListLogBuffer.h"
#include "OpenGLRenderer.h"
#include "utils/Functor.h"
@@ -58,7 +60,7 @@
class DisplayList {
public:
DisplayList(const DisplayListRenderer& recorder);
- ~DisplayList();
+ ANDROID_API ~DisplayList();
// IMPORTANT: Update the intialization of OP_NAMES in the .cpp file
// when modifying this file
@@ -107,13 +109,13 @@
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
- size_t getSize();
+ ANDROID_API size_t getSize();
bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
void output(OpenGLRenderer& renderer, uint32_t level = 0);
- static void outputLogBuffer(int fd);
+ ANDROID_API static void outputLogBuffer(int fd);
void setRenderable(bool renderable) {
mIsRenderable = renderable;
@@ -230,75 +232,76 @@
*/
class DisplayListRenderer: public OpenGLRenderer {
public:
- DisplayListRenderer();
- ~DisplayListRenderer();
+ ANDROID_API DisplayListRenderer();
+ virtual ~DisplayListRenderer();
- DisplayList* getDisplayList(DisplayList* displayList);
+ ANDROID_API DisplayList* getDisplayList(DisplayList* displayList);
- void setViewport(int width, int height);
- void prepareDirty(float left, float top, float right, float bottom, bool opaque);
- void finish();
+ virtual void setViewport(int width, int height);
+ virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual void finish();
- bool callDrawGLFunction(Functor *functor, Rect& dirty);
+ virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
- void interrupt();
- void resume();
+ virtual void interrupt();
+ virtual void resume();
- int save(int flags);
- void restore();
- void restoreToCount(int saveCount);
+ virtual int save(int flags);
+ virtual void restore();
+ virtual void restoreToCount(int saveCount);
- int saveLayer(float left, float top, float right, float bottom,
+ virtual int saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags);
- int saveLayerAlpha(float left, float top, float right, float bottom,
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
- void translate(float dx, float dy);
- void rotate(float degrees);
- void scale(float sx, float sy);
- void skew(float sx, float sy);
+ virtual void translate(float dx, float dy);
+ virtual void rotate(float degrees);
+ virtual void scale(float sx, float sy);
+ virtual void skew(float sx, float sy);
- void setMatrix(SkMatrix* matrix);
- void concatMatrix(SkMatrix* matrix);
+ virtual void setMatrix(SkMatrix* matrix);
+ virtual void concatMatrix(SkMatrix* matrix);
- bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+ virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
- bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
+ virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
Rect& dirty, uint32_t level = 0);
- void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
- void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
- void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
- void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+ virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
+ virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
+ virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
+ virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, SkPaint* paint);
- void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
+ virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint);
- void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+ virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
float left, float top, float right, float bottom, SkPaint* paint);
- void drawColor(int color, SkXfermode::Mode mode);
- void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
- void drawRoundRect(float left, float top, float right, float bottom,
+ virtual void drawColor(int color, SkXfermode::Mode mode);
+ virtual void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
+ virtual void drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, SkPaint* paint);
- void drawCircle(float x, float y, float radius, SkPaint* paint);
- void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
- void drawArc(float left, float top, float right, float bottom,
+ virtual void drawCircle(float x, float y, float radius, SkPaint* paint);
+ virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
+ virtual void drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
- void drawPath(SkPath* path, SkPaint* paint);
- void drawLines(float* points, int count, SkPaint* paint);
- void drawPoints(float* points, int count, SkPaint* paint);
- void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
+ virtual void drawPath(SkPath* path, SkPaint* paint);
+ virtual void drawLines(float* points, int count, SkPaint* paint);
+ virtual void drawPoints(float* points, int count, SkPaint* paint);
+ virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
+ SkPaint* paint);
- void resetShader();
- void setupShader(SkiaShader* shader);
+ virtual void resetShader();
+ virtual void setupShader(SkiaShader* shader);
- void resetColorFilter();
- void setupColorFilter(SkiaColorFilter* filter);
+ virtual void resetColorFilter();
+ virtual void setupColorFilter(SkiaColorFilter* filter);
- void resetShadow();
- void setupShadow(float radius, float dx, float dy, int color);
+ virtual void resetShadow();
+ virtual void setupShadow(float radius, float dx, float dy, int color);
- void reset();
+ ANDROID_API void reset();
const SkWriter32& writeStream() const {
return mWriter;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 349b9e3..dfcc5ea 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -31,6 +31,12 @@
// Rendering
///////////////////////////////////////////////////////////////////////////////
+LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
+}
+
+LayerRenderer::~LayerRenderer() {
+}
+
void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
@@ -264,7 +270,7 @@
layer->setFbo(0);
layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
- layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
+ layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
layer->region.clear();
layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
@@ -400,6 +406,18 @@
renderer.setViewport(bitmap->width(), bitmap->height());
renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
bitmap->width(), bitmap->height(), !layer->isBlend());
+
+ glDisable(GL_SCISSOR_TEST);
+ renderer.translate(0.0f, bitmap->height());
+ renderer.scale(1.0f, -1.0f);
+
+ mat4 texTransform(layer->getTexTransform());
+
+ mat4 invert;
+ invert.translate(0.0f, 1.0f, 0.0f);
+ invert.scale(1.0f, -1.0f, 1.0f);
+ layer->getTexTransform().multiply(invert);
+
if ((error = glGetError()) != GL_NO_ERROR) goto error;
{
@@ -413,6 +431,7 @@
if ((error = glGetError()) != GL_NO_ERROR) goto error;
}
+ layer->getTexTransform().load(texTransform);
status = true;
}
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 2246573..6104301 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_LAYER_RENDERER_H
#define ANDROID_HWUI_LAYER_RENDERER_H
+#include <cutils/compiler.h>
+
#include "OpenGLRenderer.h"
#include "Layer.h"
@@ -42,27 +44,24 @@
class LayerRenderer: public OpenGLRenderer {
public:
- LayerRenderer(Layer* layer): mLayer(layer) {
- }
+ ANDROID_API LayerRenderer(Layer* layer);
+ virtual ~LayerRenderer();
- ~LayerRenderer() {
- }
+ virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual void finish();
- void prepareDirty(float left, float top, float right, float bottom, bool opaque);
- void finish();
+ virtual bool hasLayer();
+ virtual Region* getRegion();
+ virtual GLint getTargetFbo();
- bool hasLayer();
- Region* getRegion();
- GLint getTargetFbo();
-
- static Layer* createTextureLayer(bool isOpaque);
- static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
- static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
- static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+ ANDROID_API static Layer* createTextureLayer(bool isOpaque);
+ ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
+ ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+ ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, GLenum renderTarget, float* transform);
- static void destroyLayer(Layer* layer);
- static void destroyLayerDeferred(Layer* layer);
- static bool copyLayer(Layer* layer, SkBitmap* bitmap);
+ ANDROID_API static void destroyLayer(Layer* layer);
+ ANDROID_API static void destroyLayerDeferred(Layer* layer);
+ ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
private:
void generateMesh();
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 56fd37d..22220a9 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -19,6 +19,8 @@
#include <SkMatrix.h>
+#include <cutils/compiler.h>
+
#include "Rect.h"
namespace android {
@@ -28,7 +30,7 @@
// Classes
///////////////////////////////////////////////////////////////////////////////
-class Matrix4 {
+class ANDROID_API Matrix4 {
public:
float data[16];
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 14b22b3..2fc88e1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -31,6 +31,8 @@
#include <utils/RefBase.h>
#include <utils/Vector.h>
+#include <cutils/compiler.h>
+
#include "Debug.h"
#include "Extensions.h"
#include "Matrix.h"
@@ -57,12 +59,12 @@
*/
class OpenGLRenderer {
public:
- OpenGLRenderer();
+ ANDROID_API OpenGLRenderer();
virtual ~OpenGLRenderer();
virtual void setViewport(int width, int height);
- void prepare(bool opaque);
+ ANDROID_API void prepare(bool opaque);
virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
@@ -72,7 +74,7 @@
virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
- int getSaveCount() const;
+ ANDROID_API int getSaveCount() const;
virtual int save(int flags);
virtual void restore();
virtual void restoreToCount(int saveCount);
@@ -87,12 +89,12 @@
virtual void scale(float sx, float sy);
virtual void skew(float sx, float sy);
- void getMatrix(SkMatrix* matrix);
+ ANDROID_API void getMatrix(SkMatrix* matrix);
virtual void setMatrix(SkMatrix* matrix);
virtual void concatMatrix(SkMatrix* matrix);
- const Rect& getClipBounds();
- bool quickReject(float left, float top, float right, float bottom);
+ ANDROID_API const Rect& getClipBounds();
+ ANDROID_API bool quickReject(float left, float top, float right, float bottom);
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 2a38910..8cf466b 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
#define ANDROID_HWUI_RESOURCE_CACHE_H
+#include <cutils/compiler.h>
+
#include <SkBitmap.h>
#include <SkiaColorFilter.h>
#include <SkiaShader.h>
@@ -49,7 +51,7 @@
ResourceType resourceType;
};
-class ResourceCache {
+class ANDROID_API ResourceCache {
KeyedVector<void *, ResourceReference *>* mCache;
public:
ResourceCache();
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index 1bf475c..2feb834 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -20,6 +20,8 @@
#include <GLES2/gl2.h>
#include <SkColorFilter.h>
+#include <cutils/compiler.h>
+
#include "ProgramCache.h"
#include "Extensions.h"
@@ -45,7 +47,7 @@
kBlend,
};
- SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
+ ANDROID_API SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
virtual ~SkiaColorFilter();
virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
@@ -79,7 +81,7 @@
* A color filter that multiplies the source color with a matrix and adds a vector.
*/
struct SkiaColorMatrixFilter: public SkiaColorFilter {
- SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
+ ANDROID_API SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
~SkiaColorMatrixFilter();
void describe(ProgramDescription& description, const Extensions& extensions);
@@ -95,7 +97,7 @@
* another fixed value. Ignores the alpha channel of both arguments.
*/
struct SkiaLightingFilter: public SkiaColorFilter {
- SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
+ ANDROID_API SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program);
@@ -110,7 +112,7 @@
* and PorterDuff blending mode.
*/
struct SkiaBlendFilter: public SkiaColorFilter {
- SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
+ ANDROID_API SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program);
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 89dd131..2de9a93 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -22,6 +22,8 @@
#include <GLES2/gl2.h>
+#include <cutils/compiler.h>
+
#include "Extensions.h"
#include "ProgramCache.h"
#include "TextureCache.h"
@@ -52,8 +54,8 @@
kCompose
};
- SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY,
- SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
+ SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
virtual ~SkiaShader();
virtual SkiaShader* copy() = 0;
@@ -139,7 +141,7 @@
* A shader that draws a bitmap.
*/
struct SkiaBitmapShader: public SkiaShader {
- SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
+ ANDROID_API SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
SkiaShader* copy();
@@ -169,8 +171,8 @@
* A shader that draws a linear gradient.
*/
struct SkiaLinearGradientShader: public SkiaShader {
- SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, int count,
- SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions,
+ int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
~SkiaLinearGradientShader();
SkiaShader* copy();
@@ -193,8 +195,8 @@
* A shader that draws a sweep gradient.
*/
struct SkiaSweepGradientShader: public SkiaShader {
- SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count,
- SkShader* key, SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions,
+ int count, SkShader* key, SkMatrix* matrix, bool blend);
~SkiaSweepGradientShader();
SkiaShader* copy();
@@ -218,8 +220,9 @@
* A shader that draws a circular gradient.
*/
struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
- SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions,
- int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors,
+ float* positions, int count, SkShader* key,SkShader::TileMode tileMode,
+ SkMatrix* matrix, bool blend);
SkiaShader* copy();
void describe(ProgramDescription& description, const Extensions& extensions);
@@ -233,7 +236,8 @@
* A shader that draws two shaders, composited with an xfermode.
*/
struct SkiaComposeShader: public SkiaShader {
- SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, SkShader* key);
+ ANDROID_API SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode,
+ SkShader* key);
~SkiaComposeShader();
SkiaShader* copy();
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 5fd5c35..4ecf8e8 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -226,6 +226,7 @@
RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
uint32_t sig = mtls->sig;
+ outer_foreach_t fn = dc->mForEachLaunch[sig];
while (1) {
uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
@@ -239,16 +240,10 @@
//LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut);
for (p.y = yStart; p.y < yEnd; p.y++) {
uint32_t offset = mtls->dimX * p.y;
- uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
- const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
-
- for (p.x = mtls->xStart; p.x < mtls->xEnd; p.x++) {
- p.in = xPtrIn;
- p.out = xPtrOut;
- dc->mForEachLaunch[sig](&mtls->script->mHal.info.root, &p);
- xPtrIn += mtls->eStrideIn;
- xPtrOut += mtls->eStrideOut;
- }
+ p.out = mtls->ptrOut + (mtls->eStrideOut * offset);
+ p.in = mtls->ptrIn + (mtls->eStrideIn * offset);
+ fn(&mtls->script->mHal.info.root, &p, mtls->xStart, mtls->xEnd,
+ mtls->eStrideIn, mtls->eStrideOut);
}
}
}
@@ -262,6 +257,7 @@
RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
uint32_t sig = mtls->sig;
+ outer_foreach_t fn = dc->mForEachLaunch[sig];
while (1) {
uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
@@ -271,17 +267,12 @@
return;
}
- //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+ //LOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
//LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut);
- uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
- const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
- for (p.x = xStart; p.x < xEnd; p.x++) {
- p.in = xPtrIn;
- p.out = xPtrOut;
- dc->mForEachLaunch[sig](&mtls->script->mHal.info.root, &p);
- xPtrIn += mtls->eStrideIn;
- xPtrOut += mtls->eStrideOut;
- }
+
+ p.out = mtls->ptrOut + (mtls->eStrideOut * xStart);
+ p.in = mtls->ptrIn + (mtls->eStrideIn * xStart);
+ fn(&mtls->script->mHal.info.root, &p, xStart, xEnd, mtls->eStrideIn, mtls->eStrideOut);
}
}
@@ -392,22 +383,17 @@
uint32_t sig = mtls.sig;
//LOGE("launch 3");
+ outer_foreach_t fn = dc->mForEachLaunch[sig];
for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * p.ar[0] +
mtls.dimX * mtls.dimY * p.z +
mtls.dimX * p.y;
- uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
- const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
-
- for (p.x = mtls.xStart; p.x < mtls.xEnd; p.x++) {
- p.in = xPtrIn;
- p.out = xPtrOut;
- dc->mForEachLaunch[sig](&s->mHal.info.root, &p);
- xPtrIn += mtls.eStrideIn;
- xPtrOut += mtls.eStrideOut;
- }
+ p.out = mtls.ptrOut + (mtls.eStrideOut * offset);
+ p.in = mtls.ptrIn + (mtls.eStrideIn * offset);
+ fn(&mtls.script->mHal.info.root, &p, mtls.xStart, mtls.xEnd,
+ mtls.eStrideIn, mtls.eStrideOut);
}
}
}
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index f8107d9..247f4dc 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -292,75 +292,136 @@
}
static void rsdForEach17(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, uint32_t);
(*(fe*)vRoot)(p->in, p->y);
}
static void rsdForEach18(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, uint32_t);
(*(fe*)vRoot)(p->out, p->y);
}
static void rsdForEach19(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, uint32_t);
(*(fe*)vRoot)(p->in, p->out, p->y);
}
static void rsdForEach21(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, const void *, uint32_t);
(*(fe*)vRoot)(p->in, p->usr, p->y);
}
static void rsdForEach22(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, const void *, uint32_t);
(*(fe*)vRoot)(p->out, p->usr, p->y);
}
static void rsdForEach23(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, const void *, uint32_t);
(*(fe*)vRoot)(p->in, p->out, p->usr, p->y);
}
static void rsdForEach25(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->x, p->y);
+ const uint8_t *pin = (const uint8_t *)p->in;
+ uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, x, y);
+ pin += instep;
+ }
}
static void rsdForEach26(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->out, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pout, x, y);
+ pout += outstep;
+ }
}
static void rsdForEach27(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->out, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ const uint8_t *pin = (const uint8_t *)p->in;
+ uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, pout, x, y);
+ pin += instep;
+ pout += outstep;
+ }
}
static void rsdForEach29(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->usr, p->x, p->y);
+ const uint8_t *pin = (const uint8_t *)p->in;
+ const void *usr = p->usr;
+ const uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, usr, x, y);
+ pin += instep;
+ }
}
static void rsdForEach30(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->out, p->usr, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ const void *usr = p->usr;
+ const uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pout, usr, x, y);
+ pout += outstep;
+ }
}
static void rsdForEach31(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->out, p->usr, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ const uint8_t *pin = (const uint8_t *)p->in;
+ const void *usr = p->usr;
+ const uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, pout, usr, x, y);
+ pin += instep;
+ pout += outstep;
+ }
}
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 159b72a..ce86d11 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -28,7 +28,9 @@
typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
typedef void (*outer_foreach_t)(const void *,
- const android::renderscript::RsForEachStubParamStruct *);
+ const android::renderscript::RsForEachStubParamStruct *,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep);
typedef struct RsdSymbolTableRec {
const char * mName;
diff --git a/libs/rs/rsProgramRaster.h b/libs/rs/rsProgramRaster.h
index 20af30a..c552ea3 100644
--- a/libs/rs/rsProgramRaster.h
+++ b/libs/rs/rsProgramRaster.h
@@ -24,17 +24,16 @@
namespace renderscript {
class ProgramRasterState;
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
class ProgramRaster : public ProgramBase {
public:
- virtual void setup(const Context *, ProgramRasterState *);
- virtual void serialize(OStream *stream) const;
- virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_RASTER; }
- static ProgramRaster *createFromStream(Context *rsc, IStream *stream);
-
- static ObjectBaseRef<ProgramRaster> getProgramRaster(Context *rsc,
- bool pointSprite,
- RsCullMode cull);
struct Hal {
mutable void *drv;
@@ -46,6 +45,14 @@
};
Hal mHal;
+ virtual void setup(const Context *, ProgramRasterState *);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_RASTER; }
+ static ProgramRaster *createFromStream(Context *rsc, IStream *stream);
+
+ static ObjectBaseRef<ProgramRaster> getProgramRaster(Context *rsc,
+ bool pointSprite,
+ RsCullMode cull);
protected:
virtual void preDestroy() const;
virtual ~ProgramRaster();
diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h
index e21f039..9bb2795 100644
--- a/libs/rs/rsProgramStore.h
+++ b/libs/rs/rsProgramStore.h
@@ -25,23 +25,16 @@
namespace renderscript {
class ProgramStoreState;
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
class ProgramStore : public ProgramBase {
public:
- virtual void setup(const Context *, ProgramStoreState *);
-
- virtual void serialize(OStream *stream) const;
- virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_STORE; }
- static ProgramStore *createFromStream(Context *rsc, IStream *stream);
- static ObjectBaseRef<ProgramStore> getProgramStore(Context *,
- bool colorMaskR, bool colorMaskG,
- bool colorMaskB, bool colorMaskA,
- bool depthMask, bool ditherEnable,
- RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc,
- RsDepthFunc depthFunc);
-
- void init();
-
struct Hal {
mutable void *drv;
@@ -64,6 +57,18 @@
};
Hal mHal;
+ virtual void setup(const Context *, ProgramStoreState *);
+
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_STORE; }
+ static ProgramStore *createFromStream(Context *rsc, IStream *stream);
+ static ObjectBaseRef<ProgramStore> getProgramStore(Context *,
+ bool colorMaskR, bool colorMaskG,
+ bool colorMaskB, bool colorMaskA,
+ bool depthMask, bool ditherEnable,
+ RsBlendSrcFunc srcFunc, RsBlendDstFunc destFunc,
+ RsDepthFunc depthFunc);
+ void init();
protected:
virtual void preDestroy() const;
virtual ~ProgramStore();
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index e698132..654cd9c 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -27,23 +27,16 @@
const static uint32_t RS_MAX_SAMPLER_SLOT = 16;
class SamplerState;
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
class Sampler : public ObjectBase {
public:
- static ObjectBaseRef<Sampler> getSampler(Context *,
- RsSamplerValue magFilter,
- RsSamplerValue minFilter,
- RsSamplerValue wrapS,
- RsSamplerValue wrapT,
- RsSamplerValue wrapR,
- float aniso = 1.0f);
- void bindToContext(SamplerState *, uint32_t slot);
- void unbindFromContext(SamplerState *);
-
- virtual void serialize(OStream *stream) const;
- virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; }
- static Sampler *createFromStream(Context *rsc, IStream *stream);
-
struct Hal {
mutable void *drv;
@@ -59,6 +52,20 @@
};
Hal mHal;
+ static ObjectBaseRef<Sampler> getSampler(Context *,
+ RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR,
+ float aniso = 1.0f);
+ void bindToContext(SamplerState *, uint32_t slot);
+ void unbindFromContext(SamplerState *);
+
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SAMPLER; }
+ static Sampler *createFromStream(Context *rsc, IStream *stream);
+
protected:
int32_t mBoundSlot;
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 3e9339e..80267c7 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -23,6 +23,55 @@
#ifndef __RS_GRAPHICS_RSH__
#define __RS_GRAPHICS_RSH__
+// These are API 15 once it get official
+typedef enum {
+ RS_DEPTH_FUNC_ALWAYS,
+ RS_DEPTH_FUNC_LESS,
+ RS_DEPTH_FUNC_LEQUAL,
+ RS_DEPTH_FUNC_GREATER,
+ RS_DEPTH_FUNC_GEQUAL,
+ RS_DEPTH_FUNC_EQUAL,
+ RS_DEPTH_FUNC_NOTEQUAL
+} rs_depth_func;
+
+typedef enum {
+ 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
+} rs_blend_src_func;
+
+typedef enum {
+ 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
+} rs_blend_dst_func;
+
+typedef enum {
+ RS_CULL_BACK,
+ RS_CULL_FRONT,
+ RS_CULL_NONE
+} rs_cull_mode;
+
+typedef enum {
+ RS_SAMPLER_NEAREST,
+ RS_SAMPLER_LINEAR,
+ RS_SAMPLER_LINEAR_MIP_LINEAR,
+ RS_SAMPLER_WRAP,
+ RS_SAMPLER_CLAMP,
+ RS_SAMPLER_LINEAR_MIP_NEAREST,
+} rs_sampler_value;
+
#if (defined(RS_VERSION) && (RS_VERSION >= 14))
/**
* Set the color target used for all subsequent rendering calls
@@ -83,6 +132,88 @@
extern void __attribute__((overloadable))
rsgBindProgramStore(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+ rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+
/**
* Bind a new ProgramVertex to the rendering context.
*
@@ -100,6 +231,24 @@
rsgBindProgramRaster(rs_program_raster pr);
/**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+ rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+/**
* Bind a new Sampler object to a ProgramFragment. The sampler will
* operate on the texture bound at the matching slot.
*
@@ -109,6 +258,51 @@
rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
/**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+ rsgSamplerGetAnisotropy(rs_sampler s);
+
+/**
* Bind a new Allocation object to a ProgramFragment. The
* Allocation must be a valid texture for the Program. The sampling
* of the texture will be controled by the Sampler bound at the
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 8793841..e275aa6 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -71,6 +71,11 @@
private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WEBM;
+ // More video file types
+ public static final int FILE_TYPE_MP2PS = 200;
+ private static final int FIRST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+ private static final int LAST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+
// Image file types
public static final int FILE_TYPE_JPEG = 31;
public static final int FILE_TYPE_GIF = 32;
@@ -235,6 +240,8 @@
addFileType("PPT", FILE_TYPE_MS_POWERPOINT, "application/mspowerpoint", MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION);
addFileType("FLAC", FILE_TYPE_FLAC, "audio/flac", MtpConstants.FORMAT_FLAC);
addFileType("ZIP", FILE_TYPE_ZIP, "application/zip");
+ addFileType("MPG", FILE_TYPE_MP2PS, "video/mp2p");
+ addFileType("MPEG", FILE_TYPE_MP2PS, "video/mp2p");
}
public static boolean isAudioFileType(int fileType) {
@@ -246,7 +253,9 @@
public static boolean isVideoFileType(int fileType) {
return (fileType >= FIRST_VIDEO_FILE_TYPE &&
- fileType <= LAST_VIDEO_FILE_TYPE);
+ fileType <= LAST_VIDEO_FILE_TYPE)
+ || (fileType >= FIRST_VIDEO_FILE_TYPE2 &&
+ fileType <= LAST_VIDEO_FILE_TYPE2);
}
public static boolean isImageFileType(int fileType) {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index ec7d8a0..a3e2517 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -32,8 +32,8 @@
libdl
LOCAL_STATIC_LIBRARIES := \
- libstagefright_rtsp \
libstagefright_nuplayer \
+ libstagefright_rtsp \
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b5eef94..24e1bfb 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -584,6 +584,10 @@
}
}
+ if (!strncasecmp("rtsp://", url, 7)) {
+ return NU_PLAYER;
+ }
+
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index e761509..33e2f93 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -8,6 +8,7 @@
NuPlayerDriver.cpp \
NuPlayerRenderer.cpp \
NuPlayerStreamListener.cpp \
+ RTSPSource.cpp \
StreamingSource.cpp \
LOCAL_C_INCLUDES := \
@@ -15,6 +16,7 @@
$(TOP)/frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/base/media/libstagefright/mpeg2ts \
$(TOP)/frameworks/base/media/libstagefright/httplive \
+ $(TOP)/frameworks/base/media/libstagefright/rtsp \
LOCAL_MODULE:= libstagefright_nuplayer
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6b40528..4c710b4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -25,6 +25,7 @@
#include "NuPlayerDriver.h"
#include "NuPlayerRenderer.h"
#include "NuPlayerSource.h"
+#include "RTSPSource.h"
#include "StreamingSource.h"
#include "ATSParser.h"
@@ -87,7 +88,14 @@
const char *url, const KeyedVector<String8, String8> *headers) {
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
- msg->setObject("source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+ if (!strncasecmp(url, "rtsp://", 7)) {
+ msg->setObject(
+ "source", new RTSPSource(url, headers, mUIDValid, mUID));
+ } else {
+ msg->setObject(
+ "source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+ }
+
msg->post();
}
@@ -568,8 +576,15 @@
CHECK(mAudioDecoder == NULL);
CHECK(mVideoDecoder == NULL);
+ ++mScanSourcesGeneration;
+ mScanSourcesPending = false;
+
mRenderer.clear();
- mSource.clear();
+
+ if (mSource != NULL) {
+ mSource->stop();
+ mSource.clear();
+ }
if (mDriver != NULL) {
sp<NuPlayerDriver> driver = mDriver.promote();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index a5382b4..f90759d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -68,6 +68,7 @@
struct Renderer;
struct Source;
struct StreamingSource;
+ struct RTSPSource;
enum {
kWhatSetDataSource = '=DaS',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 07e347e..bf19040 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -219,7 +219,9 @@
bool NuPlayer::Renderer::onDrainAudioQueue() {
uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+ if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
+ return false;
+ }
ssize_t numFramesAvailableToWrite =
mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 8a7eece..531b29f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -28,6 +28,7 @@
Source() {}
virtual void start() = 0;
+ virtual void stop() {}
// Returns OK iff more data was available,
// an error or ERROR_END_OF_STREAM if not.
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
new file mode 100644
index 0000000..e72adc4
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "RTSPSource"
+#include <utils/Log.h>
+
+#include "RTSPSource.h"
+
+#include "AnotherPacketSource.h"
+#include "MyHandler.h"
+
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::RTSPSource::RTSPSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid,
+ uid_t uid)
+ : mURL(url),
+ mUIDValid(uidValid),
+ mUID(uid),
+ mFlags(0),
+ mState(DISCONNECTED),
+ mFinalResult(OK),
+ mDisconnectReplyID(0) {
+ if (headers) {
+ mExtraHeaders = *headers;
+
+ ssize_t index =
+ mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
+
+ if (index >= 0) {
+ mFlags |= kFlagIncognito;
+
+ mExtraHeaders.removeItemsAt(index);
+ }
+ }
+}
+
+NuPlayer::RTSPSource::~RTSPSource() {
+ if (mLooper != NULL) {
+ mLooper->stop();
+ }
+}
+
+void NuPlayer::RTSPSource::start() {
+ if (mLooper == NULL) {
+ mLooper = new ALooper;
+ mLooper->setName("rtsp");
+ mLooper->start();
+
+ mReflector = new AHandlerReflector<RTSPSource>(this);
+ mLooper->registerHandler(mReflector);
+ }
+
+ CHECK(mHandler == NULL);
+
+ sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+
+ mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
+ mLooper->registerHandler(mHandler);
+
+ CHECK_EQ(mState, (int)DISCONNECTED);
+ mState = CONNECTING;
+
+ mHandler->connect();
+}
+
+void NuPlayer::RTSPSource::stop() {
+ sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
+
+ sp<AMessage> dummy;
+ msg->postAndAwaitResponse(&dummy);
+}
+
+status_t NuPlayer::RTSPSource::feedMoreTSData() {
+ return mFinalResult;
+}
+
+sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) {
+ sp<AnotherPacketSource> source = getSource(audio);
+
+ if (source == NULL) {
+ return NULL;
+ }
+
+ return source->getFormat();
+}
+
+status_t NuPlayer::RTSPSource::dequeueAccessUnit(
+ bool audio, sp<ABuffer> *accessUnit) {
+ sp<AnotherPacketSource> source = getSource(audio);
+
+ if (source == NULL) {
+ return -EWOULDBLOCK;
+ }
+
+ status_t finalResult;
+ if (!source->hasBufferAvailable(&finalResult)) {
+ return finalResult == OK ? -EWOULDBLOCK : finalResult;
+ }
+
+ return source->dequeueAccessUnit(accessUnit);
+}
+
+sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
+ return audio ? mAudioTrack : mVideoTrack;
+}
+
+status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
+ *durationUs = 0ll;
+
+ int64_t audioDurationUs;
+ if (mAudioTrack != NULL
+ && mAudioTrack->getFormat()->findInt64(
+ kKeyDuration, &audioDurationUs)
+ && audioDurationUs > *durationUs) {
+ *durationUs = audioDurationUs;
+ }
+
+ int64_t videoDurationUs;
+ if (mVideoTrack != NULL
+ && mVideoTrack->getFormat()->findInt64(
+ kKeyDuration, &videoDurationUs)
+ && videoDurationUs > *durationUs) {
+ *durationUs = videoDurationUs;
+ }
+
+ return OK;
+}
+
+status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
+ if (mState != CONNECTED) {
+ return UNKNOWN_ERROR;
+ }
+
+ mState = SEEKING;
+ mHandler->seek(seekTimeUs);
+
+ return OK;
+}
+
+bool NuPlayer::RTSPSource::isSeekable() {
+ return true;
+}
+
+void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
+ if (msg->what() == kWhatDisconnect) {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ mDisconnectReplyID = replyID;
+ finishDisconnectIfPossible();
+ return;
+ }
+
+ CHECK_EQ(msg->what(), (int)kWhatNotify);
+
+ int32_t what;
+ CHECK(msg->findInt32("what", &what));
+
+ switch (what) {
+ case MyHandler::kWhatConnected:
+ onConnected();
+ break;
+
+ case MyHandler::kWhatDisconnected:
+ onDisconnected(msg);
+ break;
+
+ case MyHandler::kWhatSeekDone:
+ {
+ mState = CONNECTED;
+ break;
+ }
+
+ case MyHandler::kWhatAccessUnit:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ sp<RefBase> obj;
+ CHECK(msg->findObject("accessUnit", &obj));
+
+ sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
+
+ int32_t damaged;
+ if (accessUnit->meta()->findInt32("damaged", &damaged)
+ && damaged) {
+ LOGI("dropping damaged access unit.");
+ break;
+ }
+
+ const TrackInfo &info = mTracks.editItemAt(trackIndex);
+ sp<AnotherPacketSource> source = info.mSource;
+ if (source != NULL) {
+#if 1
+ uint32_t rtpTime;
+ CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+ int64_t nptUs =
+ ((double)rtpTime - (double)info.mRTPTime)
+ / info.mTimeScale
+ * 1000000ll
+ + info.mNormalPlaytimeUs;
+
+ accessUnit->meta()->setInt64("timeUs", nptUs);
+#endif
+
+ source->queueAccessUnit(accessUnit);
+ }
+ break;
+ }
+
+ case MyHandler::kWhatEOS:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ int32_t finalResult;
+ CHECK(msg->findInt32("finalResult", &finalResult));
+ CHECK_NE(finalResult, (status_t)OK);
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ sp<AnotherPacketSource> source = info->mSource;
+ if (source != NULL) {
+ source->signalEOS(finalResult);
+ }
+
+ break;
+ }
+
+ case MyHandler::kWhatSeekDiscontinuity:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ sp<AnotherPacketSource> source = info->mSource;
+ if (source != NULL) {
+ source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
+ }
+
+ break;
+ }
+
+ case MyHandler::kWhatNormalPlayTimeMapping:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ uint32_t rtpTime;
+ CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
+
+ int64_t nptUs;
+ CHECK(msg->findInt64("nptUs", &nptUs));
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ info->mRTPTime = rtpTime;
+ info->mNormalPlaytimeUs = nptUs;
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+void NuPlayer::RTSPSource::onConnected() {
+ CHECK(mAudioTrack == NULL);
+ CHECK(mVideoTrack == NULL);
+
+ size_t numTracks = mHandler->countTracks();
+ for (size_t i = 0; i < numTracks; ++i) {
+ int32_t timeScale;
+ sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
+
+ const char *mime;
+ CHECK(format->findCString(kKeyMIMEType, &mime));
+
+ bool isAudio = !strncasecmp(mime, "audio/", 6);
+ bool isVideo = !strncasecmp(mime, "video/", 6);
+
+ TrackInfo info;
+ info.mTimeScale = timeScale;
+ info.mRTPTime = 0;
+ info.mNormalPlaytimeUs = 0ll;
+
+ if ((isAudio && mAudioTrack == NULL)
+ || (isVideo && mVideoTrack == NULL)) {
+ sp<AnotherPacketSource> source = new AnotherPacketSource(format);
+
+ if (isAudio) {
+ mAudioTrack = source;
+ } else {
+ mVideoTrack = source;
+ }
+
+ info.mSource = source;
+ }
+
+ mTracks.push(info);
+ }
+
+ mState = CONNECTED;
+}
+
+void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
+ status_t err;
+ CHECK(msg->findInt32("result", &err));
+ CHECK_NE(err, (status_t)OK);
+
+ mLooper->unregisterHandler(mHandler->id());
+ mHandler.clear();
+
+ mState = DISCONNECTED;
+ mFinalResult = err;
+
+ if (mDisconnectReplyID != 0) {
+ finishDisconnectIfPossible();
+ }
+}
+
+void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
+ if (mState != DISCONNECTED) {
+ mHandler->disconnect();
+ return;
+ }
+
+ (new AMessage)->postReply(mDisconnectReplyID);
+ mDisconnectReplyID = 0;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
new file mode 100644
index 0000000..66eab72
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RTSP_SOURCE_H_
+
+#define RTSP_SOURCE_H_
+
+#include "NuPlayerSource.h"
+
+#include <media/stagefright/foundation/AHandlerReflector.h>
+
+namespace android {
+
+struct ALooper;
+struct AnotherPacketSource;
+struct MyHandler;
+
+struct NuPlayer::RTSPSource : public NuPlayer::Source {
+ RTSPSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid = false,
+ uid_t uid = 0);
+
+ virtual void start();
+ virtual void stop();
+
+ virtual status_t feedMoreTSData();
+
+ virtual sp<MetaData> getFormat(bool audio);
+ virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+
+ virtual status_t getDuration(int64_t *durationUs);
+ virtual status_t seekTo(int64_t seekTimeUs);
+ virtual bool isSeekable();
+
+ void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+ virtual ~RTSPSource();
+
+private:
+ enum {
+ kWhatNotify = 'noti',
+ kWhatDisconnect = 'disc',
+ };
+
+ enum State {
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED,
+ SEEKING,
+ };
+
+ enum Flags {
+ // Don't log any URLs.
+ kFlagIncognito = 1,
+ };
+
+ struct TrackInfo {
+ sp<AnotherPacketSource> mSource;
+
+ int32_t mTimeScale;
+ uint32_t mRTPTime;
+ int64_t mNormalPlaytimeUs;
+ };
+
+ AString mURL;
+ KeyedVector<String8, String8> mExtraHeaders;
+ bool mUIDValid;
+ uid_t mUID;
+ uint32_t mFlags;
+ State mState;
+ status_t mFinalResult;
+ uint32_t mDisconnectReplyID;
+
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<RTSPSource> > mReflector;
+ sp<MyHandler> mHandler;
+
+ Vector<TrackInfo> mTracks;
+ sp<AnotherPacketSource> mAudioTrack;
+ sp<AnotherPacketSource> mVideoTrack;
+
+ sp<AnotherPacketSource> getSource(bool audio);
+
+ void onConnected();
+ void onDisconnected(const sp<AMessage> &msg);
+ void finishDisconnectIfPossible();
+
+ DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
+};
+
+} // namespace android
+
+#endif // RTSP_SOURCE_H_
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9cb18de..d947760 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -681,6 +681,10 @@
static const MimeToRole kMimeToRole[] = {
{ MEDIA_MIMETYPE_AUDIO_MPEG,
"audio_decoder.mp3", "audio_encoder.mp3" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+ "audio_decoder.mp1", "audio_encoder.mp1" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+ "audio_decoder.mp2", "audio_encoder.mp2" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB,
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 0b1a2af..0aeb515 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -58,7 +58,6 @@
$(TOP)/frameworks/base/include/media/stagefright/openmax \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
- $(TOP)/frameworks/base/media/libstagefright/rtsp \
$(TOP)/external/openssl/include \
LOCAL_SHARED_LIBRARIES := \
@@ -88,7 +87,6 @@
libvpx \
libstagefright_mpeg2ts \
libstagefright_httplive \
- libstagefright_rtsp \
libstagefright_id3 \
libFLAC \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1165af5..1c7e58d 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -22,7 +22,6 @@
#include <dlfcn.h>
-#include "include/ARTSPController.h"
#include "include/AwesomePlayer.h"
#include "include/DRMExtractor.h"
#include "include/SoftwareRenderer.h"
@@ -53,7 +52,6 @@
#include <gui/SurfaceTextureClient.h>
#include <surfaceflinger/ISurfaceComposer.h>
-#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <cutils/properties.h>
@@ -65,7 +63,6 @@
static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
-static int64_t kHighWaterMarkRTSPUs = 4000000ll; // 4secs
static const size_t kLowWaterMarkBytes = 40000;
static const size_t kHighWaterMarkBytes = 200000;
@@ -485,9 +482,6 @@
if (mConnectingDataSource != NULL) {
LOGI("interrupting the connection process");
mConnectingDataSource->disconnect();
- } else if (mConnectingRTSPController != NULL) {
- LOGI("interrupting the connection process");
- mConnectingRTSPController->disconnect();
}
if (mFlags & PREPARING_CONNECTED) {
@@ -534,11 +528,6 @@
mVideoRenderer.clear();
- if (mRTSPController != NULL) {
- mRTSPController->disconnect();
- mRTSPController.clear();
- }
-
if (mVideoSource != NULL) {
shutdownVideoDecoder_l();
}
@@ -612,10 +601,7 @@
bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
int64_t bitrate;
- if (mRTSPController != NULL) {
- *durationUs = mRTSPController->getQueueDurationUs(eos);
- return true;
- } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
+ if (mCachedSource != NULL && getBitrate(&bitrate)) {
status_t finalStatus;
size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
*durationUs = cachedDataRemaining * 8000000ll / bitrate;
@@ -751,9 +737,6 @@
LOGV("cachedDurationUs = %.2f secs, eos=%d",
cachedDurationUs / 1E6, eos);
- int64_t highWaterMarkUs =
- (mRTSPController != NULL) ? kHighWaterMarkRTSPUs : kHighWaterMarkUs;
-
if ((mFlags & PLAYING) && !eos
&& (cachedDurationUs < kLowWaterMarkUs)) {
LOGI("cache is running low (%.2f secs) , pausing.",
@@ -763,7 +746,7 @@
ensureCacheIsFetching_l();
sendCacheStats();
notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDurationUs > highWaterMarkUs) {
+ } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
if (mFlags & CACHE_UNDERRUN) {
LOGI("cache has filled up (%.2f secs), resuming.",
cachedDurationUs / 1E6);
@@ -1081,7 +1064,8 @@
if (USE_SURFACE_ALLOC
&& !strncmp(component, "OMX.", 4)
- && strncmp(component, "OMX.google.", 11)) {
+ && strncmp(component, "OMX.google.", 11)
+ && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) {
// Hardware decoders avoid the CPU color conversion by decoding
// directly to ANativeBuffers, so we must use a renderer that
// just pushes those buffers to the ANativeWindow.
@@ -1263,10 +1247,7 @@
}
status_t AwesomePlayer::getPosition(int64_t *positionUs) {
- if (mRTSPController != NULL) {
- *positionUs = mRTSPController->getNormalPlayTimeUs();
- }
- else if (mSeeking != NO_SEEK) {
+ if (mSeeking != NO_SEEK) {
*positionUs = mSeekTimeUs;
} else if (mVideoSource != NULL
&& (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
@@ -1316,25 +1297,7 @@
}
}
-// static
-void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
- static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
-}
-
-void AwesomePlayer::onRTSPSeekDone() {
- if (!mSeekNotificationSent) {
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
- }
-}
-
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
- if (mRTSPController != NULL) {
- mSeekNotificationSent = false;
- mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
- return OK;
- }
-
if (mFlags & CACHE_UNDERRUN) {
modifyFlags(CACHE_UNDERRUN, CLEAR);
play_l();
@@ -1770,7 +1733,6 @@
int64_t latenessUs = nowUs - timeUs;
if (latenessUs > 500000ll
- && mRTSPController == NULL
&& mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(
&realTimeUs, &mediaTimeUs)) {
@@ -2085,34 +2047,6 @@
return UNKNOWN_ERROR;
}
}
- } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("rtsp");
- mLooper->start();
- }
- mRTSPController = new ARTSPController(mLooper);
- mConnectingRTSPController = mRTSPController;
-
- if (mUIDValid) {
- mConnectingRTSPController->setUID(mUID);
- }
-
- mLock.unlock();
- status_t err = mRTSPController->connect(mUri.string());
- mLock.lock();
-
- mConnectingRTSPController.clear();
-
- LOGI("ARTSPController::connect returned %d", err);
-
- if (err != OK) {
- mRTSPController.clear();
- return err;
- }
-
- sp<MediaExtractor> extractor = mRTSPController.get();
- return setDataSource_l(extractor);
} else {
dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
}
@@ -2224,7 +2158,7 @@
modifyFlags(PREPARING_CONNECTED, SET);
- if (isStreamingHTTP() || mRTSPController != NULL) {
+ if (isStreamingHTTP()) {
postBufferingEvent_l();
} else {
finishAsyncPrepare_l();
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c16b3b5..70523c1 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -20,6 +20,7 @@
#include "include/MPEG4Extractor.h"
#include "include/WAVExtractor.h"
#include "include/OggExtractor.h"
+#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
#include "include/NuCachedSource2.h"
#include "include/HTTPBase.h"
@@ -113,6 +114,7 @@
RegisterSniffer(SniffMP3);
RegisterSniffer(SniffAAC);
RegisterSniffer(SniffAVI);
+ RegisterSniffer(SniffMPEG2PS);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 92e84c2..34e9cd7 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -25,11 +25,11 @@
#include "include/VBRISeeker.h"
#include "include/XINGSeeker.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -289,9 +289,24 @@
GetMPEGAudioFrameSize(
header, &frame_size, &sample_rate, &num_channels, &bitrate);
+ unsigned layer = 4 - ((header >> 17) & 3);
+
mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ switch (layer) {
+ case 1:
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+ break;
+ case 2:
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ break;
+ case 3:
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ break;
+ default:
+ TRESPASS();
+ }
+
mMeta->setInt32(kKeySampleRate, sample_rate);
mMeta->setInt32(kKeyBitRate, bitrate * 1000);
mMeta->setInt32(kKeyChannelCount, num_channels);
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 01f1fba..444e823 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -30,6 +30,8 @@
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I = "audio/mpeg-L1";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II = "audio/mpeg-L2";
const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
@@ -45,6 +47,7 @@
const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index a8023df..2221268 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -24,6 +24,7 @@
#include "include/MPEG4Extractor.h"
#include "include/WAVExtractor.h"
#include "include/OggExtractor.h"
+#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
#include "include/DRMExtractor.h"
#include "include/WVMExtractor.h"
@@ -115,6 +116,8 @@
ret = new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
ret = new AACExtractor(source);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
+ ret = new MPEG2PSExtractor(source);
}
if (ret != NULL) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7c34257..86bd267 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -102,6 +102,7 @@
{ MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, "OMX.Nvidia.mp2.decoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
@@ -1462,7 +1463,9 @@
mOutputPortSettingsChangedPending(false),
mLeftOverBuffer(NULL),
mPaused(false),
- mNativeWindow(!strncmp(componentName, "OMX.google.", 11)
+ mNativeWindow(
+ (!strncmp(componentName, "OMX.google.", 11)
+ || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode"))
? NULL : nativeWindow) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
@@ -1483,6 +1486,12 @@
static const MimeToRole kMimeToRole[] = {
{ MEDIA_MIMETYPE_AUDIO_MPEG,
"audio_decoder.mp3", "audio_encoder.mp3" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+ "audio_decoder.mp1", "audio_encoder.mp1" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+ "audio_decoder.mp2", "audio_encoder.mp2" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG,
+ "audio_decoder.mp3", "audio_encoder.mp3" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB,
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 571e8be27..bb6e4cd 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -38,7 +38,7 @@
".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
- ".avi",
+ ".avi", ".mpeg", ".mpg"
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
deleted file mode 100644
index 2bd5be6..0000000
--- a/media/libstagefright/include/ARTSPController.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef A_RTSP_CONTROLLER_H_
-
-#define A_RTSP_CONTROLLER_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/MediaExtractor.h>
-
-namespace android {
-
-struct ALooper;
-struct MyHandler;
-
-struct ARTSPController : public MediaExtractor {
- ARTSPController(const sp<ALooper> &looper);
-
- void setUID(uid_t uid);
-
- status_t connect(const char *url);
- void disconnect();
-
- void seekAsync(int64_t timeUs, void (*seekDoneCb)(void *), void *cookie);
-
- virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
-
- virtual sp<MetaData> getTrackMetaData(
- size_t index, uint32_t flags);
-
- int64_t getNormalPlayTimeUs();
- int64_t getQueueDurationUs(bool *eos);
-
- void onMessageReceived(const sp<AMessage> &msg);
-
- virtual uint32_t flags() const {
- // Seeking 10secs forward or backward is a very expensive operation
- // for rtsp, so let's not enable that.
- // The user can always use the seek bar.
-
- return CAN_PAUSE | CAN_SEEK;
- }
-
-protected:
- virtual ~ARTSPController();
-
-private:
- enum {
- kWhatConnectDone = 'cdon',
- kWhatDisconnectDone = 'ddon',
- kWhatSeekDone = 'sdon',
- };
-
- enum State {
- DISCONNECTED,
- CONNECTED,
- CONNECTING,
- };
-
- Mutex mLock;
- Condition mCondition;
-
- State mState;
- status_t mConnectionResult;
-
- sp<ALooper> mLooper;
- sp<MyHandler> mHandler;
- sp<AHandlerReflector<ARTSPController> > mReflector;
-
- bool mUIDValid;
- uid_t mUID;
-
- void (*mSeekDoneCb)(void *);
- void *mSeekDoneCookie;
- int64_t mLastSeekCompletedTimeUs;
-
- DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
-};
-
-} // namespace android
-
-#endif // A_RTSP_CONTROLLER_H_
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 8e73121..7d6bcad 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -38,9 +38,6 @@
struct NuCachedSource2;
struct ISurfaceTexture;
-struct ALooper;
-struct ARTSPController;
-
class DrmManagerClinet;
class DecryptHandle;
@@ -233,10 +230,6 @@
sp<HTTPBase> mConnectingDataSource;
sp<NuCachedSource2> mCachedSource;
- sp<ALooper> mLooper;
- sp<ARTSPController> mRTSPController;
- sp<ARTSPController> mConnectingRTSPController;
-
DrmManagerClient *mDrmManagerClient;
sp<DecryptHandle> mDecryptHandle;
@@ -287,9 +280,6 @@
static bool ContinuePreparation(void *cookie);
- static void OnRTSPSeekDoneWrapper(void *cookie);
- void onRTSPSeekDone();
-
bool getBitrate(int64_t *bitrate);
void finishSeekIfNecessary(int64_t videoTimeUs);
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
new file mode 100644
index 0000000..fb76564
--- /dev/null
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 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 MPEG2_PS_EXTRACTOR_H_
+
+#define MPEG2_PS_EXTRACTOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct ABuffer;
+struct AMessage;
+struct Track;
+struct String8;
+
+struct MPEG2PSExtractor : public MediaExtractor {
+ MPEG2PSExtractor(const sp<DataSource> &source);
+
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+ virtual sp<MetaData> getMetaData();
+
+ virtual uint32_t flags() const;
+
+protected:
+ virtual ~MPEG2PSExtractor();
+
+private:
+ struct Track;
+ struct WrappedTrack;
+
+ mutable Mutex mLock;
+ sp<DataSource> mDataSource;
+
+ off64_t mOffset;
+ status_t mFinalResult;
+ sp<ABuffer> mBuffer;
+ KeyedVector<unsigned, sp<Track> > mTracks;
+ bool mScanning;
+
+ bool mProgramStreamMapValid;
+ KeyedVector<unsigned, unsigned> mStreamTypeByESID;
+
+ status_t feedMore();
+
+ status_t dequeueChunk();
+ ssize_t dequeuePack();
+ ssize_t dequeueSystemHeader();
+ ssize_t dequeuePES();
+
+ DISALLOW_EVIL_CONSTRUCTORS(MPEG2PSExtractor);
+};
+
+bool SniffMPEG2PS(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
+
+} // namespace android
+
+#endif // MPEG2_PS_EXTRACTOR_H_
+
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 388cb54..878e534 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -64,12 +64,9 @@
bool PTSTimeDeltaEstablished();
-protected:
- virtual ~ATSParser();
-
-private:
enum {
// From ISO/IEC 13818-1: 2000 (E), Table 2-29
+ STREAMTYPE_RESERVED = 0x00,
STREAMTYPE_MPEG1_VIDEO = 0x01,
STREAMTYPE_MPEG2_VIDEO = 0x02,
STREAMTYPE_MPEG1_AUDIO = 0x03,
@@ -79,6 +76,10 @@
STREAMTYPE_H264 = 0x1b,
};
+protected:
+ virtual ~ATSParser();
+
+private:
struct Program;
struct Stream;
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 4a30416..578c669 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -6,6 +6,7 @@
AnotherPacketSource.cpp \
ATSParser.cpp \
ESQueue.cpp \
+ MPEG2PSExtractor.cpp \
MPEG2TSExtractor.cpp \
LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index a56da36..b9a4826 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -585,6 +585,8 @@
return NULL;
}
+ unsigned layer = 4 - ((header >> 17) & 3);
+
sp<ABuffer> accessUnit = new ABuffer(frameSize);
memcpy(accessUnit->data(), data, frameSize);
@@ -601,7 +603,24 @@
if (mFormat == NULL) {
mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+
+ switch (layer) {
+ case 1:
+ mFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+ break;
+ case 2:
+ mFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ break;
+ case 3:
+ mFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ break;
+ default:
+ TRESPASS();
+ }
+
mFormat->setInt32(kKeySampleRate, samplingRate);
mFormat->setInt32(kKeyChannelCount, numChannels);
}
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
new file mode 100644
index 0000000..f55be6e
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2PSExtractor"
+#include <utils/Log.h>
+
+#include "include/MPEG2PSExtractor.h"
+
+#include "AnotherPacketSource.h"
+#include "ESQueue.h"
+
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct MPEG2PSExtractor::Track : public MediaSource {
+ Track(MPEG2PSExtractor *extractor,
+ unsigned stream_id, unsigned stream_type);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+ virtual ~Track();
+
+private:
+ friend struct MPEG2PSExtractor;
+
+ MPEG2PSExtractor *mExtractor;
+
+ unsigned mStreamID;
+ unsigned mStreamType;
+ ElementaryStreamQueue *mQueue;
+ sp<AnotherPacketSource> mSource;
+
+ status_t appendPESData(
+ unsigned PTS_DTS_flags,
+ uint64_t PTS, uint64_t DTS,
+ const uint8_t *data, size_t size);
+
+ DISALLOW_EVIL_CONSTRUCTORS(Track);
+};
+
+struct MPEG2PSExtractor::WrappedTrack : public MediaSource {
+ WrappedTrack(const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+ virtual ~WrappedTrack();
+
+private:
+ sp<MPEG2PSExtractor> mExtractor;
+ sp<MPEG2PSExtractor::Track> mTrack;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WrappedTrack);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::MPEG2PSExtractor(const sp<DataSource> &source)
+ : mDataSource(source),
+ mOffset(0),
+ mFinalResult(OK),
+ mBuffer(new ABuffer(0)),
+ mScanning(true),
+ mProgramStreamMapValid(false) {
+ for (size_t i = 0; i < 500; ++i) {
+ if (feedMore() != OK) {
+ break;
+ }
+ }
+
+ // Remove all tracks that were unable to determine their format.
+ for (size_t i = mTracks.size(); i-- > 0;) {
+ if (mTracks.valueAt(i)->getFormat() == NULL) {
+ mTracks.removeItemsAt(i);
+ }
+ }
+
+ mScanning = false;
+}
+
+MPEG2PSExtractor::~MPEG2PSExtractor() {
+}
+
+size_t MPEG2PSExtractor::countTracks() {
+ return mTracks.size();
+}
+
+sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+ if (index >= mTracks.size()) {
+ return NULL;
+ }
+
+ return new WrappedTrack(this, mTracks.valueAt(index));
+}
+
+sp<MetaData> MPEG2PSExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+ if (index >= mTracks.size()) {
+ return NULL;
+ }
+
+ return mTracks.valueAt(index)->getFormat();
+}
+
+sp<MetaData> MPEG2PSExtractor::getMetaData() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
+
+ return meta;
+}
+
+uint32_t MPEG2PSExtractor::flags() const {
+ return CAN_PAUSE;
+}
+
+status_t MPEG2PSExtractor::feedMore() {
+ Mutex::Autolock autoLock(mLock);
+
+ // How much data we're reading at a time
+ static const size_t kChunkSize = 8192;
+
+ for (;;) {
+ status_t err = dequeueChunk();
+
+ if (err == -EAGAIN && mFinalResult == OK) {
+ memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
+ mBuffer->setRange(0, mBuffer->size());
+
+ if (mBuffer->size() + kChunkSize > mBuffer->capacity()) {
+ size_t newCapacity = mBuffer->capacity() + kChunkSize;
+ sp<ABuffer> newBuffer = new ABuffer(newCapacity);
+ memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
+ newBuffer->setRange(0, mBuffer->size());
+ mBuffer = newBuffer;
+ }
+
+ ssize_t n = mDataSource->readAt(
+ mOffset, mBuffer->data() + mBuffer->size(), kChunkSize);
+
+ if (n < (ssize_t)kChunkSize) {
+ mFinalResult = (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
+ return mFinalResult;
+ }
+
+ mBuffer->setRange(mBuffer->offset(), mBuffer->size() + n);
+ mOffset += n;
+ } else if (err != OK) {
+ mFinalResult = err;
+ return err;
+ } else {
+ return OK;
+ }
+ }
+}
+
+status_t MPEG2PSExtractor::dequeueChunk() {
+ if (mBuffer->size() < 4) {
+ return -EAGAIN;
+ }
+
+ if (memcmp("\x00\x00\x01", mBuffer->data(), 3)) {
+ return ERROR_MALFORMED;
+ }
+
+ unsigned chunkType = mBuffer->data()[3];
+
+ ssize_t res;
+
+ switch (chunkType) {
+ case 0xba:
+ {
+ res = dequeuePack();
+ break;
+ }
+
+ case 0xbb:
+ {
+ res = dequeueSystemHeader();
+ break;
+ }
+
+ default:
+ {
+ res = dequeuePES();
+ break;
+ }
+ }
+
+ if (res > 0) {
+ if (mBuffer->size() < (size_t)res) {
+ return -EAGAIN;
+ }
+
+ mBuffer->setRange(mBuffer->offset() + res, mBuffer->size() - res);
+ res = OK;
+ }
+
+ return res;
+}
+
+ssize_t MPEG2PSExtractor::dequeuePack() {
+ // 32 + 2 + 3 + 1 + 15 + 1 + 15+ 1 + 9 + 1 + 22 + 1 + 1 | +5
+
+ if (mBuffer->size() < 14) {
+ return -EAGAIN;
+ }
+
+ unsigned pack_stuffing_length = mBuffer->data()[13] & 7;
+
+ return pack_stuffing_length + 14;
+}
+
+ssize_t MPEG2PSExtractor::dequeueSystemHeader() {
+ if (mBuffer->size() < 6) {
+ return -EAGAIN;
+ }
+
+ unsigned header_length = U16_AT(mBuffer->data() + 4);
+
+ return header_length + 6;
+}
+
+ssize_t MPEG2PSExtractor::dequeuePES() {
+ if (mBuffer->size() < 6) {
+ return -EAGAIN;
+ }
+
+ unsigned PES_packet_length = U16_AT(mBuffer->data() + 4);
+ CHECK_NE(PES_packet_length, 0u);
+
+ size_t n = PES_packet_length + 6;
+
+ if (mBuffer->size() < n) {
+ return -EAGAIN;
+ }
+
+ ABitReader br(mBuffer->data(), n);
+
+ unsigned packet_startcode_prefix = br.getBits(24);
+
+ LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
+
+ if (packet_startcode_prefix != 1) {
+ LOGV("Supposedly payload_unit_start=1 unit does not start "
+ "with startcode.");
+
+ return ERROR_MALFORMED;
+ }
+
+ CHECK_EQ(packet_startcode_prefix, 0x000001u);
+
+ unsigned stream_id = br.getBits(8);
+ LOGV("stream_id = 0x%02x", stream_id);
+
+ /* unsigned PES_packet_length = */br.getBits(16);
+
+ if (stream_id == 0xbc) {
+ // program_stream_map
+
+ if (!mScanning) {
+ return n;
+ }
+
+ mStreamTypeByESID.clear();
+
+ /* unsigned current_next_indicator = */br.getBits(1);
+ /* unsigned reserved = */br.getBits(2);
+ /* unsigned program_stream_map_version = */br.getBits(5);
+ /* unsigned reserved = */br.getBits(7);
+ /* unsigned marker_bit = */br.getBits(1);
+ unsigned program_stream_info_length = br.getBits(16);
+
+ size_t offset = 0;
+ while (offset < program_stream_info_length) {
+ if (offset + 2 > program_stream_info_length) {
+ return ERROR_MALFORMED;
+ }
+
+ unsigned descriptor_tag = br.getBits(8);
+ unsigned descriptor_length = br.getBits(8);
+
+ LOGI("found descriptor tag 0x%02x of length %u",
+ descriptor_tag, descriptor_length);
+
+ if (offset + 2 + descriptor_length > program_stream_info_length) {
+ return ERROR_MALFORMED;
+ }
+
+ br.skipBits(8 * descriptor_length);
+
+ offset += 2 + descriptor_length;
+ }
+
+ unsigned elementary_stream_map_length = br.getBits(16);
+
+ offset = 0;
+ while (offset < elementary_stream_map_length) {
+ if (offset + 4 > elementary_stream_map_length) {
+ return ERROR_MALFORMED;
+ }
+
+ unsigned stream_type = br.getBits(8);
+ unsigned elementary_stream_id = br.getBits(8);
+
+ LOGI("elementary stream id 0x%02x has stream type 0x%02x",
+ elementary_stream_id, stream_type);
+
+ mStreamTypeByESID.add(elementary_stream_id, stream_type);
+
+ unsigned elementary_stream_info_length = br.getBits(16);
+
+ if (offset + 4 + elementary_stream_info_length
+ > elementary_stream_map_length) {
+ return ERROR_MALFORMED;
+ }
+
+ offset += 4 + elementary_stream_info_length;
+ }
+
+ /* unsigned CRC32 = */br.getBits(32);
+
+ mProgramStreamMapValid = true;
+ } else if (stream_id != 0xbe // padding_stream
+ && stream_id != 0xbf // private_stream_2
+ && stream_id != 0xf0 // ECM
+ && stream_id != 0xf1 // EMM
+ && stream_id != 0xff // program_stream_directory
+ && stream_id != 0xf2 // DSMCC
+ && stream_id != 0xf8) { // H.222.1 type E
+ CHECK_EQ(br.getBits(2), 2u);
+
+ /* unsigned PES_scrambling_control = */br.getBits(2);
+ /* unsigned PES_priority = */br.getBits(1);
+ /* unsigned data_alignment_indicator = */br.getBits(1);
+ /* unsigned copyright = */br.getBits(1);
+ /* unsigned original_or_copy = */br.getBits(1);
+
+ unsigned PTS_DTS_flags = br.getBits(2);
+ LOGV("PTS_DTS_flags = %u", PTS_DTS_flags);
+
+ unsigned ESCR_flag = br.getBits(1);
+ LOGV("ESCR_flag = %u", ESCR_flag);
+
+ unsigned ES_rate_flag = br.getBits(1);
+ LOGV("ES_rate_flag = %u", ES_rate_flag);
+
+ unsigned DSM_trick_mode_flag = br.getBits(1);
+ LOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag);
+
+ unsigned additional_copy_info_flag = br.getBits(1);
+ LOGV("additional_copy_info_flag = %u", additional_copy_info_flag);
+
+ /* unsigned PES_CRC_flag = */br.getBits(1);
+ /* PES_extension_flag = */br.getBits(1);
+
+ unsigned PES_header_data_length = br.getBits(8);
+ LOGV("PES_header_data_length = %u", PES_header_data_length);
+
+ unsigned optional_bytes_remaining = PES_header_data_length;
+
+ uint64_t PTS = 0, DTS = 0;
+
+ if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+ CHECK_GE(optional_bytes_remaining, 5u);
+
+ CHECK_EQ(br.getBits(4), PTS_DTS_flags);
+
+ PTS = ((uint64_t)br.getBits(3)) << 30;
+ CHECK_EQ(br.getBits(1), 1u);
+ PTS |= ((uint64_t)br.getBits(15)) << 15;
+ CHECK_EQ(br.getBits(1), 1u);
+ PTS |= br.getBits(15);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ LOGV("PTS = %llu", PTS);
+ // LOGI("PTS = %.2f secs", PTS / 90000.0f);
+
+ optional_bytes_remaining -= 5;
+
+ if (PTS_DTS_flags == 3) {
+ CHECK_GE(optional_bytes_remaining, 5u);
+
+ CHECK_EQ(br.getBits(4), 1u);
+
+ DTS = ((uint64_t)br.getBits(3)) << 30;
+ CHECK_EQ(br.getBits(1), 1u);
+ DTS |= ((uint64_t)br.getBits(15)) << 15;
+ CHECK_EQ(br.getBits(1), 1u);
+ DTS |= br.getBits(15);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ LOGV("DTS = %llu", DTS);
+
+ optional_bytes_remaining -= 5;
+ }
+ }
+
+ if (ESCR_flag) {
+ CHECK_GE(optional_bytes_remaining, 6u);
+
+ br.getBits(2);
+
+ uint64_t ESCR = ((uint64_t)br.getBits(3)) << 30;
+ CHECK_EQ(br.getBits(1), 1u);
+ ESCR |= ((uint64_t)br.getBits(15)) << 15;
+ CHECK_EQ(br.getBits(1), 1u);
+ ESCR |= br.getBits(15);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ LOGV("ESCR = %llu", ESCR);
+ /* unsigned ESCR_extension = */br.getBits(9);
+
+ CHECK_EQ(br.getBits(1), 1u);
+
+ optional_bytes_remaining -= 6;
+ }
+
+ if (ES_rate_flag) {
+ CHECK_GE(optional_bytes_remaining, 3u);
+
+ CHECK_EQ(br.getBits(1), 1u);
+ /* unsigned ES_rate = */br.getBits(22);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ optional_bytes_remaining -= 3;
+ }
+
+ br.skipBits(optional_bytes_remaining * 8);
+
+ // ES data follows.
+
+ CHECK_GE(PES_packet_length, PES_header_data_length + 3);
+
+ unsigned dataLength =
+ PES_packet_length - 3 - PES_header_data_length;
+
+ if (br.numBitsLeft() < dataLength * 8) {
+ LOGE("PES packet does not carry enough data to contain "
+ "payload. (numBitsLeft = %d, required = %d)",
+ br.numBitsLeft(), dataLength * 8);
+
+ return ERROR_MALFORMED;
+ }
+
+ CHECK_GE(br.numBitsLeft(), dataLength * 8);
+
+ ssize_t index = mTracks.indexOfKey(stream_id);
+ if (index < 0 && mScanning) {
+ unsigned streamType;
+
+ ssize_t streamTypeIndex;
+ if (mProgramStreamMapValid
+ && (streamTypeIndex =
+ mStreamTypeByESID.indexOfKey(stream_id)) >= 0) {
+ streamType = mStreamTypeByESID.valueAt(streamTypeIndex);
+ } else if ((stream_id & ~0x1f) == 0xc0) {
+ // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7
+ // or ISO/IEC 14496-3 audio
+ streamType = ATSParser::STREAMTYPE_MPEG2_AUDIO;
+ } else if ((stream_id & ~0x0f) == 0xe0) {
+ // ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC 14496-2 video
+ streamType = ATSParser::STREAMTYPE_MPEG2_VIDEO;
+ } else {
+ streamType = ATSParser::STREAMTYPE_RESERVED;
+ }
+
+ index = mTracks.add(
+ stream_id, new Track(this, stream_id, streamType));
+ }
+
+ status_t err = OK;
+
+ if (index >= 0) {
+ err =
+ mTracks.editValueAt(index)->appendPESData(
+ PTS_DTS_flags, PTS, DTS, br.data(), dataLength);
+ }
+
+ br.skipBits(dataLength * 8);
+
+ if (err != OK) {
+ return err;
+ }
+ } else if (stream_id == 0xbe) { // padding_stream
+ CHECK_NE(PES_packet_length, 0u);
+ br.skipBits(PES_packet_length * 8);
+ } else {
+ CHECK_NE(PES_packet_length, 0u);
+ br.skipBits(PES_packet_length * 8);
+ }
+
+ return n;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::Track::Track(
+ MPEG2PSExtractor *extractor, unsigned stream_id, unsigned stream_type)
+ : mExtractor(extractor),
+ mStreamID(stream_id),
+ mStreamType(stream_type),
+ mQueue(NULL) {
+ bool supported = true;
+ ElementaryStreamQueue::Mode mode;
+
+ switch (mStreamType) {
+ case ATSParser::STREAMTYPE_H264:
+ mode = ElementaryStreamQueue::H264;
+ break;
+ case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS:
+ mode = ElementaryStreamQueue::AAC;
+ break;
+ case ATSParser::STREAMTYPE_MPEG1_AUDIO:
+ case ATSParser::STREAMTYPE_MPEG2_AUDIO:
+ mode = ElementaryStreamQueue::MPEG_AUDIO;
+ break;
+
+ case ATSParser::STREAMTYPE_MPEG1_VIDEO:
+ case ATSParser::STREAMTYPE_MPEG2_VIDEO:
+ mode = ElementaryStreamQueue::MPEG_VIDEO;
+ break;
+
+ case ATSParser::STREAMTYPE_MPEG4_VIDEO:
+ mode = ElementaryStreamQueue::MPEG4_VIDEO;
+ break;
+
+ default:
+ supported = false;
+ break;
+ }
+
+ if (supported) {
+ mQueue = new ElementaryStreamQueue(mode);
+ } else {
+ LOGI("unsupported stream ID 0x%02x", stream_id);
+ }
+}
+
+MPEG2PSExtractor::Track::~Track() {
+ delete mQueue;
+ mQueue = NULL;
+}
+
+status_t MPEG2PSExtractor::Track::start(MetaData *params) {
+ if (mSource == NULL) {
+ return NO_INIT;
+ }
+
+ return mSource->start(params);
+}
+
+status_t MPEG2PSExtractor::Track::stop() {
+ if (mSource == NULL) {
+ return NO_INIT;
+ }
+
+ return mSource->stop();
+}
+
+sp<MetaData> MPEG2PSExtractor::Track::getFormat() {
+ if (mSource == NULL) {
+ return NULL;
+ }
+
+ return mSource->getFormat();
+}
+
+status_t MPEG2PSExtractor::Track::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ if (mSource == NULL) {
+ return NO_INIT;
+ }
+
+ status_t finalResult;
+ while (!mSource->hasBufferAvailable(&finalResult)) {
+ if (finalResult != OK) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ status_t err = mExtractor->feedMore();
+
+ if (err != OK) {
+ mSource->signalEOS(err);
+ }
+ }
+
+ return mSource->read(buffer, options);
+}
+
+status_t MPEG2PSExtractor::Track::appendPESData(
+ unsigned PTS_DTS_flags,
+ uint64_t PTS, uint64_t DTS,
+ const uint8_t *data, size_t size) {
+ if (mQueue == NULL) {
+ return OK;
+ }
+
+ int64_t timeUs;
+ if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+ timeUs = (PTS * 100) / 9;
+ } else {
+ timeUs = 0;
+ }
+
+ status_t err = mQueue->appendData(data, size, timeUs);
+
+ if (err != OK) {
+ return err;
+ }
+
+ sp<ABuffer> accessUnit;
+ while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
+ if (mSource == NULL) {
+ sp<MetaData> meta = mQueue->getFormat();
+
+ if (meta != NULL) {
+ LOGV("Stream ID 0x%02x now has data.", mStreamID);
+
+ mSource = new AnotherPacketSource(meta);
+ mSource->queueAccessUnit(accessUnit);
+ }
+ } else if (mQueue->getFormat() != NULL) {
+ mSource->queueAccessUnit(accessUnit);
+ }
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::WrappedTrack::WrappedTrack(
+ const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track)
+ : mExtractor(extractor),
+ mTrack(track) {
+}
+
+MPEG2PSExtractor::WrappedTrack::~WrappedTrack() {
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::start(MetaData *params) {
+ return mTrack->start(params);
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::stop() {
+ return mTrack->stop();
+}
+
+sp<MetaData> MPEG2PSExtractor::WrappedTrack::getFormat() {
+ return mTrack->getFormat();
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ return mTrack->read(buffer, options);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffMPEG2PS(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
+ uint8_t header[5];
+ if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return false;
+ }
+
+ if (memcmp("\x00\x00\x01\xba", header, 4) || (header[4] >> 6) != 1) {
+ return false;
+ }
+
+ *confidence = 0.25f; // Slightly larger than .mp3 extractor's confidence
+
+ mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
+
+ return true;
+}
+
+} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 4ecb92f..3f4cdb5 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -34,8 +34,8 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <utils/Vector.h>
@@ -402,43 +402,15 @@
return csd;
}
-static bool GetClockRate(const AString &desc, uint32_t *clockRate) {
- ssize_t slashPos = desc.find("/");
- if (slashPos < 0) {
- return false;
- }
-
- const char *s = desc.c_str() + slashPos + 1;
-
- char *end;
- unsigned long x = strtoul(s, &end, 10);
-
- if (end == s || (*end != '\0' && *end != '/')) {
- return false;
- }
-
- *clockRate = x;
-
- return true;
-}
-
APacketSource::APacketSource(
const sp<ASessionDescription> &sessionDesc, size_t index)
: mInitCheck(NO_INIT),
- mFormat(new MetaData),
- mEOSResult(OK),
- mIsAVC(false),
- mScanForIDR(true),
- mRTPTimeBase(0),
- mNormalPlayTimeBaseUs(0),
- mLastNormalPlayTimeUs(0) {
+ mFormat(new MetaData) {
unsigned long PT;
AString desc;
AString params;
sessionDesc->getFormatType(index, &PT, &desc, ¶ms);
- CHECK(GetClockRate(desc, &mClockRate));
-
int64_t durationUs;
if (sessionDesc->getDurationUs(&durationUs)) {
mFormat->setInt64(kKeyDuration, durationUs);
@@ -448,8 +420,6 @@
mInitCheck = OK;
if (!strncmp(desc.c_str(), "H264/", 5)) {
- mIsAVC = true;
-
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
int32_t width, height;
@@ -602,137 +572,8 @@
return mInitCheck;
}
-status_t APacketSource::start(MetaData *params) {
- return OK;
-}
-
-status_t APacketSource::stop() {
- return OK;
-}
-
sp<MetaData> APacketSource::getFormat() {
return mFormat;
}
-status_t APacketSource::read(
- MediaBuffer **out, const ReadOptions *) {
- *out = NULL;
-
- Mutex::Autolock autoLock(mLock);
- while (mEOSResult == OK && mBuffers.empty()) {
- mCondition.wait(mLock);
- }
-
- if (!mBuffers.empty()) {
- const sp<ABuffer> buffer = *mBuffers.begin();
-
- updateNormalPlayTime_l(buffer);
-
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
- mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
- *out = mediaBuffer;
-
- mBuffers.erase(mBuffers.begin());
- return OK;
- }
-
- return mEOSResult;
-}
-
-void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) {
- uint32_t rtpTime;
- CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
- mLastNormalPlayTimeUs =
- (((double)rtpTime - (double)mRTPTimeBase) / mClockRate)
- * 1000000ll
- + mNormalPlayTimeBaseUs;
-}
-
-void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
- int32_t damaged;
- if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
- LOGV("discarding damaged AU");
- return;
- }
-
- if (mScanForIDR && mIsAVC) {
- // This pretty piece of code ensures that the first access unit
- // fed to the decoder after stream-start or seek is guaranteed to
- // be an IDR frame. This is to workaround limitations of a certain
- // hardware h.264 decoder that requires this to be the case.
-
- if (!IsIDR(buffer)) {
- LOGV("skipping AU while scanning for next IDR frame.");
- return;
- }
-
- mScanForIDR = false;
- }
-
- Mutex::Autolock autoLock(mLock);
- mBuffers.push_back(buffer);
- mCondition.signal();
-}
-
-void APacketSource::signalEOS(status_t result) {
- CHECK(result != OK);
-
- Mutex::Autolock autoLock(mLock);
- mEOSResult = result;
- mCondition.signal();
-}
-
-void APacketSource::flushQueue() {
- Mutex::Autolock autoLock(mLock);
- mBuffers.clear();
-
- mScanForIDR = true;
-}
-
-int64_t APacketSource::getNormalPlayTimeUs() {
- Mutex::Autolock autoLock(mLock);
- return mLastNormalPlayTimeUs;
-}
-
-void APacketSource::setNormalPlayTimeMapping(
- uint32_t rtpTime, int64_t normalPlayTimeUs) {
- Mutex::Autolock autoLock(mLock);
-
- mRTPTimeBase = rtpTime;
- mNormalPlayTimeBaseUs = normalPlayTimeUs;
-}
-
-int64_t APacketSource::getQueueDurationUs(bool *eos) {
- Mutex::Autolock autoLock(mLock);
-
- *eos = (mEOSResult != OK);
-
- if (mBuffers.size() < 2) {
- return 0;
- }
-
- const sp<ABuffer> first = *mBuffers.begin();
- const sp<ABuffer> last = *--mBuffers.end();
-
- int64_t firstTimeUs;
- CHECK(first->meta()->findInt64("timeUs", &firstTimeUs));
-
- int64_t lastTimeUs;
- CHECK(last->meta()->findInt64("timeUs", &lastTimeUs));
-
- if (lastTimeUs < firstTimeUs) {
- LOGE("Huh? Time moving backwards? %lld > %lld",
- firstTimeUs, lastTimeUs);
-
- return 0;
- }
-
- return lastTimeUs - firstTimeUs;
-}
-
} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 7a77fc6..530e537 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -19,63 +19,27 @@
#define A_PACKET_SOURCE_H_
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-#include <utils/List.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/RefBase.h>
namespace android {
-struct ABuffer;
struct ASessionDescription;
-struct APacketSource : public MediaSource {
+struct APacketSource : public RefBase {
APacketSource(const sp<ASessionDescription> &sessionDesc, size_t index);
status_t initCheck() const;
- virtual status_t start(MetaData *params = NULL);
- virtual status_t stop();
virtual sp<MetaData> getFormat();
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
- void queueAccessUnit(const sp<ABuffer> &buffer);
- void signalEOS(status_t result);
-
- void flushQueue();
-
- int64_t getNormalPlayTimeUs();
-
- void setNormalPlayTimeMapping(
- uint32_t rtpTime, int64_t normalPlayTimeUs);
-
- int64_t getQueueDurationUs(bool *eos);
-
protected:
virtual ~APacketSource();
private:
status_t mInitCheck;
- Mutex mLock;
- Condition mCondition;
-
sp<MetaData> mFormat;
- List<sp<ABuffer> > mBuffers;
- status_t mEOSResult;
-
- bool mIsAVC;
- bool mScanForIDR;
-
- uint32_t mClockRate;
-
- uint32_t mRTPTimeBase;
- int64_t mNormalPlayTimeBaseUs;
-
- int64_t mLastNormalPlayTimeUs;
-
- void updateNormalPlayTime_l(const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(APacketSource);
};
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
deleted file mode 100644
index 2ebae7e..0000000
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ARTSPController.h"
-
-#include "MyHandler.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-ARTSPController::ARTSPController(const sp<ALooper> &looper)
- : mState(DISCONNECTED),
- mLooper(looper),
- mUIDValid(false),
- mSeekDoneCb(NULL),
- mSeekDoneCookie(NULL),
- mLastSeekCompletedTimeUs(-1) {
- mReflector = new AHandlerReflector<ARTSPController>(this);
- looper->registerHandler(mReflector);
-}
-
-ARTSPController::~ARTSPController() {
- CHECK_EQ((int)mState, (int)DISCONNECTED);
- mLooper->unregisterHandler(mReflector->id());
-}
-
-void ARTSPController::setUID(uid_t uid) {
- mUIDValid = true;
- mUID = uid;
-}
-
-status_t ARTSPController::connect(const char *url) {
- Mutex::Autolock autoLock(mLock);
-
- if (mState != DISCONNECTED) {
- return ERROR_ALREADY_CONNECTED;
- }
-
- sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
-
- mHandler = new MyHandler(url, mLooper, mUIDValid, mUID);
-
- mState = CONNECTING;
-
- mHandler->connect(msg);
-
- while (mState == CONNECTING) {
- mCondition.wait(mLock);
- }
-
- if (mState != CONNECTED) {
- mHandler.clear();
- }
-
- return mConnectionResult;
-}
-
-void ARTSPController::disconnect() {
- Mutex::Autolock autoLock(mLock);
-
- if (mState == CONNECTING) {
- mState = DISCONNECTED;
- mConnectionResult = ERROR_IO;
- mCondition.broadcast();
-
- mHandler.clear();
- return;
- } else if (mState != CONNECTED) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatDisconnectDone, mReflector->id());
- mHandler->disconnect(msg);
-
- while (mState == CONNECTED) {
- mCondition.wait(mLock);
- }
-
- mHandler.clear();
-}
-
-void ARTSPController::seekAsync(
- int64_t timeUs,
- void (*seekDoneCb)(void *), void *cookie) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(seekDoneCb != NULL);
- CHECK(mSeekDoneCb == NULL);
-
- // Ignore seek requests that are too soon after the previous one has
- // completed, we don't want to swamp the server.
-
- bool tooEarly =
- mLastSeekCompletedTimeUs >= 0
- && ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
-
- if (mState != CONNECTED || tooEarly) {
- (*seekDoneCb)(cookie);
- return;
- }
-
- mSeekDoneCb = seekDoneCb;
- mSeekDoneCookie = cookie;
-
- sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
- mHandler->seek(timeUs, msg);
-}
-
-size_t ARTSPController::countTracks() {
- if (mHandler == NULL) {
- return 0;
- }
-
- return mHandler->countTracks();
-}
-
-sp<MediaSource> ARTSPController::getTrack(size_t index) {
- CHECK(mHandler != NULL);
-
- return mHandler->getPacketSource(index);
-}
-
-sp<MetaData> ARTSPController::getTrackMetaData(
- size_t index, uint32_t flags) {
- CHECK(mHandler != NULL);
-
- return mHandler->getPacketSource(index)->getFormat();
-}
-
-void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatConnectDone:
- {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(msg->findInt32("result", &mConnectionResult));
- mState = (mConnectionResult == OK) ? CONNECTED : DISCONNECTED;
-
- mCondition.signal();
- break;
- }
-
- case kWhatDisconnectDone:
- {
- Mutex::Autolock autoLock(mLock);
- mState = DISCONNECTED;
- mCondition.signal();
- break;
- }
-
- case kWhatSeekDone:
- {
- LOGI("seek done");
-
- mLastSeekCompletedTimeUs = ALooper::GetNowUs();
-
- void (*seekDoneCb)(void *) = mSeekDoneCb;
- mSeekDoneCb = NULL;
-
- (*seekDoneCb)(mSeekDoneCookie);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-int64_t ARTSPController::getNormalPlayTimeUs() {
- CHECK(mHandler != NULL);
- return mHandler->getNormalPlayTimeUs();
-}
-
-int64_t ARTSPController::getQueueDurationUs(bool *eos) {
- *eos = true;
-
- int64_t minQueuedDurationUs = 0;
- for (size_t i = 0; i < mHandler->countTracks(); ++i) {
- sp<APacketSource> source = mHandler->getPacketSource(i);
-
- bool newEOS;
- int64_t queuedDurationUs = source->getQueueDurationUs(&newEOS);
-
- if (!newEOS) {
- *eos = false;
- }
-
- if (i == 0 || queuedDurationUs < minQueuedDurationUs) {
- minQueuedDurationUs = queuedDurationUs;
- }
- }
-
- return minQueuedDurationUs;
-}
-
-} // namespace android
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 8530ff3..8230347 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -15,7 +15,6 @@
ARTPSource.cpp \
ARTPWriter.cpp \
ARTSPConnection.cpp \
- ARTSPController.cpp \
ASessionDescription.cpp \
LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 8128813..af7dd23 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -94,12 +94,24 @@
}
struct MyHandler : public AHandler {
+ enum {
+ kWhatConnected = 'conn',
+ kWhatDisconnected = 'disc',
+ kWhatSeekDone = 'sdon',
+
+ kWhatAccessUnit = 'accU',
+ kWhatEOS = 'eos!',
+ kWhatSeekDiscontinuity = 'seeD',
+ kWhatNormalPlayTimeMapping = 'nptM',
+ };
+
MyHandler(
- const char *url, const sp<ALooper> &looper,
+ const char *url,
+ const sp<AMessage> ¬ify,
bool uidValid = false, uid_t uid = 0)
- : mUIDValid(uidValid),
+ : mNotify(notify),
+ mUIDValid(uidValid),
mUID(uid),
- mLooper(looper),
mNetLooper(new ALooper),
mConn(new ARTSPConnection(mUIDValid, mUID)),
mRTPConn(new ARTPConnection),
@@ -145,12 +157,9 @@
mSessionHost = host;
}
- void connect(const sp<AMessage> &doneMsg) {
- mDoneMsg = doneMsg;
-
- mLooper->registerHandler(this);
- mLooper->registerHandler(mConn);
- (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
+ void connect() {
+ looper()->registerHandler(mConn);
+ (1 ? mNetLooper : looper())->registerHandler(mRTPConn);
sp<AMessage> notify = new AMessage('biny', id());
mConn->observeBinaryData(notify);
@@ -159,33 +168,16 @@
mConn->connect(mOriginalSessionURL.c_str(), reply);
}
- void disconnect(const sp<AMessage> &doneMsg) {
- mDoneMsg = doneMsg;
-
+ void disconnect() {
(new AMessage('abor', id()))->post();
}
- void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
+ void seek(int64_t timeUs) {
sp<AMessage> msg = new AMessage('seek', id());
msg->setInt64("time", timeUs);
- msg->setMessage("doneMsg", doneMsg);
msg->post();
}
- int64_t getNormalPlayTimeUs() {
- int64_t maxTimeUs = 0;
- for (size_t i = 0; i < mTracks.size(); ++i) {
- int64_t timeUs = mTracks.editItemAt(i).mPacketSource
- ->getNormalPlayTimeUs();
-
- if (i == 0 || timeUs > maxTimeUs) {
- maxTimeUs = timeUs;
- }
- }
-
- return maxTimeUs;
- }
-
static void addRR(const sp<ABuffer> &buf) {
uint8_t *ptr = buf->data() + buf->size();
ptr[0] = 0x80 | 0;
@@ -619,7 +611,9 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
TrackInfo *info = &mTracks.editItemAt(i);
- info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
+ if (!mFirstAccessUnit) {
+ postQueueEOS(i, ERROR_END_OF_STREAM);
+ }
if (!info->mUsingInterleavedTCP) {
mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
@@ -690,11 +684,10 @@
case 'quit':
{
- if (mDoneMsg != NULL) {
- mDoneMsg->setInt32("result", UNKNOWN_ERROR);
- mDoneMsg->post();
- mDoneMsg = NULL;
- }
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatDisconnected);
+ msg->setInt32("result", UNKNOWN_ERROR);
+ msg->post();
break;
}
@@ -795,17 +788,12 @@
case 'seek':
{
- sp<AMessage> doneMsg;
- CHECK(msg->findMessage("doneMsg", &doneMsg));
-
- if (mSeekPending) {
- doneMsg->post();
- break;
- }
-
if (!mSeekable) {
LOGW("This is a live stream, ignoring seek request.");
- doneMsg->post();
+
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatSeekDone);
+ msg->post();
break;
}
@@ -831,7 +819,6 @@
sp<AMessage> reply = new AMessage('see1', id());
reply->setInt64("time", timeUs);
- reply->setMessage("doneMsg", doneMsg);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -842,7 +829,8 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
TrackInfo *info = &mTracks.editItemAt(i);
- info->mPacketSource->flushQueue();
+ postQueueSeekDiscontinuity(i);
+
info->mRTPAnchor = 0;
info->mNTPAnchorUs = -1;
}
@@ -866,11 +854,7 @@
request.append("\r\n");
- sp<AMessage> doneMsg;
- CHECK(msg->findMessage("doneMsg", &doneMsg));
-
sp<AMessage> reply = new AMessage('see2', id());
- reply->setMessage("doneMsg", doneMsg);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -915,10 +899,9 @@
mSeekPending = false;
- sp<AMessage> doneMsg;
- CHECK(msg->findMessage("doneMsg", &doneMsg));
-
- doneMsg->post();
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatSeekDone);
+ msg->post();
break;
}
@@ -1056,8 +1039,14 @@
LOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
- info->mPacketSource->setNormalPlayTimeMapping(
- rtpTime, (int64_t)(npt1 * 1E6));
+ info->mNormalPlayTimeRTP = rtpTime;
+ info->mNormalPlayTimeUs = (int64_t)(npt1 * 1E6);
+
+ if (!mFirstAccessUnit) {
+ postNormalPlayTimeMapping(
+ trackIndex,
+ info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+ }
++n;
}
@@ -1065,11 +1054,15 @@
mSeekable = true;
}
- sp<APacketSource> getPacketSource(size_t index) {
+ sp<MetaData> getTrackFormat(size_t index, int32_t *timeScale) {
CHECK_GE(index, 0u);
CHECK_LT(index, mTracks.size());
- return mTracks.editItemAt(index).mPacketSource;
+ const TrackInfo &info = mTracks.itemAt(index);
+
+ *timeScale = info.mTimeScale;
+
+ return info.mPacketSource->getFormat();
}
size_t countTracks() const {
@@ -1089,6 +1082,9 @@
int64_t mNTPAnchorUs;
int32_t mTimeScale;
+ uint32_t mNormalPlayTimeRTP;
+ int64_t mNormalPlayTimeUs;
+
sp<APacketSource> mPacketSource;
// Stores packets temporarily while no notion of time
@@ -1096,9 +1092,9 @@
List<sp<ABuffer> > mPackets;
};
+ sp<AMessage> mNotify;
bool mUIDValid;
uid_t mUID;
- sp<ALooper> mLooper;
sp<ALooper> mNetLooper;
sp<ARTSPConnection> mConn;
sp<ARTPConnection> mRTPConn;
@@ -1127,8 +1123,6 @@
Vector<TrackInfo> mTracks;
- sp<AMessage> mDoneMsg;
-
void setupTrack(size_t index) {
sp<APacketSource> source =
new APacketSource(mSessionDesc, index);
@@ -1158,6 +1152,8 @@
info->mNewSegment = true;
info->mRTPAnchor = 0;
info->mNTPAnchorUs = -1;
+ info->mNormalPlayTimeRTP = 0;
+ info->mNormalPlayTimeUs = 0ll;
unsigned long PT;
AString formatDesc;
@@ -1283,9 +1279,17 @@
LOGV("onAccessUnitComplete track %d", trackIndex);
if (mFirstAccessUnit) {
- mDoneMsg->setInt32("result", OK);
- mDoneMsg->post();
- mDoneMsg = NULL;
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatConnected);
+ msg->post();
+
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ TrackInfo *info = &mTracks.editItemAt(i);
+
+ postNormalPlayTimeMapping(
+ i,
+ info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+ }
mFirstAccessUnit = false;
}
@@ -1303,12 +1307,12 @@
track->mPackets.erase(track->mPackets.begin());
if (addMediaTimestamp(trackIndex, track, accessUnit)) {
- track->mPacketSource->queueAccessUnit(accessUnit);
+ postQueueAccessUnit(trackIndex, accessUnit);
}
}
if (addMediaTimestamp(trackIndex, track, accessUnit)) {
- track->mPacketSource->queueAccessUnit(accessUnit);
+ postQueueAccessUnit(trackIndex, accessUnit);
}
}
@@ -1344,6 +1348,39 @@
return true;
}
+ void postQueueAccessUnit(
+ size_t trackIndex, const sp<ABuffer> &accessUnit) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatAccessUnit);
+ msg->setSize("trackIndex", trackIndex);
+ msg->setObject("accessUnit", accessUnit);
+ msg->post();
+ }
+
+ void postQueueEOS(size_t trackIndex, status_t finalResult) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatEOS);
+ msg->setSize("trackIndex", trackIndex);
+ msg->setInt32("finalResult", finalResult);
+ msg->post();
+ }
+
+ void postQueueSeekDiscontinuity(size_t trackIndex) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatSeekDiscontinuity);
+ msg->setSize("trackIndex", trackIndex);
+ msg->post();
+ }
+
+ void postNormalPlayTimeMapping(
+ size_t trackIndex, uint32_t rtpTime, int64_t nptUs) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatNormalPlayTimeMapping);
+ msg->setSize("trackIndex", trackIndex);
+ msg->setInt32("rtpTime", rtpTime);
+ msg->setInt64("nptUs", nptUs);
+ msg->post();
+ }
DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
};
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 4c7f84e..0b4f403 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -768,6 +768,9 @@
* {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
*/
public interface EGLWindowSurfaceFactory {
+ /**
+ * @return null if the surface cannot be constructed.
+ */
EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
Object nativeWindow);
void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
@@ -777,7 +780,19 @@
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
EGLConfig config, Object nativeWindow) {
- return egl.eglCreateWindowSurface(display, config, nativeWindow, null);
+ EGLSurface result = null;
+ try {
+ result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
+ } catch (IllegalArgumentException e) {
+ // This exception indicates that the surface flinger surface
+ // is not valid. This can happen if the surface flinger surface has
+ // been torn down, but the application has not yet been
+ // notified via SurfaceHolder.Callback.surfaceDestroyed.
+ // In theory the application should be notified first,
+ // but in practice sometimes it is not. See b/4588890
+ Log.e(TAG, "eglCreateWindowSurface", e);
+ }
+ return result;
}
public void destroySurface(EGL10 egl, EGLDisplay display,
@@ -1041,9 +1056,8 @@
int error = mEgl.eglGetError();
if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
- return null;
}
- throwEglException("createWindowSurface", error);
+ return null;
}
/*
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index b05705e..bcb1aa2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -238,6 +238,11 @@
* Notify our observers of an interface removal.
*/
private void notifyInterfaceRemoved(String iface) {
+ // netd already clears out quota and alerts for removed ifaces; update
+ // our sanity-checking state.
+ mActiveAlertIfaces.remove(iface);
+ mActiveQuotaIfaces.remove(iface);
+
for (INetworkManagementEventObserver obs : mObservers) {
try {
obs.interfaceRemoved(iface);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index feb2c52..b695903 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -368,18 +368,6 @@
mCurrentScalingMode);
if (!isFixedSize()) {
- // we're being resized and there is a freeze display request,
- // acquire a freeze lock, so that the screen stays put
- // until we've redrawn at the new size; this is to avoid
- // glitches upon orientation changes.
- if (mFlinger->hasFreezeRequest()) {
- // if the surface is hidden, don't try to acquire the
- // freeze lock, since hidden surfaces may never redraw
- if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
- mFreezeLock = mFlinger->getFreezeLock();
- }
- }
-
// this will make sure LayerBase::doTransaction doesn't update
// the drawing state's size
Layer::State& editDraw(mDrawingState);
@@ -393,14 +381,6 @@
temp.requested_h);
}
- if (temp.sequence != front.sequence) {
- if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
- // this surface is now hidden, so it shouldn't hold a freeze lock
- // (it may never redraw, which is fine if it is hidden)
- mFreezeLock.clear();
- }
- }
-
return LayerBase::doTransaction(flags);
}
@@ -474,7 +454,7 @@
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- // update the layer size and release freeze-lock
+ // update the layer size if needed
const Layer::State& front(drawingState());
// FIXME: mPostedDirtyRegion = dirty & bounds
@@ -511,9 +491,6 @@
// recompute visible region
recomputeVisibleRegions = true;
-
- // we now have the correct size, unfreeze the screen
- mFreezeLock.clear();
}
LOGD_IF(DEBUG_RESIZE,
@@ -546,11 +523,6 @@
dirtyRegion.andSelf(visibleRegionScreen);
outDirtyRegion.orSelf(dirtyRegion);
}
- if (visibleRegionScreen.isEmpty()) {
- // an invisible layer should not hold a freeze-lock
- // (because it may never be updated and therefore never release it)
- mFreezeLock.clear();
- }
}
void Layer::dump(String8& result, char* buffer, size_t SIZE) const
@@ -568,9 +540,9 @@
snprintf(buffer, SIZE,
" "
"format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
- " freezeLock=%p, transform-hint=0x%02x, queued-frames=%d\n",
+ " transform-hint=0x%02x, queued-frames=%d\n",
mFormat, w0, h0, s0,f0,
- getFreezeLock().get(), getTransformHint(), mQueuedFrames);
+ getTransformHint(), mQueuedFrames);
result.append(buffer);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 82e3521..2b9471b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -39,7 +39,6 @@
// ---------------------------------------------------------------------------
-class FreezeLock;
class Client;
class GLExtensions;
@@ -80,7 +79,6 @@
virtual wp<IBinder> getSurfaceTextureBinder() const;
// only for debugging
- inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
protected:
@@ -124,9 +122,6 @@
bool mProtectedByApp; // application requires protected path to external sink
Region mPostedDirtyRegion;
- // page-flip thread and transaction thread (currently main thread)
- sp<FreezeLock> mFreezeLock;
-
// binder thread, transaction thread
mutable Mutex mLock;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7c0cd9b..7a8952a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -79,15 +79,12 @@
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
- mResizeTransationPending(false),
+ mTransationPending(false),
mLayersRemoved(false),
mBootTime(systemTime()),
mVisibleRegionsDirty(false),
mHwWorkListDirty(false),
- mFreezeDisplay(false),
mElectronBeamAnimationMode(0),
- mFreezeCount(0),
- mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugBackground(0),
mDebugDDMS(0),
@@ -190,11 +187,6 @@
{
// the window manager died on us. prepare its eulogy.
- // unfreeze the screen in case it was... frozen
- mFreezeDisplayTime = 0;
- mFreezeCount = 0;
- mFreezeDisplay = false;
-
// reset screen orientation
setOrientation(0, eOrientationDefault, 0);
@@ -322,33 +314,7 @@
{
while (true) {
nsecs_t timeout = -1;
- const nsecs_t freezeDisplayTimeout = ms2ns(5000);
- if (UNLIKELY(isFrozen())) {
- // wait 5 seconds
- const nsecs_t now = systemTime();
- if (mFreezeDisplayTime == 0) {
- mFreezeDisplayTime = now;
- }
- nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
- timeout = waitTime>0 ? waitTime : 0;
- }
-
sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
-
- // see if we timed out
- if (isFrozen()) {
- const nsecs_t now = systemTime();
- nsecs_t frozenTime = (now - mFreezeDisplayTime);
- if (frozenTime >= freezeDisplayTimeout) {
- // we timed out and are still frozen
- LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
- mFreezeDisplay, mFreezeCount);
- mFreezeDisplayTime = 0;
- mFreezeCount = 0;
- mFreezeDisplay = false;
- }
- }
-
if (msg != 0) {
switch (msg->what) {
case MessageQueue::INVALIDATE:
@@ -580,13 +546,6 @@
mDirtyRegion.set(hw.bounds());
}
- if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
- // freezing or unfreezing the display -> trigger animation if needed
- mFreezeDisplay = mCurrentState.freezeDisplay;
- if (mFreezeDisplay)
- mFreezeDisplayTime = 0;
- }
-
if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
// layers have been added
mVisibleRegionsDirty = true;
@@ -612,11 +571,6 @@
commitTransaction();
}
-sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
-{
- return new FreezeLock(const_cast<SurfaceFlinger *>(this));
-}
-
void SurfaceFlinger::computeVisibleRegions(
const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
{
@@ -746,7 +700,7 @@
void SurfaceFlinger::commitTransaction()
{
mDrawingState = mCurrentState;
- mResizeTransationPending = false;
+ mTransationPending = false;
mTransactionCV.broadcast();
}
@@ -1233,15 +1187,14 @@
void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state,
- int orientation) {
+ int orientation, uint32_t flags) {
Mutex::Autolock _l(mStateLock);
- uint32_t flags = 0;
+ uint32_t transactionFlags = 0;
if (mCurrentState.orientation != orientation) {
if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
mCurrentState.orientation = orientation;
- flags |= eTransactionNeeded;
- mResizeTransationPending = true;
+ transactionFlags |= eTransactionNeeded;
} else if (orientation != eOrientationUnchanged) {
LOGW("setTransactionState: ignoring unrecognized orientation: %d",
orientation);
@@ -1252,56 +1205,29 @@
for (size_t i=0 ; i<count ; i++) {
const ComposerState& s(state[i]);
sp<Client> client( static_cast<Client *>(s.client.get()) );
- flags |= setClientStateLocked(client, s.state);
+ transactionFlags |= setClientStateLocked(client, s.state);
}
- if (flags) {
- setTransactionFlags(flags);
+ if (transactionFlags) {
+ setTransactionFlags(transactionFlags);
}
- signalEvent();
-
- // if there is a transaction with a resize, wait for it to
- // take effect before returning.
- while (mResizeTransationPending) {
+ // if this is a synchronous transaction, wait for it to take effect before
+ // returning.
+ if (flags & eSynchronous) {
+ mTransationPending = true;
+ }
+ while (mTransationPending) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
// called after a few seconds.
LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
- mResizeTransationPending = false;
+ mTransationPending = false;
break;
}
}
}
-status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
-{
- if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
- return BAD_VALUE;
-
- Mutex::Autolock _l(mStateLock);
- mCurrentState.freezeDisplay = 1;
- setTransactionFlags(eTransactionNeeded);
-
- // flags is intended to communicate some sort of animation behavior
- // (for instance fading)
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
-{
- if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
- return BAD_VALUE;
-
- Mutex::Autolock _l(mStateLock);
- mCurrentState.freezeDisplay = 0;
- setTransactionFlags(eTransactionNeeded);
-
- // flags is intended to communicate some sort of animation behavior
- // (for instance fading)
- return NO_ERROR;
-}
-
int SurfaceFlinger::setOrientation(DisplayID dpy,
int orientation, uint32_t flags)
{
@@ -1487,7 +1413,6 @@
if (what & eSizeChanged) {
if (layer->setSize(s.w, s.h)) {
flags |= eTraversalNeeded;
- mResizeTransationPending = true;
}
}
if (what & eAlphaChanged) {
@@ -1607,8 +1532,7 @@
mWormholeRegion.dump(result, "WormholeRegion");
const DisplayHardware& hw(graphicPlane(0).displayHardware());
snprintf(buffer, SIZE,
- " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
- mFreezeDisplay?"yes":"no", mFreezeCount,
+ " orientation=%d, canDraw=%d\n",
mCurrentState.orientation, hw.canDraw());
result.append(buffer);
snprintf(buffer, SIZE,
@@ -1661,8 +1585,6 @@
case CREATE_CONNECTION:
case SET_TRANSACTION_STATE:
case SET_ORIENTATION:
- case FREEZE_DISPLAY:
- case UNFREEZE_DISPLAY:
case BOOT_FINISHED:
case TURN_ELECTRON_BEAM_OFF:
case TURN_ELECTRON_BEAM_ON:
@@ -1734,10 +1656,6 @@
GraphicLog::getInstance().setEnabled(enabled);
return NO_ERROR;
}
- case 1007: // set mFreezeCount
- mFreezeCount = data.readInt32();
- mFreezeDisplayTime = 0;
- return NO_ERROR;
case 1008: // toggle use of hw composer
n = data.readInt32();
mDebugDisableHWC = n ? 1 : 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0e642c1..eabcc9d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -46,7 +46,6 @@
class Client;
class DisplayHardware;
-class FreezeLock;
class Layer;
class LayerDim;
struct surface_flinger_cblk_t;
@@ -168,9 +167,7 @@
virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
virtual void setTransactionState(const Vector<ComposerState>& state,
- int orientation);
- virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags);
- virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
+ int orientation, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual bool authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const;
@@ -244,12 +241,10 @@
struct State {
State() {
orientation = ISurfaceComposer::eOrientationDefault;
- freezeDisplay = 0;
}
LayerVector layersSortedByZ;
uint8_t orientation;
uint8_t orientationFlags;
- uint8_t freezeDisplay;
};
virtual bool threadLoop();
@@ -308,20 +303,6 @@
status_t renderScreenToTextureLocked(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
- friend class FreezeLock;
- sp<FreezeLock> getFreezeLock() const;
- inline void incFreezeCount() {
- if (mFreezeCount == 0)
- mFreezeDisplayTime = 0;
- mFreezeCount++;
- }
- inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
- inline bool hasFreezeRequest() const { return mFreezeDisplay; }
- inline bool isFrozen() const {
- return (mFreezeDisplay || mFreezeCount>0) && mBootFinished;
- }
-
-
void debugFlashRegions();
void debugShowFPS() const;
void drawWormhole() const;
@@ -341,7 +322,7 @@
volatile int32_t mTransactionFlags;
Condition mTransactionCV;
SortedVector< sp<LayerBase> > mLayerPurgatory;
- bool mResizeTransationPending;
+ bool mTransationPending;
// protected by mStateLock (but we could use another lock)
GraphicPlane mGraphicPlanes[1];
@@ -364,10 +345,7 @@
Region mWormholeRegion;
bool mVisibleRegionsDirty;
bool mHwWorkListDirty;
- bool mFreezeDisplay;
int32_t mElectronBeamAnimationMode;
- int32_t mFreezeCount;
- nsecs_t mFreezeDisplayTime;
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
@@ -403,20 +381,6 @@
};
// ---------------------------------------------------------------------------
-
-class FreezeLock : public LightRefBase<FreezeLock> {
- SurfaceFlinger* mFlinger;
-public:
- FreezeLock(SurfaceFlinger* flinger)
- : mFlinger(flinger) {
- mFlinger->incFreezeCount();
- }
- ~FreezeLock() {
- mFlinger->decFreezeCount();
- }
-};
-
-// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 5053e7d..b655648 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -1 +1,40 @@
-include $(call all-subdir-makefiles)
+# Build the unit tests,
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SurfaceFlinger_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ Transaction_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libEGL \
+ libGLESv2 \
+ libandroid \
+ libbinder \
+ libcutils \
+ libgui \
+ libstlport \
+ libui \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport \
+
+# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+# to integrate with auto-test framework.
+include $(BUILD_NATIVE_TEST)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
new file mode 100644
index 0000000..afafd8a
--- /dev/null
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
+ uint8_t r, uint8_t g, uint8_t b) {
+ Surface::SurfaceInfo info;
+ sp<Surface> s = sc->getSurface();
+ ASSERT_TRUE(s != NULL);
+ ASSERT_EQ(NO_ERROR, s->lock(&info));
+ uint8_t* img = reinterpret_cast<uint8_t*>(info.bits);
+ for (uint32_t y = 0; y < info.h; y++) {
+ for (uint32_t x = 0; x < info.w; x++) {
+ uint8_t* pixel = img + (4 * (y*info.s + x));
+ pixel[0] = r;
+ pixel[1] = g;
+ pixel[2] = b;
+ pixel[3] = 255;
+ }
+ }
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+}
+
+// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
+// individual pixel values for testing purposes.
+class ScreenCapture : public RefBase {
+public:
+ static void captureScreen(sp<ScreenCapture>* sc) {
+ sp<IMemoryHeap> heap;
+ uint32_t w=0, h=0;
+ PixelFormat fmt=0;
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 0, 0,
+ 0, INT_MAX));
+ ASSERT_TRUE(heap != NULL);
+ ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
+ *sc = new ScreenCapture(w, h, heap);
+ }
+
+ void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+ const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
+ const uint8_t* pixel = img + (4 * (y*mWidth + x));
+ if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+ String8 err(String8::format("pixel @ (%3d, %3d): "
+ "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+ x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+ EXPECT_EQ(String8(), err);
+ }
+ }
+
+private:
+ ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
+ mWidth(w),
+ mHeight(h),
+ mHeap(heap)
+ {}
+
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ sp<IMemoryHeap> mHeap;
+};
+
+class LayerUpdateTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ ssize_t displayWidth = mComposerClient->getDisplayWidth(0);
+ ssize_t displayHeight = mComposerClient->getDisplayHeight(0);
+
+ // Background surface
+ mBGSurfaceControl = mComposerClient->createSurface(
+ String8("BG Test Surface"), 0, displayWidth, displayHeight,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != NULL);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+ fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
+
+ // Foreground surface
+ mFGSurfaceControl = mComposerClient->createSurface(
+ String8("FG Test Surface"), 0, 64, 64, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mFGSurfaceControl != NULL);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+
+ // Synchronization surface
+ mSyncSurfaceControl = mComposerClient->createSurface(
+ String8("Sync Test Surface"), 0, 1, 1, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mSyncSurfaceControl != NULL);
+ ASSERT_TRUE(mSyncSurfaceControl->isValid());
+
+ fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+
+ SurfaceComposerClient::openGlobalTransaction();
+
+ ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2));
+ ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX-1));
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+
+ ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT_MAX-1));
+ ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2,
+ displayHeight-2));
+ ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show());
+
+ SurfaceComposerClient::closeGlobalTransaction(true);
+ }
+
+ virtual void TearDown() {
+ mComposerClient->dispose();
+ mBGSurfaceControl = 0;
+ mFGSurfaceControl = 0;
+ mSyncSurfaceControl = 0;
+ mComposerClient = 0;
+ }
+
+ void waitForPostedBuffers() {
+ // Since the sync surface is in synchronous mode (i.e. double buffered)
+ // posting three buffers to it should ensure that at least two
+ // SurfaceFlinger::handlePageFlip calls have been made, which should
+ // guaranteed that a buffer posted to another Surface has been retired.
+ fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ }
+
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mFGSurfaceControl;
+
+ // This surface is used to ensure that the buffers posted to
+ // mFGSurfaceControl have been picked up by SurfaceFlinger.
+ sp<SurfaceControl> mSyncSurfaceControl;
+};
+
+TEST_F(LayerUpdateTest, LayerMoveWorks) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before move");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 0, 12, 63, 63, 195);
+ sc->checkPixel( 75, 75, 195, 63, 63);
+ sc->checkPixel(145, 145, 63, 63, 195);
+ }
+
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
+ SurfaceComposerClient::closeGlobalTransaction(true);
+ {
+ // This should reflect the new position, but not the new color.
+ SCOPED_TRACE("after move, before redraw");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 24, 24, 63, 63, 195);
+ sc->checkPixel( 75, 75, 63, 63, 195);
+ sc->checkPixel(145, 145, 195, 63, 63);
+ }
+
+ fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+ waitForPostedBuffers();
+ {
+ // This should reflect the new position and the new color.
+ SCOPED_TRACE("after redraw");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 24, 24, 63, 63, 195);
+ sc->checkPixel( 75, 75, 63, 63, 195);
+ sc->checkPixel(145, 145, 63, 195, 63);
+ }
+}
+
+TEST_F(LayerUpdateTest, LayerResizeWorks) {
+ sp<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before resize");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 0, 12, 63, 63, 195);
+ sc->checkPixel( 75, 75, 195, 63, 63);
+ sc->checkPixel(145, 145, 63, 63, 195);
+ }
+
+ LOGD("resizing");
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
+ SurfaceComposerClient::closeGlobalTransaction(true);
+ LOGD("resized");
+ {
+ // This should not reflect the new size or color because SurfaceFlinger
+ // has not yet received a buffer of the correct size.
+ SCOPED_TRACE("after resize, before redraw");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 0, 12, 63, 63, 195);
+ sc->checkPixel( 75, 75, 195, 63, 63);
+ sc->checkPixel(145, 145, 63, 63, 195);
+ }
+
+ LOGD("drawing");
+ fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+ waitForPostedBuffers();
+ LOGD("drawn");
+ {
+ // This should reflect the new size and the new color.
+ SCOPED_TRACE("after redraw");
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel( 24, 24, 63, 63, 195);
+ sc->checkPixel( 75, 75, 63, 195, 63);
+ sc->checkPixel(145, 145, 63, 195, 63);
+ }
+}
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index 3471ec2..a66e19d 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -19,166 +19,20 @@
import android.content.ContentProvider;
import android.content.UriMatcher;
import android.content.ContentValues;
-import android.database.AbstractCursor;
import android.database.Cursor;
-import android.database.CursorWindow;
+import android.database.MatrixCursor;
import android.net.Uri;
-import android.os.SystemProperties;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.Log;
-import java.util.ArrayList;
import java.util.List;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.AdnRecord;
import com.android.internal.telephony.IIccPhoneBook;
-/**
- * XXX old code -- should be replaced with MatrixCursor.
- * @deprecated This is has been replaced by MatrixCursor.
-*/
-class ArrayListCursor extends AbstractCursor {
- private String[] mColumnNames;
- private ArrayList<Object>[] mRows;
-
- @SuppressWarnings({"unchecked"})
- public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
- int colCount = columnNames.length;
- boolean foundID = false;
- // Add an _id column if not in columnNames
- for (int i = 0; i < colCount; ++i) {
- if (columnNames[i].compareToIgnoreCase("_id") == 0) {
- mColumnNames = columnNames;
- foundID = true;
- break;
- }
- }
-
- if (!foundID) {
- mColumnNames = new String[colCount + 1];
- System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
- mColumnNames[colCount] = "_id";
- }
-
- int rowCount = rows.size();
- mRows = new ArrayList[rowCount];
-
- for (int i = 0; i < rowCount; ++i) {
- mRows[i] = rows.get(i);
- if (!foundID) {
- mRows[i].add(i);
- }
- }
- }
-
- @Override
- public void fillWindow(int position, CursorWindow window) {
- if (position < 0 || position > getCount()) {
- return;
- }
-
- window.acquireReference();
- try {
- int oldpos = mPos;
- mPos = position - 1;
- window.clear();
- window.setStartPosition(position);
- int columnNum = getColumnCount();
- window.setNumColumns(columnNum);
- while (moveToNext() && window.allocRow()) {
- for (int i = 0; i < columnNum; i++) {
- final Object data = mRows[mPos].get(i);
- if (data != null) {
- if (data instanceof byte[]) {
- byte[] field = (byte[]) data;
- if (!window.putBlob(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- } else {
- String field = data.toString();
- if (!window.putString(field, mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- } else {
- if (!window.putNull(mPos, i)) {
- window.freeLastRow();
- break;
- }
- }
- }
- }
-
- mPos = oldpos;
- } catch (IllegalStateException e){
- // simply ignore it
- } finally {
- window.releaseReference();
- }
- }
-
- @Override
- public int getCount() {
- return mRows.length;
- }
-
- @Override
- public String[] getColumnNames() {
- return mColumnNames;
- }
-
- @Override
- public byte[] getBlob(int columnIndex) {
- return (byte[]) mRows[mPos].get(columnIndex);
- }
-
- @Override
- public String getString(int columnIndex) {
- Object cell = mRows[mPos].get(columnIndex);
- return (cell == null) ? null : cell.toString();
- }
-
- @Override
- public short getShort(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.shortValue();
- }
-
- @Override
- public int getInt(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.intValue();
- }
-
- @Override
- public long getLong(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.longValue();
- }
-
- @Override
- public float getFloat(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.floatValue();
- }
-
- @Override
- public double getDouble(int columnIndex) {
- Number num = (Number) mRows[mPos].get(columnIndex);
- return num.doubleValue();
- }
-
- @Override
- public boolean isNull(int columnIndex) {
- return mRows[mPos].get(columnIndex) == null;
- }
-}
-
/**
* {@hide}
@@ -191,7 +45,8 @@
private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
"name",
"number",
- "emails"
+ "emails",
+ "_id"
};
private static final int ADN = 1;
@@ -213,70 +68,27 @@
}
- private boolean mSimulator;
-
@Override
public boolean onCreate() {
- String device = SystemProperties.get("ro.product.device");
- if (!TextUtils.isEmpty(device)) {
- mSimulator = false;
- } else {
- // simulator
- mSimulator = true;
- }
-
return true;
}
@Override
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
- ArrayList<ArrayList> results;
+ switch (URL_MATCHER.match(url)) {
+ case ADN:
+ return loadFromEf(IccConstants.EF_ADN);
- if (!mSimulator) {
- switch (URL_MATCHER.match(url)) {
- case ADN:
- results = loadFromEf(IccConstants.EF_ADN);
- break;
+ case FDN:
+ return loadFromEf(IccConstants.EF_FDN);
- case FDN:
- results = loadFromEf(IccConstants.EF_FDN);
- break;
+ case SDN:
+ return loadFromEf(IccConstants.EF_SDN);
- case SDN:
- results = loadFromEf(IccConstants.EF_SDN);
- break;
-
- default:
- throw new IllegalArgumentException("Unknown URL " + url);
- }
- } else {
- // Fake up some data for the simulator
- results = new ArrayList<ArrayList>(4);
- ArrayList<String> contact;
-
- contact = new ArrayList<String>();
- contact.add("Ron Stevens/H");
- contact.add("512-555-5038");
- results.add(contact);
-
- contact = new ArrayList<String>();
- contact.add("Ron Stevens/M");
- contact.add("512-555-8305");
- results.add(contact);
-
- contact = new ArrayList<String>();
- contact.add("Melissa Owens");
- contact.add("512-555-8305");
- results.add(contact);
-
- contact = new ArrayList<String>();
- contact.add("Directory Assistence");
- contact.add("411");
- results.add(contact);
+ default:
+ throw new IllegalArgumentException("Unknown URL " + url);
}
-
- return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
}
@Override
@@ -473,12 +285,10 @@
return 1;
}
- private ArrayList<ArrayList> loadFromEf(int efType) {
- ArrayList<ArrayList> results = new ArrayList<ArrayList>();
- List<AdnRecord> adnRecords = null;
-
+ private MatrixCursor loadFromEf(int efType) {
if (DBG) log("loadFromEf: efType=" + efType);
+ List<AdnRecord> adnRecords = null;
try {
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
ServiceManager.getService("simphonebook"));
@@ -490,21 +300,21 @@
} catch (SecurityException ex) {
if (DBG) log(ex.toString());
}
+
if (adnRecords != null) {
// Load the results
-
- int N = adnRecords.size();
+ final int N = adnRecords.size();
+ final MatrixCursor cursor = new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES, N);
if (DBG) log("adnRecords.size=" + N);
for (int i = 0; i < N ; i++) {
- loadRecord(adnRecords.get(i), results);
+ loadRecord(adnRecords.get(i), cursor, i);
}
+ return cursor;
} else {
// No results to load
Log.w(TAG, "Cannot load ADN records");
- results.clear();
+ return new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES);
}
- if (DBG) log("loadFromEf: return results");
- return results;
}
private boolean
@@ -584,35 +394,33 @@
}
/**
- * Loads an AdnRecord into an ArrayList. Must be called with mLock held.
+ * Loads an AdnRecord into a MatrixCursor. Must be called with mLock held.
*
* @param record the ADN record to load from
- * @param results the array list to put the results in
+ * @param cursor the cursor to receive the results
*/
- private void loadRecord(AdnRecord record,
- ArrayList<ArrayList> results) {
+ private void loadRecord(AdnRecord record, MatrixCursor cursor, int id) {
if (!record.isEmpty()) {
- ArrayList<String> contact = new ArrayList<String>();
+ Object[] contact = new Object[4];
String alphaTag = record.getAlphaTag();
String number = record.getNumber();
- String[] emails = record.getEmails();
if (DBG) log("loadRecord: " + alphaTag + ", " + number + ",");
- contact.add(alphaTag);
- contact.add(number);
- StringBuilder emailString = new StringBuilder();
+ contact[0] = alphaTag;
+ contact[1] = number;
+ String[] emails = record.getEmails();
if (emails != null) {
+ StringBuilder emailString = new StringBuilder();
for (String email: emails) {
if (DBG) log("Adding email:" + email);
emailString.append(email);
emailString.append(",");
}
- contact.add(emailString.toString());
- } else {
- contact.add(null);
+ contact[2] = emailString.toString();
}
- results.add(contact);
+ contact[3] = id;
+ cursor.addRow(contact);
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index 3232eedc..414ae0d 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -22,9 +22,11 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;
import android.os.Bundle;
+import android.os.Environment;
import android.util.Log;
import android.view.Gravity;
import android.view.TextureView;
@@ -39,6 +41,7 @@
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
import java.io.BufferedOutputStream;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -65,7 +68,8 @@
Bitmap b = mTextureView.getBitmap(800, 800);
BufferedOutputStream out = null;
try {
- out = new BufferedOutputStream(new FileOutputStream("/sdcard/out.png"));
+ File dump = new File(Environment.getExternalStorageDirectory(), "out.png");
+ out = new BufferedOutputStream(new FileOutputStream(dump));
b.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (FileNotFoundException e) {
e.printStackTrace();
@@ -168,10 +172,10 @@
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
- -1.0f, -1.0f, 0, 0.f, 0.f,
- 1.0f, -1.0f, 0, 1.f, 0.f,
- -1.0f, 1.0f, 0, 0.f, 1.f,
- 1.0f, 1.0f, 0, 1.f, 1.f,
+ -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
};
@Override
@@ -212,8 +216,6 @@
while (!mFinished) {
checkCurrent();
- Log.d(LOG_TAG, "Rendering frame");
-
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
checkGlError();
@@ -237,7 +239,7 @@
checkEglError();
try {
- Thread.sleep(20);
+ Thread.sleep(2000);
} catch (InterruptedException e) {
// Ignore
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index fcb57d9..0f4c668 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -17,16 +17,23 @@
package com.android.test.hwui;
import android.app.Activity;
+import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
+import android.os.Environment;
import android.view.Gravity;
+import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
@SuppressWarnings({"UnusedDeclaration"})
@@ -44,6 +51,26 @@
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
+ mTextureView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bitmap b = mTextureView.getBitmap(800, 800);
+ BufferedOutputStream out = null;
+ try {
+ File dump = new File(Environment.getExternalStorageDirectory(), "out.png");
+ out = new BufferedOutputStream(new FileOutputStream(dump));
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ if (out != null) try {
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
Button button = new Button(this);
button.setText("Remove/Add");
@@ -73,6 +100,8 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
+ mCamera.setDisplayOrientation(getCameraOrientation());
+
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
previewSize.width, previewSize.height, Gravity.CENTER));
@@ -86,6 +115,34 @@
mCamera.startPreview();
}
+ private int getCameraOrientation() {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
+ Camera.getCameraInfo(i, info);
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) break;
+ }
+
+ int rotation = getWindowManager().getDefaultDisplay().getRotation();
+ int degrees = 0;
+
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ }
+
+ return (info.orientation - degrees + 360) % 360;
+ }
+
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
diff --git a/tests/RenderScriptTests/ComputePerf/Android.mk b/tests/RenderScriptTests/ComputePerf/Android.mk
new file mode 100644
index 0000000..1d67d29
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsComputePerf
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
new file mode 100644
index 0000000..a9193b5
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.computeperf">
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-sdk android:minSdkVersion="14" />
+ <application android:label="Compute Perf">
+ <activity android:name="ComputePerf">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/ComputePerf/res/layout/main.xml b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
new file mode 100644
index 0000000..61cd24d
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/displayin"
+ android:layout_width="320dip"
+ android:layout_height="266dip" />
+
+ <ImageView
+ android:id="@+id/displayout"
+ android:layout_width="320dip"
+ android:layout_height="266dip" />
+
+</LinearLayout>
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
new file mode 100644
index 0000000..d0e089b
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computeperf;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.renderscript.RenderScript;
+import android.renderscript.Allocation;
+import android.widget.ImageView;
+
+public class ComputePerf extends Activity {
+
+ private LaunchTest mLT;
+ private RenderScript mRS;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ mRS = RenderScript.create(this);
+ mLT = new LaunchTest(mRS, getResources());
+ mLT.run();
+ mLT.run();
+ }
+
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
new file mode 100644
index 0000000..0c29ce1
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computeperf;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class LaunchTest implements Runnable {
+ private RenderScript mRS;
+ private Allocation mAllocationX;
+ private Allocation mAllocationXY;
+ private ScriptC_launchtestxlw mScript_xlw;
+ private ScriptC_launchtestxyw mScript_xyw;
+
+ LaunchTest(RenderScript rs, Resources res) {
+ mRS = rs;
+ mScript_xlw = new ScriptC_launchtestxlw(mRS, res, R.raw.launchtestxlw);
+ mScript_xyw = new ScriptC_launchtestxyw(mRS, res, R.raw.launchtestxyw);
+ final int dim = mScript_xlw.get_dim();
+
+ mAllocationX = Allocation.createSized(rs, Element.U8(rs), dim);
+ Type.Builder tb = new Type.Builder(rs, Element.U8(rs));
+ tb.setX(dim);
+ tb.setY(dim);
+ mAllocationXY = Allocation.createTyped(rs, tb.create());
+ mScript_xlw.bind_buf(mAllocationXY);
+ }
+
+ public void run() {
+ long t = java.lang.System.currentTimeMillis();
+ mScript_xlw.forEach_root(mAllocationX);
+ mRS.finish();
+ t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("ComputePerf", "xlw launch test ms " + t);
+
+ t = java.lang.System.currentTimeMillis();
+ mScript_xyw.forEach_root(mAllocationXY);
+ mRS.finish();
+ t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("ComputePerf", "xyw launch test ms " + t);
+ }
+
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
new file mode 100644
index 0000000..7b81dfe
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computeperf)
+
+const int dim = 2048;
+uint8_t *buf;
+
+void root(uchar *v_out, uint32_t x) {
+ uint8_t *p = buf;
+ p += x * dim;
+ for (int i=0; i<dim; i++) {
+ p[i] = 1;
+ }
+}
+
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
new file mode 100644
index 0000000..7f7aa95
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computeperf)
+
+void root(uchar *v_out, uint32_t x, uint32_t y) {
+ *v_out = 0;
+}
+
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
index b77ccb4..42b1cf1 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
@@ -105,8 +105,8 @@
rsgMeshComputeBoundingBox(info->mMesh,
&minX, &minY, &minZ,
&maxX, &maxY, &maxZ);
- info->bBoxMin = (minX, minY, minZ);
- info->bBoxMax = (maxX, maxY, maxZ);
+ info->bBoxMin = (float3){minX, minY, minZ};
+ info->bBoxMax = (float3){maxX, maxY, maxZ};
gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
}
gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
index d44fd2b..05ef3ac 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
@@ -104,8 +104,8 @@
rsgMeshComputeBoundingBox(info->mMesh,
&minX, &minY, &minZ,
&maxX, &maxY, &maxZ);
- info->bBoxMin = (minX, minY, minZ);
- info->bBoxMax = (maxX, maxY, maxZ);
+ info->bBoxMin = (float3){minX, minY, minZ};
+ info->bBoxMax = (float3){maxX, maxY, maxZ};
gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
}
gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index c038478..4466e59 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,6 +64,9 @@
unitTests = new ArrayList<UnitTest>();
+ unitTests.add(new UT_sampler(this, mRes, mCtx));
+ unitTests.add(new UT_program_store(this, mRes, mCtx));
+ unitTests.add(new UT_program_raster(this, mRes, mCtx));
unitTests.add(new UT_primitives(this, mRes, mCtx));
unitTests.add(new UT_vector(this, mRes, mCtx));
unitTests.add(new UT_rsdebug(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
new file mode 100644
index 0000000..1fbf97a
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramRaster.CullMode;
+
+public class UT_program_raster extends UnitTest {
+ private Resources mRes;
+
+ protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "ProgramRaster", ctx);
+ mRes = res;
+ }
+
+ private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
+ ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
+ b.setCullMode(CullMode.BACK);
+ b.setPointSpriteEnabled(false);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
+ ProgramRaster.Builder b = getDefaultBuilder(RS);
+ s.set_pointSpriteEnabled(b.setPointSpriteEnabled(true).create());
+ b = getDefaultBuilder(RS);
+ s.set_cullMode(b.setCullMode(CullMode.FRONT).create());
+ return;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_program_raster_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
new file mode 100644
index 0000000..e06112c
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.Builder;
+import android.renderscript.ProgramStore.DepthFunc;
+
+public class UT_program_store extends UnitTest {
+ private Resources mRes;
+
+ protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "ProgramStore", ctx);
+ mRes = res;
+ }
+
+ private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
+ ProgramStore.Builder b = new ProgramStore.Builder(RS);
+ b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
+ b.setColorMaskEnabled(false, false, false, false);
+ b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ b.setDepthMaskEnabled(false);
+ b.setDitherEnabled(false);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
+ ProgramStore.Builder b = getDefaultBuilder(RS);
+ s.set_ditherEnable(b.setDitherEnabled(true).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_colorRWriteEnable(b.setColorMaskEnabled(true, false, false, false).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_colorGWriteEnable(b.setColorMaskEnabled(false, true, false, false).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_colorBWriteEnable(b.setColorMaskEnabled(false, false, true, false).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_colorAWriteEnable(b.setColorMaskEnabled(false, false, false, true).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_blendSrc(b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
+ ProgramStore.BlendDstFunc.ZERO).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_blendDst(b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
+ ProgramStore.BlendDstFunc.DST_ALPHA).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_depthWriteEnable(b.setDepthMaskEnabled(true).create());
+
+ b = getDefaultBuilder(RS);
+ s.set_depthFunc(b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create());
+ return;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_program_store_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
new file mode 100644
index 0000000..b0ccf9d
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Sampler;
+import android.renderscript.Sampler.Value;
+
+public class UT_sampler extends UnitTest {
+ private Resources mRes;
+
+ protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Sampler", ctx);
+ mRes = res;
+ }
+
+ private Sampler.Builder getDefaultBuilder(RenderScript RS) {
+ Sampler.Builder b = new Sampler.Builder(RS);
+ b.setMinification(Value.NEAREST);
+ b.setMagnification(Value.NEAREST);
+ b.setWrapS(Value.CLAMP);
+ b.setWrapT(Value.CLAMP);
+ b.setAnisotropy(1.0f);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
+ Sampler.Builder b = getDefaultBuilder(RS);
+ b.setMinification(Value.LINEAR_MIP_LINEAR);
+ s.set_minification(b.create());
+
+ b = getDefaultBuilder(RS);
+ b.setMagnification(Value.LINEAR);
+ s.set_magnification(b.create());
+
+ b = getDefaultBuilder(RS);
+ b.setWrapS(Value.WRAP);
+ s.set_wrapS(b.create());
+
+ b = getDefaultBuilder(RS);
+ b.setWrapT(Value.WRAP);
+ s.set_wrapT(b.create());
+
+ b = getDefaultBuilder(RS);
+ b.setAnisotropy(8.0f);
+ s.set_anisotropy(b.create());
+ return;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_sampler_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
new file mode 100644
index 0000000..11b8c30
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_raster pointSpriteEnabled;
+rs_program_raster cullMode;
+
+static bool test_program_raster_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+ _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+
+ _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+ _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+
+ if (failed) {
+ rsDebug("test_program_raster_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_program_raster_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void program_raster_test() {
+ bool failed = false;
+ failed |= test_program_raster_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
new file mode 100644
index 0000000..3cd8a20
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -0,0 +1,128 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_store ditherEnable;
+rs_program_store colorRWriteEnable;
+rs_program_store colorGWriteEnable;
+rs_program_store colorBWriteEnable;
+rs_program_store colorAWriteEnable;
+rs_program_store blendSrc;
+rs_program_store blendDst;
+rs_program_store depthWriteEnable;
+rs_program_store depthFunc;
+
+static bool test_program_store_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+
+ if (failed) {
+ rsDebug("test_program_store_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_program_store_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void program_store_test() {
+ bool failed = false;
+ failed |= test_program_store_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
new file mode 100644
index 0000000..ac9a549
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -0,0 +1,63 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+rs_sampler minification;
+rs_sampler magnification;
+rs_sampler wrapS;
+rs_sampler wrapT;
+rs_sampler anisotropy;
+
+static bool test_sampler_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+ _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+ _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+ _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+
+ if (failed) {
+ rsDebug("test_sampler_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_sampler_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void sampler_test() {
+ bool failed = false;
+ failed |= test_sampler_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+