summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml15
-rw-r--r--camera/libcameraservice/CameraService.cpp1
-rw-r--r--core/java/android/app/NativeActivity.java25
-rw-r--r--core/java/android/database/AbstractCursor.java4
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java7
-rw-r--r--core/java/android/database/sqlite/SQLiteProgram.java173
-rw-r--r--core/java/android/database/sqlite/SQLiteStatement.java83
-rw-r--r--core/java/android/view/GLES20Canvas.java14
-rw-r--r--core/java/android/view/HardwareRenderer.java39
-rw-r--r--core/java/android/webkit/CallbackProxy.java4
-rw-r--r--core/java/android/webkit/WebHistoryItem.java40
-rw-r--r--core/java/android/webkit/WebView.java4
-rw-r--r--core/java/android/webkit/ZoomManager.java4
-rw-r--r--core/java/android/widget/AbsListView.java78
-rw-r--r--core/java/android/widget/CursorTreeAdapter.java8
-rw-r--r--core/java/android/widget/SimpleCursorTreeAdapter.java55
-rw-r--r--core/jni/android_app_NativeActivity.cpp82
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp18
-rw-r--r--core/jni/android_view_Surface.cpp3
-rw-r--r--core/jni/android_view_Surface.h31
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp11
-rw-r--r--core/tests/coretests/src/android/database/DatabaseGeneralTest.java23
-rw-r--r--core/tests/coretests/src/android/database/sqlite/AbstractJDBCDriverTest.java211
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java38
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteJDBCDriverTest.java137
-rw-r--r--docs/html/guide/developing/eclipse-adt.jd5
-rw-r--r--docs/html/guide/developing/other-ide.jd5
-rw-r--r--docs/html/guide/samples/index.jd98
-rw-r--r--docs/html/guide/topics/data/backup.jd4
-rw-r--r--docs/html/guide/topics/resources/providing-resources.jd2
-rw-r--r--docs/html/resources/dashboard/platform-versions.jd78
-rw-r--r--docs/html/resources/dashboard/screens.jd10
-rw-r--r--docs/html/sdk/older_releases.jd42
-rw-r--r--graphics/java/android/renderscript/FileA3D.java6
-rw-r--r--graphics/java/android/renderscript/Mesh.java447
-rw-r--r--graphics/java/android/renderscript/RenderScript.java4
-rw-r--r--graphics/jni/android_renderscript_RenderScript.cpp39
-rw-r--r--include/media/stagefright/CameraSource.h12
-rw-r--r--include/media/stagefright/foundation/ALooper.h5
-rw-r--r--include/media/stagefright/foundation/AMessage.h2
-rw-r--r--libs/hwui/GenerationCache.h17
-rw-r--r--libs/hwui/OpenGLRenderer.cpp96
-rw-r--r--libs/hwui/OpenGLRenderer.h4
-rw-r--r--libs/hwui/Snapshot.h15
-rw-r--r--libs/hwui/Texture.h4
-rw-r--r--libs/hwui/TextureCache.cpp69
-rw-r--r--libs/hwui/TextureCache.h48
-rw-r--r--libs/rs/Android.mk1
-rw-r--r--libs/rs/RenderScript.h3
-rw-r--r--libs/rs/RenderScriptEnv.h2
-rw-r--r--libs/rs/java/Fountain/res/raw/fountain.rs16
-rw-r--r--libs/rs/java/Fountain/res/raw/fountain_bc.bcbin2924 -> 2996 bytes
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java26
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainView.java24
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java11
-rw-r--r--libs/rs/java/ModelViewer/res/raw/modelviewer.rs2
-rw-r--r--libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bcbin6220 -> 6216 bytes
-rw-r--r--libs/rs/java/ModelViewer/res/raw/robot.a3dbin144508 -> 144504 bytes
-rw-r--r--libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java8
-rw-r--r--libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java6
-rw-r--r--libs/rs/rs.spec34
-rw-r--r--libs/rs/rsContext.h1
-rw-r--r--libs/rs/rsContextHostStub.h1
-rw-r--r--libs/rs/rsFileA3D.cpp3
-rw-r--r--libs/rs/rsMesh.cpp352
-rw-r--r--libs/rs/rsMesh.h51
-rw-r--r--libs/rs/rsScriptC_LibGL.cpp48
-rw-r--r--libs/rs/rsSimpleMesh.cpp259
-rw-r--r--libs/rs/rsSimpleMesh.h73
-rw-r--r--libs/rs/scriptc/rs_graphics.rsh4
-rw-r--r--libs/surfaceflinger/TextureManager.cpp35
-rw-r--r--libs/ui/PixelFormat.cpp7
-rw-r--r--media/jni/android_media_MtpServer.cpp3
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp332
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h10
-rw-r--r--media/libstagefright/CameraSource.cpp47
-rw-r--r--media/libstagefright/foundation/ALooper.cpp9
-rw-r--r--media/libstagefright/foundation/AMessage.cpp103
-rw-r--r--media/mtp/Android.mk12
-rw-r--r--media/mtp/MtpDatabase.cpp504
-rw-r--r--media/mtp/MtpDatabase.h94
-rw-r--r--media/mtp/MtpServer.cpp20
-rw-r--r--media/mtp/MtpServer.h13
-rw-r--r--media/mtp/MtpSqliteDatabase.cpp564
-rw-r--r--media/mtp/MtpSqliteDatabase.h96
-rw-r--r--media/mtp/SqliteDatabase.h4
-rw-r--r--media/mtp/mtptest.cpp3
-rw-r--r--media/mtp/scantest.cpp4
-rw-r--r--native/android/Android.mk3
-rw-r--r--native/android/native_window.cpp47
-rw-r--r--native/include/android/native_activity.h29
-rw-r--r--native/include/android/native_window.h42
-rw-r--r--opengl/libs/EGL/egl.cpp4
-rw-r--r--opengl/tests/gl_jni/jni/gl_code.cpp1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java2
-rw-r--r--tests/HwAccelerationTest/res/drawable/sunset1.jpgbin0 -> 25019 bytes
-rw-r--r--tests/HwAccelerationTest/res/drawable/sunset2.pngbin0 -> 55763 bytes
97 files changed, 2952 insertions, 2081 deletions
diff --git a/api/current.xml b/api/current.xml
index 192e0bf6329d..c6df75920453 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -205332,6 +205332,21 @@
<parameter name="boundPosition" type="int">
</parameter>
</method>
+<method name="smoothScrollToPositionFromTop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="position" type="int">
+</parameter>
+<parameter name="offset" type="int">
+</parameter>
+</method>
<method name="verifyDrawable"
return="boolean"
abstract="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 75948a5d532c..10668a496fb5 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -1031,6 +1031,7 @@ void CameraService::Client::handleShutter(image_rect_type *size) {
mHardware->getRawHeap());
mSurface->registerBuffers(buffers);
+ IPCThreadState::self()->flushCommands();
}
mLock.unlock();
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index d43368b1b1e2..161161c7d8fe 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -5,12 +5,14 @@ import dalvik.system.PathClassLoader;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Looper;
import android.os.MessageQueue;
import android.view.InputChannel;
import android.view.InputQueue;
import android.view.KeyEvent;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
@@ -41,10 +43,10 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
private native void onStopNative(int handle);
private native void onLowMemoryNative(int handle);
private native void onWindowFocusChangedNative(int handle, boolean focused);
- private native void onSurfaceCreatedNative(int handle, SurfaceHolder holder);
- private native void onSurfaceChangedNative(int handle, SurfaceHolder holder,
+ private native void onSurfaceCreatedNative(int handle, Surface surface);
+ private native void onSurfaceChangedNative(int handle, Surface surface,
int format, int width, int height);
- private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder);
+ private native void onSurfaceDestroyedNative(int handle);
private native void onInputChannelCreatedNative(int handle, InputChannel channel);
private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
@@ -55,6 +57,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
getWindow().takeSurface(this);
getWindow().takeInputQueue(this);
+ getWindow().setFormat(PixelFormat.RGB_565);
try {
ai = getPackageManager().getActivityInfo(
@@ -98,7 +101,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
protected void onDestroy() {
mDestroyed = true;
if (mCurSurfaceHolder != null) {
- onSurfaceDestroyedNative(mNativeHandle, mCurSurfaceHolder);
+ onSurfaceDestroyedNative(mNativeHandle);
mCurSurfaceHolder = null;
}
if (mCurInputQueue != null) {
@@ -158,21 +161,21 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
public void surfaceCreated(SurfaceHolder holder) {
if (!mDestroyed) {
mCurSurfaceHolder = holder;
- onSurfaceCreatedNative(mNativeHandle, holder);
+ onSurfaceCreatedNative(mNativeHandle, holder.getSurface());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (!mDestroyed) {
mCurSurfaceHolder = holder;
- onSurfaceChangedNative(mNativeHandle, holder, format, width, height);
+ onSurfaceChangedNative(mNativeHandle, holder.getSurface(), format, width, height);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCurSurfaceHolder = null;
if (!mDestroyed) {
- onSurfaceDestroyedNative(mNativeHandle, holder);
+ onSurfaceDestroyedNative(mNativeHandle);
}
}
@@ -196,4 +199,12 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback,
decor.dispatchKeyEvent(event);
}
}
+
+ void setWindowFlags(int flags, int mask) {
+ getWindow().setFlags(flags, mask);
+ }
+
+ void setWindowFormat(int format) {
+ getWindow().setFormat(format);
+ }
}
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 8434ca5c5c81..9b14998eeba2 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -462,8 +462,8 @@ public abstract class AbstractCursor implements CrossProcessCursor {
protected int mPos;
/**
- * If {@link mRowIdColumnIndex} is not -1 this contains contains the value of
- * the column at {@link mRowIdColumnIndex} for the current row this cursor is
+ * If {@link #mRowIdColumnIndex} is not -1 this contains contains the value of
+ * the column at {@link #mRowIdColumnIndex} for the current row this cursor is
* pointing at.
*/
protected Long mCurrentRowID;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index eec03b21e52a..1a096971e4f2 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,7 +16,6 @@
package android.database.sqlite;
-import android.app.ActivityThread;
import android.app.AppGlobals;
import android.content.ContentValues;
import android.database.Cursor;
@@ -1045,6 +1044,9 @@ public class SQLiteDatabase extends SQLiteClosable {
if (!isOpen()) {
return; // already closed
}
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ Log.i(TAG, "closing db: " + mPath + " (connection # " + mConnectionNum);
+ }
lock();
try {
closeClosable();
@@ -2123,7 +2125,8 @@ public class SQLiteDatabase extends SQLiteClosable {
/* package */ void verifyDbIsOpen() {
if (!isOpen()) {
- throw new IllegalStateException("database " + getPath() + " already closed");
+ throw new IllegalStateException("database " + getPath() + " (conn# " +
+ mConnectionNum + ") already closed");
}
}
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index a3513e61e6a3..83cec37aee1c 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -28,6 +28,11 @@ public abstract class SQLiteProgram extends SQLiteClosable {
private static final String TAG = "SQLiteProgram";
+ /** the type of sql statement being processed by this object */
+ private static final int SELECT_STMT = 1;
+ private static final int UPDATE_STMT = 2;
+ private static final int OTHER_STMT = 3;
+
/** The database this program is compiled against.
* @deprecated do not use this
*/
@@ -61,35 +66,37 @@ public abstract class SQLiteProgram extends SQLiteClosable {
/* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
mDatabase = db;
mSql = sql.trim();
- db.acquireReference();
- db.addSQLiteClosable(this);
- this.nHandle = db.mNativeHandle;
+ attachObjectToDatabase(db);
+ compileSql();
+ }
+
+ private void compileSql() {
+ if (nStatement > 0) {
+ // already compiled.
+ return;
+ }
// only cache CRUD statements
- String prefixSql = mSql.substring(0, 6);
- if (!prefixSql.equalsIgnoreCase("INSERT") && !prefixSql.equalsIgnoreCase("UPDATE") &&
- !prefixSql.equalsIgnoreCase("REPLAC") &&
- !prefixSql.equalsIgnoreCase("DELETE") && !prefixSql.equalsIgnoreCase("SELECT")) {
- mCompiledSql = new SQLiteCompiledSql(db, sql);
+ if (getSqlStatementType(mSql) == OTHER_STMT) {
+ mCompiledSql = new SQLiteCompiledSql(mDatabase, mSql);
nStatement = mCompiledSql.nStatement;
// since it is not in the cache, no need to acquire() it.
return;
}
- // it is not pragma
- mCompiledSql = db.getCompiledStatementForSql(sql);
+ mCompiledSql = mDatabase.getCompiledStatementForSql(mSql);
if (mCompiledSql == null) {
// create a new compiled-sql obj
- mCompiledSql = new SQLiteCompiledSql(db, sql);
+ mCompiledSql = new SQLiteCompiledSql(mDatabase, mSql);
// add it to the cache of compiled-sqls
// but before adding it and thus making it available for anyone else to use it,
// make sure it is acquired by me.
mCompiledSql.acquire();
- db.addToCompiledQueries(sql, mCompiledSql);
+ mDatabase.addToCompiledQueries(mSql, mCompiledSql);
if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
Log.v(TAG, "Created DbObj (id#" + mCompiledSql.nStatement +
- ") for sql: " + sql);
+ ") for sql: " + mSql);
}
} else {
// it is already in compiled-sql cache.
@@ -100,12 +107,12 @@ public abstract class SQLiteProgram extends SQLiteClosable {
// we can't have two different SQLiteProgam objects can't share the same
// CompiledSql object. create a new one.
// finalize it when I am done with it in "this" object.
- mCompiledSql = new SQLiteCompiledSql(db, sql);
+ mCompiledSql = new SQLiteCompiledSql(mDatabase, mSql);
if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
Log.v(TAG, "** possible bug ** Created NEW DbObj (id#" +
mCompiledSql.nStatement +
") because the previously created DbObj (id#" + last +
- ") was not released for sql:" + sql);
+ ") was not released for sql:" + mSql);
}
// since it is not in the cache, no need to acquire() it.
}
@@ -113,11 +120,37 @@ public abstract class SQLiteProgram extends SQLiteClosable {
nStatement = mCompiledSql.nStatement;
}
+ private int getSqlStatementType(String sql) {
+ if (mSql.length() < 6) {
+ return OTHER_STMT;
+ }
+ String prefixSql = mSql.substring(0, 6);
+ if (prefixSql.equalsIgnoreCase("SELECT")) {
+ return SELECT_STMT;
+ } else if (prefixSql.equalsIgnoreCase("INSERT") ||
+ prefixSql.equalsIgnoreCase("UPDATE") ||
+ prefixSql.equalsIgnoreCase("REPLAC") ||
+ prefixSql.equalsIgnoreCase("DELETE")) {
+ return UPDATE_STMT;
+ }
+ return OTHER_STMT;
+ }
+
+ private synchronized void attachObjectToDatabase(SQLiteDatabase db) {
+ db.acquireReference();
+ db.addSQLiteClosable(this);
+ nHandle = db.mNativeHandle;
+ }
+
+ private synchronized void detachObjectFromDatabase() {
+ mDatabase.removeSQLiteClosable(this);
+ mDatabase.releaseReference();
+ }
+
@Override
protected void onAllReferencesReleased() {
releaseCompiledSqlIfNotInCache();
- mDatabase.releaseReference();
- mDatabase.removeSQLiteClosable(this);
+ detachObjectFromDatabase();
}
@Override
@@ -135,13 +168,13 @@ public abstract class SQLiteProgram extends SQLiteClosable {
// it is NOT in compiled-sql cache. i.e., responsibility of
// releasing this statement is on me.
mCompiledSql.releaseSqlStatement();
- mCompiledSql = null;
- nStatement = 0;
} else {
// it is in compiled-sql cache. reset its CompiledSql#mInUse flag
mCompiledSql.release();
}
- }
+ }
+ mCompiledSql = null;
+ nStatement = 0;
}
/**
@@ -150,7 +183,9 @@ public abstract class SQLiteProgram extends SQLiteClosable {
* @return a unique identifier for this program
*/
public final int getUniqueId() {
- return (mCompiledSql != null) ? mCompiledSql.nStatement : 0;
+ synchronized (this) {
+ return (mCompiledSql != null) ? mCompiledSql.nStatement : 0;
+ }
}
/* package */ String getSqlString() {
@@ -176,12 +211,14 @@ public abstract class SQLiteProgram extends SQLiteClosable {
* @param index The 1-based index to the parameter to bind null to
*/
public void bindNull(int index) {
- mDatabase.verifyDbIsOpen();
- acquireReference();
- try {
- native_bind_null(index);
- } finally {
- releaseReference();
+ synchronized (this) {
+ mDatabase.verifyDbIsOpen();
+ acquireReference();
+ try {
+ native_bind_null(index);
+ } finally {
+ releaseReference();
+ }
}
}
@@ -193,12 +230,14 @@ public abstract class SQLiteProgram extends SQLiteClosable {
* @param value The value to bind
*/
public void bindLong(int index, long value) {
- mDatabase.verifyDbIsOpen();
- acquireReference();
- try {
- native_bind_long(index, value);
- } finally {
- releaseReference();
+ synchronized (this) {
+ mDatabase.verifyDbIsOpen();
+ acquireReference();
+ try {
+ native_bind_long(index, value);
+ } finally {
+ releaseReference();
+ }
}
}
@@ -210,12 +249,14 @@ public abstract class SQLiteProgram extends SQLiteClosable {
* @param value The value to bind
*/
public void bindDouble(int index, double value) {
- mDatabase.verifyDbIsOpen();
- acquireReference();
- try {
- native_bind_double(index, value);
- } finally {
- releaseReference();
+ synchronized (this) {
+ mDatabase.verifyDbIsOpen();
+ acquireReference();
+ try {
+ native_bind_double(index, value);
+ } finally {
+ releaseReference();
+ }
}
}
@@ -230,12 +271,14 @@ public abstract class SQLiteProgram extends SQLiteClosable {
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
- mDatabase.verifyDbIsOpen();
- acquireReference();
- try {
- native_bind_string(index, value);
- } finally {
- releaseReference();
+ synchronized (this) {
+ mDatabase.verifyDbIsOpen();
+ acquireReference();
+ try {
+ native_bind_string(index, value);
+ } finally {
+ releaseReference();
+ }
}
}
@@ -250,12 +293,14 @@ public abstract class SQLiteProgram extends SQLiteClosable {
if (value == null) {
throw new IllegalArgumentException("the bind value at index " + index + " is null");
}
- mDatabase.verifyDbIsOpen();
- acquireReference();
- try {
- native_bind_blob(index, value);
- } finally {
- releaseReference();
+ synchronized (this) {
+ mDatabase.verifyDbIsOpen();
+ acquireReference();
+ try {
+ native_bind_blob(index, value);
+ } finally {
+ releaseReference();
+ }
}
}
@@ -263,12 +308,14 @@ public abstract class SQLiteProgram extends SQLiteClosable {
* Clears all existing bindings. Unset bindings are treated as NULL.
*/
public void clearBindings() {
- mDatabase.verifyDbIsOpen();
- acquireReference();
- try {
- native_clear_bindings();
- } finally {
- releaseReference();
+ synchronized (this) {
+ mDatabase.verifyDbIsOpen();
+ acquireReference();
+ try {
+ native_clear_bindings();
+ } finally {
+ releaseReference();
+ }
}
}
@@ -276,10 +323,16 @@ public abstract class SQLiteProgram extends SQLiteClosable {
* Release this program's resources, making it invalid.
*/
public void close() {
- if (!mDatabase.isOpen()) {
- return;
+ synchronized (this) {
+ if (nStatement == 0 || nHandle == 0 || !mDatabase.isOpen()) {
+ return;
+ }
+ releaseReference();
+ // set all database objects to null/0, so that the user can't use a closed Object.
+ mCompiledSql = null;
+ nStatement = 0;
+ nHandle = 0;
}
- releaseReference();
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index e1ad306c76d4..f6ca1d128d9f 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -31,6 +31,9 @@ import dalvik.system.BlockGuard;
*/
public class SQLiteStatement extends SQLiteProgram
{
+ private static final boolean READ = true;
+ private static final boolean WRITE = false;
+
/**
* Don't use SQLiteStatement constructor directly, please use
* {@link SQLiteDatabase#compileStatement(String)}
@@ -49,19 +52,12 @@ public class SQLiteStatement extends SQLiteProgram
* some reason
*/
public void execute() {
- mDatabase.verifyDbIsOpen();
- BlockGuard.getThreadPolicy().onWriteToDisk();
- long timeStart = SystemClock.uptimeMillis();
- mDatabase.lock();
-
- acquireReference();
+ long timeStart = acquireAndLock(WRITE);
try {
- mDatabase.closePendingStatements();
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
} finally {
- releaseReference();
- mDatabase.unlock();
+ releaseAndUnlock();
}
}
@@ -75,20 +71,13 @@ public class SQLiteStatement extends SQLiteProgram
* some reason
*/
public long executeInsert() {
- mDatabase.verifyDbIsOpen();
- BlockGuard.getThreadPolicy().onWriteToDisk();
- long timeStart = SystemClock.uptimeMillis();
- mDatabase.lock();
-
- acquireReference();
+ long timeStart = acquireAndLock(WRITE);
try {
- mDatabase.closePendingStatements();
native_execute();
mDatabase.logTimeStat(mSql, timeStart);
return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
} finally {
- releaseReference();
- mDatabase.unlock();
+ releaseAndUnlock();
}
}
@@ -101,20 +90,13 @@ public class SQLiteStatement extends SQLiteProgram
* @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public long simpleQueryForLong() {
- mDatabase.verifyDbIsOpen();
- BlockGuard.getThreadPolicy().onReadFromDisk();
- long timeStart = SystemClock.uptimeMillis();
- mDatabase.lock();
-
- acquireReference();
+ long timeStart = acquireAndLock(READ);
try {
- mDatabase.closePendingStatements();
long retValue = native_1x1_long();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
} finally {
- releaseReference();
- mDatabase.unlock();
+ releaseAndUnlock();
}
}
@@ -127,21 +109,50 @@ public class SQLiteStatement extends SQLiteProgram
* @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
public String simpleQueryForString() {
- mDatabase.verifyDbIsOpen();
- BlockGuard.getThreadPolicy().onReadFromDisk();
- long timeStart = SystemClock.uptimeMillis();
- mDatabase.lock();
-
- acquireReference();
+ long timeStart = acquireAndLock(READ);
try {
- mDatabase.closePendingStatements();
String retValue = native_1x1_string();
mDatabase.logTimeStat(mSql, timeStart);
return retValue;
} finally {
- releaseReference();
- mDatabase.unlock();
+ releaseAndUnlock();
+ }
+ }
+
+ /**
+ * Called before every method in this class before executing a SQL statement,
+ * this method does the following:
+ * <ul>
+ * <li>make sure the database is open</li>
+ * <li>notifies {@link BlockGuard} of read/write</li>
+ * <li>get lock on the database</li>
+ * <li>acquire reference on this object</li>
+ * <li>and then return the current time _before_ the database lock was acquired</li>
+ * </ul>
+ * <p>
+ * This method removes the duplcate code from the other public
+ * methods in this class.
+ */
+ private long acquireAndLock(boolean rwFlag) {
+ mDatabase.verifyDbIsOpen();
+ if (rwFlag == WRITE) {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ } else {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
}
+ long startTime = SystemClock.uptimeMillis();
+ mDatabase.lock();
+ acquireReference();
+ mDatabase.closePendingStatements();
+ return startTime;
+ }
+
+ /**
+ * this method releases locks and references acquired in {@link #acquireAndLock(boolean)}.
+ */
+ private void releaseAndUnlock() {
+ releaseReference();
+ mDatabase.unlock();
}
private final native void native_execute();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index ccf122120ee8..b46091081c96 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -368,19 +368,19 @@ class GLES20Canvas extends Canvas {
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
- final float width = bitmap.getWidth();
- final float height = bitmap.getHeight();
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, 0.0f, 0.0f, width, height,
- 0.0f, 0.0f, width, height, matrix.native_instance, nativePaint,
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint,
bitmap.getDensity(), mDensity, mScreenDensity);
}
+ private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint,
+ int bitmapDensity, int canvasDensity, int screenDensity);
+
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
- dst.left, dst.top, dst.right, dst.bottom, 0, nativePaint,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint,
bitmap.getDensity(), mDensity, mScreenDensity);
}
@@ -388,7 +388,7 @@ class GLES20Canvas extends Canvas {
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
- dst.left, dst.top, dst.right, dst.bottom, 0, nativePaint,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint,
bitmap.getDensity(), mDensity, mScreenDensity);
}
@@ -397,7 +397,7 @@ class GLES20Canvas extends Canvas {
private native void nDrawBitmap(int renderer, int bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
- float left, float top, float right, float bottom, int matrix, int paint,
+ float left, float top, float right, float bottom, int paint,
int bitmapDensity, int canvasDensity, int screenDensity);
@Override
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index a1ee3d3dfba8..d30bce9bb89a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -413,33 +413,30 @@ abstract class HardwareRenderer {
}
EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- int[] num_config = new int[1];
- if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
- num_config)) {
+ int[] index = new int[1];
+ if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
- int numConfigs = num_config[0];
-
+ int numConfigs = index[0];
if (numConfigs <= 0) {
- throw new IllegalArgumentException(
- "No configs match configSpec");
+ throw new IllegalArgumentException("No configs match configSpec");
}
EGLConfig[] configs = new EGLConfig[numConfigs];
- if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
- num_config)) {
- throw new IllegalArgumentException("eglChooseConfig#2 failed");
+ if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
+ throw new IllegalArgumentException("eglChooseConfig failed");
}
+
EGLConfig config = chooseConfig(egl, display, configs);
if (config == null) {
throw new IllegalArgumentException("No config chosen");
}
+
return config;
}
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs);
+ abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
private int[] filterConfigSpec(int[] configSpec) {
if (mGlVersion != 2) {
@@ -450,10 +447,10 @@ abstract class HardwareRenderer {
*/
int len = configSpec.length;
int[] newConfigSpec = new int[len + 2];
- System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
- newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
+ System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
+ newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
- newConfigSpec[len+1] = EGL10.EGL_NONE;
+ newConfigSpec[len + 1] = EGL10.EGL_NONE;
return newConfigSpec;
}
}
@@ -496,13 +493,12 @@ abstract class HardwareRenderer {
for (EGLConfig config : configs) {
int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
- if ((d >= mDepthSize) && (s >= mStencilSize)) {
+ if (d >= mDepthSize && s >= mStencilSize) {
int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
- if ((r == mRedSize) && (g == mGreenSize) && (b == mBlueSize) &&
- (a == mAlphaSize)) {
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize && a >= mAlphaSize) {
return config;
}
}
@@ -510,16 +506,15 @@ abstract class HardwareRenderer {
return null;
}
- private int findConfigAttrib(EGL10 egl, EGLDisplay display,
- EGLConfig config, int attribute, int defaultValue) {
-
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
+ int attribute, int defaultValue) {
if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
return mValue[0];
}
return defaultValue;
}
- }
+ }
}
/**
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 15ffffdb4413..1b5651b324c8 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -1222,9 +1222,7 @@ class CallbackProxy extends Handler {
// for null.
WebHistoryItem i = mBackForwardList.getCurrentItem();
if (i != null) {
- if (precomposed || i.getTouchIconUrl() == null) {
- i.setTouchIconUrl(url);
- }
+ i.setTouchIconUrl(url, precomposed);
}
// Do an unsynchronized quick check to avoid posting if no callback has
// been set.
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index 428a59ce90f4..7c0e47821b7f 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -18,6 +18,9 @@ package android.webkit;
import android.graphics.Bitmap;
+import java.net.MalformedURLException;
+import java.net.URL;
+
/**
* A convenience class for accessing fields in an entry in the back/forward list
* of a WebView. Each WebHistoryItem is a snapshot of the requested history
@@ -39,8 +42,12 @@ public class WebHistoryItem implements Cloneable {
private Bitmap mFavicon;
// The pre-flattened data used for saving the state.
private byte[] mFlattenedData;
- // The apple-touch-icon url for use when adding the site to the home screen
- private String mTouchIconUrl;
+ // The apple-touch-icon url for use when adding the site to the home screen,
+ // as obtained from a <link> element in the page.
+ private String mTouchIconUrlFromLink;
+ // If no <link> is specified, this holds the default location of the
+ // apple-touch-icon.
+ private String mTouchIconUrlServerDefault;
// Custom client data that is not flattened or read by native code.
private Object mCustomData;
@@ -132,10 +139,28 @@ public class WebHistoryItem implements Cloneable {
/**
* Return the touch icon url.
+ * If no touch icon <link> tag was specified, returns
+ * <host>/apple-touch-icon.png. The DownloadTouchIcon class that
+ * attempts to retrieve the touch icon will handle the case where
+ * that file does not exist. An icon set by a <link> tag is always
+ * used in preference to an icon saved on the server.
* @hide
*/
public String getTouchIconUrl() {
- return mTouchIconUrl;
+ if (mTouchIconUrlFromLink != null) {
+ return mTouchIconUrlFromLink;
+ } else if (mTouchIconUrlServerDefault != null) {
+ return mTouchIconUrlServerDefault;
+ }
+
+ try {
+ URL url = new URL(mOriginalUrl);
+ mTouchIconUrlServerDefault = new URL(url.getProtocol(), url.getHost(), url.getPort(),
+ "/apple-touch-icon.png").toString();
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ return mTouchIconUrlServerDefault;
}
/**
@@ -171,11 +196,14 @@ public class WebHistoryItem implements Cloneable {
}
/**
- * Set the touch icon url.
+ * Set the touch icon url. Will not overwrite an icon that has been
+ * set already from a <link> tag, unless the new icon is precomposed.
* @hide
*/
- /*package*/ void setTouchIconUrl(String url) {
- mTouchIconUrl = url;
+ /*package*/ void setTouchIconUrl(String url, boolean precomposed) {
+ if (precomposed || mTouchIconUrlFromLink == null) {
+ mTouchIconUrlFromLink = url;
+ }
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 91d62f6a249e..d5136ae98c34 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2314,7 +2314,9 @@ public class WebView extends AbsoluteLayout
}
/**
- * Get the touch icon url for the apple-touch-icon <link> element.
+ * Get the touch icon url for the apple-touch-icon <link> element, or
+ * a URL on this site's server pointing to the standard location of a
+ * touch icon.
* @hide
*/
public String getTouchIconUrl() {
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 00fadb5a45f6..7f7f46e0cb23 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -768,8 +768,8 @@ class ZoomManager {
mMinZoomScale = zoomOverviewScale;
}
// fit the content width to the current view. Ignore the rounding error case.
- if (!mWebView.drawHistory() && (mInZoomOverview || mInitialZoomOverview)
- && Math.abs((viewWidth * mInvActualScale) - mZoomOverviewWidth) > 1) {
+ if (!mWebView.drawHistory() && (mInitialZoomOverview || (mInZoomOverview
+ && Math.abs((viewWidth * mInvActualScale) - mZoomOverviewWidth) > 1))) {
mInitialZoomOverview = false;
setZoomScale(zoomOverviewScale, !willScaleTriggerZoom(mTextWrapScale));
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 10927a7524d5..1d5c5f944185 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2541,6 +2541,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private static final int MOVE_UP_POS = 2;
private static final int MOVE_DOWN_BOUND = 3;
private static final int MOVE_UP_BOUND = 4;
+ private static final int MOVE_OFFSET = 5;
private int mMode;
private int mTargetPos;
@@ -2548,6 +2549,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private int mLastSeenPos;
private int mScrollDuration;
private final int mExtraScroll;
+
+ private int mOffsetFromTop;
PositionScroller() {
mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
@@ -2639,11 +2642,37 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
post(this);
}
-
+
+ void startWithOffset(int position, int offset) {
+ mTargetPos = position;
+ mOffsetFromTop = offset;
+ mBoundPos = INVALID_POSITION;
+ mLastSeenPos = INVALID_POSITION;
+ mMode = MOVE_OFFSET;
+
+ final int firstPos = mFirstPosition;
+ final int lastPos = firstPos + getChildCount() - 1;
+
+ int viewTravelCount = 0;
+ if (position < firstPos) {
+ viewTravelCount = firstPos - position;
+ } else if (position > lastPos) {
+ viewTravelCount = position - lastPos;
+ } else {
+ // On-screen, just scroll.
+ final int targetTop = getChildAt(position - firstPos).getTop();
+ smoothScrollBy(targetTop - offset, SCROLL_DURATION);
+ return;
+ }
+
+ mScrollDuration = SCROLL_DURATION / viewTravelCount;
+ post(this);
+ }
+
void stop() {
removeCallbacks(this);
}
-
+
public void run() {
final int listHeight = getHeight();
final int firstPos = mFirstPosition;
@@ -2769,6 +2798,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
break;
}
+ case MOVE_OFFSET: {
+ if (firstPos == mLastSeenPos) {
+ // No new views, let things keep going.
+ post(this);
+ }
+
+ final int position = mTargetPos;
+ final int lastPos = firstPos + getChildCount() - 1;
+
+ if (position < firstPos) {
+ final View firstView = getChildAt(0);
+ final int firstViewPixelsShowing = firstView.getHeight() + firstView.getTop();
+ smoothScrollBy(-firstViewPixelsShowing, mScrollDuration);
+ post(this);
+ } else if (position > lastPos) {
+ final View lastView = getChildAt(getChildCount() - 1);
+ final int lastViewPixelsShowing = lastView.getBottom() - lastView.getHeight();
+ smoothScrollBy(lastViewPixelsShowing, mScrollDuration);
+ post(this);
+ } else {
+ // On-screen, just scroll.
+ final int targetTop = getChildAt(position - firstPos).getTop();
+ smoothScrollBy(targetTop - mOffsetFromTop, mScrollDuration);
+ }
+ break;
+ }
+
default:
break;
}
@@ -2788,6 +2844,24 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
+ * Smoothly scroll to the specified adapter position. The view will scroll
+ * such that the indicated position is displayed <code>offset</code> pixels from
+ * the top edge of the view. If this is impossible, (e.g. the offset would scroll
+ * the first or last item beyond the boundaries of the list) it will get as close
+ * as possible.
+ *
+ * @param position Position to scroll to
+ * @param offset Desired distance in pixels of <code>position</code> from the top
+ * of the view when scrolling is finished
+ */
+ public void smoothScrollToPositionFromTop(int position, int offset) {
+ if (mPositionScroller == null) {
+ mPositionScroller = new PositionScroller();
+ }
+ mPositionScroller.startWithOffset(position, offset);
+ }
+
+ /**
* Smoothly scroll to the specified adapter position. The view will
* scroll such that the indicated position is displayed, but it will
* stop early if scrolling further would scroll boundPosition out of
diff --git a/core/java/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java
index 7b9b7bdafc0f..3fadf4c54075 100644
--- a/core/java/android/widget/CursorTreeAdapter.java
+++ b/core/java/android/widget/CursorTreeAdapter.java
@@ -134,14 +134,16 @@ public abstract class CursorTreeAdapter extends BaseExpandableListAdapter implem
/**
* Sets the group Cursor.
*
- * @param cursor The Cursor to set for the group.
+ * @param cursor The Cursor to set for the group. If there is an existing cursor
+ * it will be closed.
*/
public void setGroupCursor(Cursor cursor) {
mGroupCursorHelper.changeCursor(cursor, false);
}
/**
- * Sets the children Cursor for a particular group.
+ * Sets the children Cursor for a particular group. If there is an existing cursor
+ * it will be closed.
* <p>
* This is useful when asynchronously querying to prevent blocking the UI.
*
@@ -476,7 +478,7 @@ public abstract class CursorTreeAdapter extends BaseExpandableListAdapter implem
mCursor.unregisterContentObserver(mContentObserver);
mCursor.unregisterDataSetObserver(mDataSetObserver);
- mCursor.deactivate();
+ mCursor.close();
mCursor = null;
}
diff --git a/core/java/android/widget/SimpleCursorTreeAdapter.java b/core/java/android/widget/SimpleCursorTreeAdapter.java
index a1c65f0a81ab..a0335426ddf5 100644
--- a/core/java/android/widget/SimpleCursorTreeAdapter.java
+++ b/core/java/android/widget/SimpleCursorTreeAdapter.java
@@ -38,6 +38,10 @@ import android.view.View;
* binding can be found, an {@link IllegalStateException} is thrown.
*/
public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
+
+ /** The name of the columns that contain the data to display for a group. */
+ private String[] mGroupFromNames;
+
/** The indices of columns that contain data to display for a group. */
private int[] mGroupFrom;
/**
@@ -46,6 +50,9 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
*/
private int[] mGroupTo;
+ /** The name of the columns that contain the data to display for a child. */
+ private String[] mChildFromNames;
+
/** The indices of columns that contain data to display for a child. */
private int[] mChildFrom;
/**
@@ -171,38 +178,12 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
private void init(String[] groupFromNames, int[] groupTo, String[] childFromNames,
int[] childTo) {
+
+ mGroupFromNames = groupFromNames;
mGroupTo = groupTo;
+ mChildFromNames = childFromNames;
mChildTo = childTo;
-
- // Get the group cursor column indices, the child cursor column indices will come
- // when needed
- initGroupFromColumns(groupFromNames);
-
- // Get a temporary child cursor to init the column indices
- if (getGroupCount() > 0) {
- MyCursorHelper tmpCursorHelper = getChildrenCursorHelper(0, true);
- if (tmpCursorHelper != null) {
- initChildrenFromColumns(childFromNames, tmpCursorHelper.getCursor());
- deactivateChildrenCursorHelper(0);
- }
- }
- }
-
- private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
- for (int i = fromColumnNames.length - 1; i >= 0; i--) {
- fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
- }
- }
-
- private void initGroupFromColumns(String[] groupFromNames) {
- mGroupFrom = new int[groupFromNames.length];
- initFromColumns(mGroupCursorHelper.getCursor(), groupFromNames, mGroupFrom);
- }
-
- private void initChildrenFromColumns(String[] childFromNames, Cursor childCursor) {
- mChildFrom = new int[childFromNames.length];
- initFromColumns(childCursor, childFromNames, mChildFrom);
}
/**
@@ -257,13 +238,29 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
}
}
+ private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
+ for (int i = fromColumnNames.length - 1; i >= 0; i--) {
+ fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
+ }
+ }
+
@Override
protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
+ if (mChildFrom == null) {
+ mChildFrom = new int[mChildFromNames.length];
+ initFromColumns(cursor, mChildFromNames, mChildFrom);
+ }
+
bindView(view, context, cursor, mChildFrom, mChildTo);
}
@Override
protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
+ if (mGroupFrom == null) {
+ mGroupFrom = new int[mGroupFromNames.length];
+ initFromColumns(cursor, mGroupFromNames, mGroupFrom);
+ }
+
bindView(view, context, cursor, mGroupFrom, mGroupTo);
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index dd59d6327663..dab1dba811cb 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -22,6 +22,8 @@
#include <android_runtime/AndroidRuntime.h>
#include <android/native_activity.h>
+#include <surfaceflinger/Surface.h>
+#include <ui/egl/android_natives.h>
#include <ui/InputTransport.h>
#include <utils/PollLoop.h>
@@ -29,6 +31,7 @@
#include "android_os_MessageQueue.h"
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
+#include "android_view_Surface.h"
namespace android
{
@@ -37,8 +40,16 @@ static struct {
jclass clazz;
jmethodID dispatchUnhandledKeyEvent;
+ jmethodID setWindowFlags;
+ jmethodID setWindowFormat;
} gNativeActivityClassInfo;
+// ------------------------------------------------------------------------
+
+/*
+ * Specialized input queue that allows unhandled key events to be dispatched
+ * back to the native activity's Java framework code.
+ */
struct MyInputQueue : AInputQueue {
explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
: AInputQueue(channel), mWorkWrite(workWrite) {
@@ -74,13 +85,18 @@ struct MyInputQueue : AInputQueue {
Vector<KeyEvent*> mPendingKeys;
};
+// ------------------------------------------------------------------------
+
+/*
+ * Native state for interacting with the NativeActivity class.
+ */
struct NativeCode {
NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
memset(&activity, sizeof(activity), 0);
memset(&callbacks, sizeof(callbacks), 0);
dlhandle = _dlhandle;
createActivityFunc = _createFunc;
- surface = NULL;
+ nativeWindow = NULL;
inputChannel = NULL;
nativeInputQueue = NULL;
mainWorkRead = mainWorkWrite = -1;
@@ -104,18 +120,18 @@ struct NativeCode {
if (mainWorkRead >= 0) close(mainWorkRead);
if (mainWorkWrite >= 0) close(mainWorkWrite);
if (dlhandle != NULL) {
- dlclose(dlhandle);
+ // for now don't unload... we probably should clean this
+ // up and only keep one open dlhandle per proc, since there
+ // is really no benefit to unloading the code.
+ //dlclose(dlhandle);
}
}
void setSurface(jobject _surface) {
- if (surface != NULL) {
- activity.env->DeleteGlobalRef(surface);
- }
if (_surface != NULL) {
- surface = activity.env->NewGlobalRef(_surface);
+ nativeWindow = android_Surface_getNativeWindow(activity.env, _surface);
} else {
- surface = NULL;
+ nativeWindow = NULL;
}
}
@@ -150,7 +166,7 @@ struct NativeCode {
void* dlhandle;
ANativeActivity_createFunc* createActivityFunc;
- jobject surface;
+ sp<ANativeWindow> nativeWindow;
jobject inputChannel;
struct MyInputQueue* nativeInputQueue;
@@ -160,6 +176,11 @@ struct NativeCode {
sp<PollLoop> pollLoop;
};
+// ------------------------------------------------------------------------
+
+/*
+ * Callback for handling native events on the application's main thread.
+ */
static bool mainWorkCallback(int fd, int events, void* data) {
NativeCode* code = (NativeCode*)data;
if ((events & POLLIN) != 0) {
@@ -180,6 +201,8 @@ static bool mainWorkCallback(int fd, int events, void* data) {
return true;
}
+// ------------------------------------------------------------------------
+
static jint
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue)
{
@@ -323,9 +346,9 @@ onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
code->setSurface(surface);
- if (code->callbacks.onSurfaceCreated != NULL) {
- code->callbacks.onSurfaceCreated(&code->activity,
- (ASurfaceHolder*)code->surface);
+ if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
+ code->callbacks.onNativeWindowCreated(&code->activity,
+ code->nativeWindow.get());
}
}
}
@@ -336,9 +359,17 @@ onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface
{
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
- if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) {
- code->callbacks.onSurfaceChanged(&code->activity,
- (ASurfaceHolder*)code->surface, format, width, height);
+ sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
+ code->setSurface(surface);
+ if (oldNativeWindow != code->nativeWindow) {
+ if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
+ code->callbacks.onNativeWindowDestroyed(&code->activity,
+ oldNativeWindow.get());
+ }
+ if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
+ code->callbacks.onNativeWindowCreated(&code->activity,
+ code->nativeWindow.get());
+ }
}
}
}
@@ -348,9 +379,9 @@ onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surfa
{
if (handle != 0) {
NativeCode* code = (NativeCode*)handle;
- if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) {
- code->callbacks.onSurfaceDestroyed(&code->activity,
- (ASurfaceHolder*)code->surface);
+ if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
+ code->callbacks.onNativeWindowDestroyed(&code->activity,
+ code->nativeWindow.get());
}
code->setSurface(NULL);
}
@@ -398,9 +429,9 @@ static const JNINativeMethod g_methods[] = {
{ "onStopNative", "(I)V", (void*)onStop_native },
{ "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
{ "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
- { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
- { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
- { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
+ { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
+ { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
+ { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
{ "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
{ "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
};
@@ -421,11 +452,18 @@ int register_android_app_NativeActivity(JNIEnv* env)
//LOGD("register_android_app_NativeActivity");
FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName);
-
+
GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent,
gNativeActivityClassInfo.clazz,
"dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V");
-
+
+ GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
+ gNativeActivityClassInfo.clazz,
+ "setWindowFlags", "(II)V");
+ GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
+ gNativeActivityClassInfo.clazz,
+ "setWindowFormat", "(I)V");
+
return AndroidRuntime::registerNativeMethods(
env, kNativeActivityPathName,
g_methods, NELEM(g_methods));
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index cba6ed15e553..89ad53418a24 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -195,13 +195,22 @@ static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject canvas
OpenGLRenderer* renderer, SkBitmap* bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
- SkMatrix* matrix, SkPaint* paint,
- jint bitmapDensity, jint canvasDensity, jint screenDensity) {
+ SkPaint* paint, jint bitmapDensity, jint canvasDensity, jint screenDensity) {
if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
- dstLeft, dstTop, dstRight, dstBottom, matrix, paint);
+ dstLeft, dstTop, dstRight, dstBottom, paint);
} else {
+ // TODO: implement
+ }
+}
+static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint,
+ jint bitmapDensity, jint canvasDensity,jint screenDensity) {
+ if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
+ renderer->drawBitmap(bitmap, matrix, paint);
+ } else {
+ // TODO: implement
}
}
@@ -249,7 +258,8 @@ static JNINativeMethod gMethods[] = {
{ "nConcatMatrix", "(II)V", (void*) android_view_GLES20Canvas_concatMatrix },
{ "nDrawBitmap", "(IIFFIIII)V", (void*) android_view_GLES20Canvas_drawBitmap },
- { "nDrawBitmap", "(IIFFFFFFFFIIIII)V", (void*) android_view_GLES20Canvas_drawBitmapRect },
+ { "nDrawBitmap", "(IIFFFFFFFFIIII)V", (void*) android_view_GLES20Canvas_drawBitmapRect },
+ { "nDrawBitmap", "(IIIIIII)V", (void*) android_view_GLES20Canvas_drawBitmapMatrix },
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor },
{ "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index cef5c107ec86..a82abc93eacf 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -33,6 +33,7 @@
#include "jni.h"
#include <android_runtime/AndroidRuntime.h>
+#include "android_view_Surface.h"
#include <utils/misc.h>
@@ -179,7 +180,7 @@ static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
return result;
}
-EGLNativeWindowType android_Surface_getEGLNativeWindow(
+sp<ANativeWindow> android_Surface_getNativeWindow(
JNIEnv* env, jobject clazz) {
return getSurface(env, clazz).get();
}
diff --git a/core/jni/android_view_Surface.h b/core/jni/android_view_Surface.h
new file mode 100644
index 000000000000..c37932e74c4f
--- /dev/null
+++ b/core/jni/android_view_Surface.h
@@ -0,0 +1,31 @@
+/*
+ * 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 _ANDROID_VIEW_SURFACE_H
+#define _ANDROID_VIEW_SURFACE_H
+
+#include <android/native_window.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern sp<ANativeWindow> android_Surface_getNativeWindow(
+ JNIEnv* env, jobject clazz);
+
+} // namespace android
+
+#endif // _ANDROID_VIEW_SURFACE_H
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index d5cde48b8538..866c038eac43 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -25,10 +25,9 @@
#include <SkBitmap.h>
#include <SkPixelRef.h>
-namespace android {
+#include "android_view_Surface.h"
-extern EGLNativeWindowType android_Surface_getEGLNativeWindow(
- JNIEnv* env, jobject clazz);
+namespace android {
static jclass gDisplay_class;
static jclass gContext_class;
@@ -325,7 +324,7 @@ static jint jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject disp
}
EGLDisplay dpy = getDisplay(_env, display);
EGLContext cnf = getConfig(_env, config);
- EGLNativeWindowType window = 0;
+ sp<ANativeWindow> window;
if (native_window == NULL) {
not_valid_surface:
doThrow(_env, "java/lang/IllegalArgumentException",
@@ -333,12 +332,12 @@ not_valid_surface:
return 0;
}
- window = android_Surface_getEGLNativeWindow(_env, native_window);
+ window = android_Surface_getNativeWindow(_env, native_window);
if (window == NULL)
goto not_valid_surface;
jint* base = beginNativeAttribList(_env, attrib_list);
- EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window, base);
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
endNativeAttributeList(_env, attrib_list, base);
return (jint)sur;
}
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index c86bdfa57812..921ac8a09976 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -1103,29 +1103,6 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
}
@SmallTest
- public void testLruCachingOfSqliteCompiledSqlObjs() {
- mDatabase.execSQL("CREATE TABLE test (i int, j int);");
- mDatabase.execSQL("insert into test values(1,1);");
- // set cache size
- int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
- mDatabase.setMaxSqlCacheSize(N);
-
- // do N+1 queries - and when the 0th entry is removed from LRU cache due to the
- // insertion of (N+1)th entry, make sure 0th entry is closed
- ArrayList<SQLiteStatement> stmtObjs = new ArrayList<SQLiteStatement>();
- for (int i = 0; i < N+1; i++) {
- SQLiteStatement c = mDatabase.compileStatement("select * from test where i = " + i);
- c.close();
- stmtObjs.add(i, c);
- }
-
- assertEquals(0, stmtObjs.get(0).getUniqueId());
- for (int i = 1; i < N+1; i++) {
- assertTrue(stmtObjs.get(i).getUniqueId() > 0);
- }
- }
-
- @SmallTest
public void testSetMaxCahesize() {
mDatabase.execSQL("CREATE TABLE test (i int, j int);");
mDatabase.execSQL("insert into test values(1,1);");
diff --git a/core/tests/coretests/src/android/database/sqlite/AbstractJDBCDriverTest.java b/core/tests/coretests/src/android/database/sqlite/AbstractJDBCDriverTest.java
deleted file mode 100644
index 19c7bcb03cc9..000000000000
--- a/core/tests/coretests/src/android/database/sqlite/AbstractJDBCDriverTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2008 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.sqlite;
-
-import java.io.File;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-import junit.framework.TestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-/**
- * Tests for the most commonly used methods of sql like creating a connection,
- * inserting, selecting, updating.
- */
-public abstract class AbstractJDBCDriverTest extends TestCase {
-
- @MediumTest
- public void testJDBCDriver() throws Exception {
- Connection firstConnection = null;
- Connection secondConnection = null;
- File dbFile = getDbFile();
- String connectionURL = getConnectionURL();
- Statement firstStmt = null;
- Statement secondStmt = null;
- try {
- Class.forName(getJDBCDriverClassName());
- firstConnection = DriverManager.getConnection(connectionURL);
- secondConnection = DriverManager.getConnection(connectionURL);
-
- String[] ones = {"hello!", "goodbye"};
- short[] twos = {10, 20};
- String[] onesUpdated = new String[ones.length];
- for (int i = 0; i < ones.length; i++) {
- onesUpdated[i] = ones[i] + twos[i];
- }
- firstStmt = firstConnection.createStatement();
- firstStmt.execute("create table tbl1(one varchar(10), two smallint)");
- secondStmt = secondConnection.createStatement();
-
- autoCommitInsertSelectTest(firstStmt, ones, twos);
- updateSelectCommitSelectTest(firstStmt, secondStmt, ones, onesUpdated, twos);
- updateSelectRollbackSelectTest(firstStmt, secondStmt, onesUpdated, ones, twos);
- } finally {
- closeConnections(firstConnection, secondConnection, dbFile, firstStmt, secondStmt);
- }
- }
-
- protected abstract String getJDBCDriverClassName();
- protected abstract String getConnectionURL();
- protected abstract File getDbFile();
-
- private void closeConnections(Connection firstConnection, Connection secondConnection,
- File dbFile, Statement firstStmt, Statement secondStmt) {
- String failText = null;
- try {
- if (firstStmt != null) {
- firstStmt.execute("drop table tbl1");
- }
- } catch (SQLException e) {
- failText = e.getLocalizedMessage();
- }
- try {
- if (firstStmt != null) {
- firstStmt.close();
- }
- } catch (SQLException e) {
- failText = e.getLocalizedMessage();
- }
- try {
- if (firstConnection != null) {
- firstConnection.close();
- }
- } catch (SQLException e) {
- failText = e.getLocalizedMessage();
- }
- try {
- if (secondStmt != null) {
- secondStmt.close();
- }
- } catch (SQLException e) {
- failText = e.getLocalizedMessage();
- }
- try {
- if (secondConnection != null) {
- secondConnection.close();
- }
- } catch (SQLException e) {
- failText = e.getLocalizedMessage();
- }
- dbFile.delete();
- assertNull(failText, failText);
- }
-
- /**
- * Inserts the values from 'ones' with the values from 'twos' into 'tbl1'
- * @param stmt the statement to use for the inserts.
- * @param ones the string values to insert into tbl1.
- * @param twos the corresponding numerical values to insert into tbl1.
- * @throws SQLException in case of a problem during insert.
- */
- private void autoCommitInsertSelectTest(Statement stmt, String[] ones,
- short[] twos) throws SQLException {
- for (int i = 0; i < ones.length; i++) {
- stmt.execute("insert into tbl1 values('" + ones[i] + "'," + twos[i]
- + ")");
- }
- assertAllFromTbl1(stmt, ones, twos);
- }
-
- /**
- * Asserts that all values that where added to tbl1 are actually in tbl1.
- * @param stmt the statement to use for the select.
- * @param ones the string values that where added.
- * @param twos the numerical values that where added.
- * @throws SQLException in case of a problem during select.
- */
- private void assertAllFromTbl1(Statement stmt, String[] ones, short[] twos)
- throws SQLException {
- ResultSet rs = stmt.executeQuery("select * from tbl1");
- int i = 0;
- for (; rs.next(); i++) {
- assertTrue(i < ones.length);
- assertEquals(ones[i], rs.getString("one"));
- assertEquals(twos[i], rs.getShort("two"));
- }
- assertEquals(i, ones.length);
- }
-
- /**
- * Tests the results of an update followed bz a select on a diffrent statement.
- * After that the first statement commits its update. and now the second
- * statement should also be able to see the changed values in a select.
- * @param firstStmt the statement to use for the update and commit.
- * @param secondStmt the statement that should be used to check if the commit works
- * @param ones the original string values.
- * @param onesUpdated the updated string values.
- * @param twos the numerical values.
- * @throws SQLException in case of a problem during any of the executed commands.
- */
- private void updateSelectCommitSelectTest(Statement firstStmt,
- Statement secondStmt, String[] ones, String[] onesUpdated,
- short[] twos) throws SQLException {
- firstStmt.getConnection().setAutoCommit(false);
- try {
- updateOnes(firstStmt, onesUpdated, twos);
- assertAllFromTbl1(secondStmt, ones, twos);
- firstStmt.getConnection().commit();
- assertAllFromTbl1(secondStmt, onesUpdated, twos);
- } finally {
- firstStmt.getConnection().setAutoCommit(true);
- }
- }
-
- /**
- * Tests if an update followed by a select works. After that a rollback will
- * be made and again a select should show that the rollback worked.
- * @param firstStmt the statement to use for the update and the rollback
- * @param secondStmt the statement to use for checking if the rollback worked as intended.
- * @param ones the original string values.
- * @param onesUpdated the updated string values.
- * @param twos the nomerical values.
- * @throws SQLException in case of a problem during any command.
- */
- private void updateSelectRollbackSelectTest(Statement firstStmt,
- Statement secondStmt, String[] ones, String[] onesUpdated,
- short[] twos) throws SQLException {
- firstStmt.getConnection().setAutoCommit(false);
- try {
- updateOnes(firstStmt, onesUpdated, twos);
- assertAllFromTbl1(secondStmt, ones, twos);
- firstStmt.getConnection().rollback();
- assertAllFromTbl1(secondStmt, ones, twos);
- } finally {
- firstStmt.getConnection().setAutoCommit(true);
- }
- }
-
- /**
- * updates the sring values. the original values are stored in 'ones'
- * and the updated values in 'ones_updated'
- * @param stmt the statement to use for the update.
- * @param onesUpdated the new string values.
- * @param twos the numerical values.
- * @throws SQLException in case of a problem during update.
- */
- private void updateOnes(Statement stmt, String[] onesUpdated, short[] twos)
- throws SQLException {
- for (int i = 0; i < onesUpdated.length; i++) {
- stmt.execute("UPDATE tbl1 SET one = '" + onesUpdated[i]
- + "' WHERE two = " + twos[i]);
- }
- }
-}
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index b098b5cc0927..eac9eea28038 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
@@ -18,12 +18,16 @@ package android.database.sqlite;
import android.content.Context;
import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteStatement;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import java.io.File;
+import java.util.ArrayList;
public class SQLiteDatabaseTest extends AndroidTestCase {
private static final String TAG = "DatabaseGeneralTest";
@@ -125,6 +129,7 @@ public class SQLiteDatabaseTest extends AndroidTestCase {
* </ul>
*/
@LargeTest
+ @Suppress // run this test only if you need to collect the numbers from this test
public void testConcurrencyEffectsOfConnPool() throws Exception {
// run the test with sqlite WAL enable
runConnectionPoolTest(true);
@@ -271,4 +276,37 @@ public class SQLiteDatabaseTest extends AndroidTestCase {
setCounts(readerNum, numReads);
}
}
+
+ @SmallTest
+ public void testLruCachingOfSqliteCompiledSqlObjs() {
+ mDatabase.execSQL("CREATE TABLE test (i int, j int);");
+ mDatabase.execSQL("insert into test values(1,1);");
+ // set cache size
+ int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
+ mDatabase.setMaxSqlCacheSize(N);
+
+ // do N+1 queries - and when the 0th entry is removed from LRU cache due to the
+ // insertion of (N+1)th entry, make sure 0th entry is closed
+ ArrayList<Integer> stmtObjs = new ArrayList<Integer>();
+ ArrayList<String> sqlStrings = new ArrayList<String>();
+ SQLiteStatement stmt0 = null;
+ for (int i = 0; i < N+1; i++) {
+ String s = "select * from test where i = " + i;
+ sqlStrings.add(s);
+ SQLiteStatement c = mDatabase.compileStatement(s);
+ stmtObjs.add(i, c.getUniqueId());
+ if (i == 0) {
+ // save thie SQLiteStatement obj. we want to make sure it is thrown out of
+ // the cache and its handle is 0'ed.
+ stmt0 = c;
+ }
+ c.close();
+ }
+ // is 0'th entry out of the cache?
+ assertEquals(0, stmt0.getUniqueId());
+ for (int i = 1; i < N+1; i++) {
+ SQLiteCompiledSql compSql = mDatabase.getCompiledStatementForSql(sqlStrings.get(i));
+ assertTrue(stmtObjs.contains(compSql.nStatement));
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteJDBCDriverTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteJDBCDriverTest.java
deleted file mode 100644
index 8e677a5b8702..000000000000
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteJDBCDriverTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2008 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.sqlite;
-
-import java.io.File;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.sql.Statement;
-import android.test.suitebuilder.annotation.MediumTest;
-
-/**
- * Minimal test for JDBC driver
- */
-public class SQLiteJDBCDriverTest extends AbstractJDBCDriverTest {
-
- private File dbFile;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- dbFile = File.createTempFile("sqliteTestDB", null);
- }
-
- @Override
- protected void tearDown() throws Exception {
- if(dbFile != null) {
- dbFile.delete();
- }
- super.tearDown();
- }
-
- @Override
- protected String getConnectionURL() {
- return "jdbc:sqlite:/" + dbFile;
- }
-
- @Override
- protected File getDbFile() {
- return dbFile;
- }
-
- @Override
- protected String getJDBCDriverClassName() {
- return "SQLite.JDBCDriver";
- }
-
- // Regression test for (Noser) #255: PreparedStatement.executeUpdate results
- // in VM crashing with SIGABRT.
- @MediumTest
- public void test_connection3() throws Exception {
- PreparedStatement prst = null;
- Statement st = null;
- Connection conn = null;
- try {
- Class.forName("SQLite.JDBCDriver").newInstance();
- if (dbFile.exists()) {
- dbFile.delete();
- }
- conn = DriverManager.getConnection("jdbc:sqlite:/"
- + dbFile.getPath());
- assertNotNull(conn);
-
- // create table
- st = conn.createStatement();
- String sql = "CREATE TABLE zoo (ZID INTEGER NOT NULL, family VARCHAR (20) NOT NULL, name VARCHAR (20) NOT NULL, PRIMARY KEY(ZID) )";
- st.executeUpdate(sql);
-
- String update = "update zoo set family = ? where name = ?;";
- prst = conn.prepareStatement(update);
- prst.setString(1, "cat");
- prst.setString(2, "Yasha");
- // st = conn.createStatement();
- // st.execute("select * from zoo where family = 'cat'");
- // ResultSet rs = st.getResultSet();
- // assertEquals(0, getCount(rs));
- prst.executeUpdate();
- // st.execute("select * from zoo where family = 'cat'");
- // ResultSet rs1 = st.getResultSet();
- // assertEquals(1, getCount(rs1));
- try {
- prst = conn.prepareStatement("");
- prst.execute();
- fail("SQLException is not thrown");
- } catch (SQLException e) {
- // expected
- }
-
- try {
- conn.prepareStatement(null);
- fail("NPE is not thrown");
- } catch (Exception e) {
- // expected
- }
- try {
- st = conn.createStatement();
- st.execute("drop table if exists zoo");
-
- } catch (SQLException e) {
- fail("Couldn't drop table: " + e.getMessage());
- } finally {
- try {
- st.close();
- conn.close();
- } catch (SQLException ee) {
- }
- }
- } finally {
- try {
- if (prst != null) {
- prst.close();
- }
- if (st != null) {
- st.close();
- }
- } catch (SQLException ee) {
- }
- }
-
- }
-
-}
diff --git a/docs/html/guide/developing/eclipse-adt.jd b/docs/html/guide/developing/eclipse-adt.jd
index cf2a45716d34..66379a3945d2 100644
--- a/docs/html/guide/developing/eclipse-adt.jd
+++ b/docs/html/guide/developing/eclipse-adt.jd
@@ -527,7 +527,7 @@ Marking a project as an Android library project. </p>
<p>A library project's manifest file must declare all of the shared components
that it includes, just as would a standard Android application. For more
information, see the documentation for <a
-href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
<p>For example, the <a
href="{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a>
@@ -613,7 +613,8 @@ like this: </p>
...
&lt;/manifest&gt;</pre>
-<p>For more information about the manifest file, see the documentation for <a href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+<p>For more information about the manifest file, see the documentation for <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
<h3 id="considerations">Development considerations</h3>
diff --git a/docs/html/guide/developing/other-ide.jd b/docs/html/guide/developing/other-ide.jd
index e8a6fb6494f8..1d67aa90ede4 100644
--- a/docs/html/guide/developing/other-ide.jd
+++ b/docs/html/guide/developing/other-ide.jd
@@ -687,7 +687,7 @@ so that other applications can use it, you can do so by adding a the
<p>A library project's manifest file must declare all of the shared components
that it includes, just as would a standard Android application. For more
information, see the documentation for <a
-href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
<p>For example, the <a
href="{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a>
@@ -799,7 +799,8 @@ like this: </p>
...
&lt;/manifest&gt;</pre>
-<p>For more information about the manifest file, see the documentation for <a href="{@docRoot}guide/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
+<p>For more information about the manifest file, see the documentation for <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p>
<h3 id="depAppBuild">Building a dependent application</h3>
diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd
index 2f3ac5ebb6bc..bd9ea52bc6ff 100644
--- a/docs/html/guide/samples/index.jd
+++ b/docs/html/guide/samples/index.jd
@@ -3,99 +3,13 @@ page.title=Sample Code
@jd:body
-<p>Sometimes, the best way to learn how things are done is to look at some code.
-Here, you can browse the source of some sample Android applications that are included
-in the Android SDK.</p>
+<script type="text/javascript">
+ window.location = toRoot + "resources/samples/index.html";
+</script>
-<p>Each version of the Android platform available for the SDK includes a full set of sample
-applications (which may vary between different versions of the platform).
-You can find the samples in your SDK at:</p>
+<p><strong>This document has moved. Please go to <a
+href="http://developer.android.com/resources/samples/index.html">List of Sample
+Apps</a>.</strong></p>
-<p style="margin-left:2em">
-<code><em>&lt;sdk&gt;</em>/platforms/android-<em>&lt;version&gt;</em>/samples/</code>
-</p>
-
-<p>You can easily create new Android projects with these samples, modify them
-if you'd like, then run them on an emulator or device. For example, to create
-a project for the API Demos app from Eclipse,
-start a new Android Project, select "Create project from existing source", then select
-{@code ApiDemos} in the {@code samples/} directory. To create the API Demos project
-using the {@code android} tool, execute:</p>
-<pre>
-android update project -s -n API Demos -t <em>&lt;target_ID></em> -p <em>&lt;path-to-platform></em>/samples/ApiDemos/
-</pre>
-
-<p>The pages below provide an overview of each sample application (available with most
-platforms) and allow you to view the source files in your browser. </p>
-
-<div class="special">
- <p>Some of the samples in this listing are not yet available in the
- SDK. While we work to update the SDK, you can
- <a href="{@docRoot}shareables/latest_samples.zip">download the latest samples</a> as a ZIP
- archive.</p>
-</div>
-
-<dl>
-
- <dt><a href="{@docRoot}resources/samples/ApiDemos/index.html">API Demos</a></dt>
- <dd>A variety of small applications that demonstrate an extensive collection of
- framework topics.</dd>
-
- <dt><a href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a></dt>
- <dd>An simple example that illustrates a few different ways for an application to
- implement support for the Android data backup and restore mechanism.</dd>
-
- <dt><a href="{@docRoot}resources/samples/BluetoothChat/index.html">Bluetooth Chat</a></dt>
- <dd>An application for two-way text messaging over Bluetooth.</dd>
-
- <dt><a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a></dt>
- <dd>An application that demonstrates how to query the system contacts provider
- using the <code>ContactsContract</code> API, as
- well as insert contacts into a specific account.</dd>
-
- <dt><a href="{@docRoot}resources/samples/Home/index.html">Home</a></dt>
- <dd>A home screen replacement application.</dd>
-
- <dt><a href="{@docRoot}resources/samples/JetBoy/index.html">JetBoy</a></dt>
- <dd>JetBoy is a game that demonstrates the SONiVOX JET interactive music technology,
- with {@link android.media.JetPlayer}.</dd>
-
- <dt><a href="{@docRoot}resources/samples/LunarLander/index.html">Lunar Lander</a></dt>
- <dd>A classic Lunar Lander game.</dd>
-
- <dt><a href="{@docRoot}resources/samples/MultiResolution/index.html">Multiple Resolutions</a></dt>
- <dd>A sample application that shows how to use resource directory qualifiers to
- provide different resources for different screen configurations.</dd>
-
- <dt><a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a></dt>
- <dd>An application for saving notes. Similar (but not identical) to the
- <a href="{@docRoot}resources/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
-
- <dt><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a></dt>
- <dd>A sample application that demonstrates Android's search framework,
- including how to provide search suggestions for Quick Search Box.</dd>
-
- <dt><a href="{@docRoot}resources/samples/Snake/index.html">Snake</a></dt>
- <dd>An implementation of the classic game "Snake."</dd>
-
- <dt><a href="{@docRoot}resources/samples/SoftKeyboard/index.html">Soft Keyboard</a></dt>
- <dd>An example of writing an input method for a software keyboard.</dd>
-
- <dt><a href=""{@docRoot}resources/samples/Wiktionary/index.html">Wiktionary</a></dt>
- <dd>An example of creating interactive widgets for display on the Android
- home screen.</dd>
-
- <dt><a href="{@docRoot}resources/samples/WiktionarySimple/index.html">Wiktionary (Simplified)</a></dt>
- <dd>A simple Android home screen widgets example.</dd>
-
-</dl>
-
-
-<div class="special">
-<p>For more sample applications, check out
-<a href="http://code.google.com/p/apps-for-android/">apps-for-android</a>, a
-collection of open source applications that demonstrate various Android APIs.
-</p>
-</div>
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index aeefca8f9553..6c02031fd4f5 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -240,7 +240,7 @@ Backup Service Key is ignored.</p>
<h2 id="BackupAgent">Extending BackupAgent</h2>
<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
-directly, but should instead <a href="BackupAgentHelper">extend BackupAgentHelper</a> to take
+directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
advantage of the built-in helper classes that automatically backup and restore your files. However,
you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
<ul>
@@ -262,7 +262,7 @@ create your table and insert the data during a restore operation.</li>
<p>If you don't need to perform any of the tasks above and want to back up complete files from
{@link android.content.SharedPreferences} or <a
href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
-should skip to <a href="BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
+should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index cac85e835fe0..7e2f8a0cea04 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -761,7 +761,7 @@ Android runs your application, it will crash if you do not provide default resou
cannot use the resources named with the new qualifier. For example, if your <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
minSdkVersion}</a> is set to 4, and you qualify all of your drawable resources using <a
-href="NightQualifier">night mode</a> ({@code night} or {@code notnight}, which were added in API
+href="#NightQualifier">night mode</a> ({@code night} or {@code notnight}, which were added in API
Level 8), then an API Level 4 device cannot access your drawable resources and will crash. In this
case, you probably want {@code notnight} to be your default resources, so you should exclude that
qualifier so your drawable resources are in either {@code drawable/} or {@code drawable-night/}.</p>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 5e751057e17d..6cb7228016b5 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -43,29 +43,73 @@ the development of your application features for the devices currently in
the hands of users. For information about how to target your application to devices based on
platform version, see <a href="{@docRoot}guide/appendix/api-levels.html">API Levels</a>.</p>
-<p class="note"><strong>Note:</strong> This data is based on the number
-of Android devices that have accessed Android Market within a 14-day period
-ending on the data collection date noted below.</p>
+
+<h3 id="Current">Current Distribution</h3>
+
+<p>The following pie chart and table is based on the number of Android devices that have accessed
+Android Market within a 14-day period ending on the data collection date noted below.</p>
<div class="dashboard-panel">
-<img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.1,24.6,25.0,0.1,0.3,50.0&chl=
-Android%201.1|Android%201.5|Android%201.6|Android%202.0|Android%202.0.1|Android%202.1&chco=c4df9b,
-6fad0c" />
+<img alt="" height="250" width="460"
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.3,21.3,23.5,53.1,1.8&chl=Other*|
+Android%201.5|Android%201.6|Android%202.1|Android%202.2&chco=c4df9b,6fad0c" />
<table>
<tr>
- <th>Android Platform</th>
- <th>Percent of Devices</th>
+ <th>Platform</th>
+ <th>API Level</th>
+ <th>Distribution</th>
</tr>
-<tr><td>Android 1.1</td><td>0.1%</td></tr>
-<tr><td>Android 1.5</td><td>24.6%</td></tr>
-<tr><td>Android 1.6</td><td>25.0%</td></tr>
-<tr><td>Android 2.0</td><td>0.1%</td></tr>
-<tr><td>Android 2.0.1</td><td>0.3%</td></tr>
-<tr><td>Android 2.1</td><td>50.0%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>21.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>23.5%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>53.1%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>1.8%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on June 16, 2010</em></p>
-</div>
+
+<p><em>Data collected during two weeks ending on July 1, 2010</em></p>
+<p style="font-size:.9em">* <em>Other: 0.3% of devices running obsolete versions</em></p>
+
+</div><!-- end dashboard-panel -->
+
+
+<h3 id="Historical">Historical Distribution</h3>
+
+<p>The following stacked line graph provides a history of the relative number of
+active Android devices running different versions of the Android platform. It also provides a
+valuable perspective of how many devices your application is compatible with, based on the
+platform version.</p>
+
+<p>Notice that the platform versions are stacked on top of each other with the oldest active
+version at the top. This format indicates the total percent of active devices that are compatible
+with a given version of Android. For example, if you develop your application for
+the version that is at the very top of the chart, then your application is
+compatible with 100% of active devices (and all future versions), because all Android APIs are
+forward compatible. Or, if you develop your application for a version lower on the chart,
+then it is currently compatible with the percentage of devices indicated on the y-axis, where the
+line for that version meets the y-axis on the right.</p>
+
+<p>Each dataset in the timeline is based on the number of Android devices that accessed
+Android Market within a 14-day period ending on the date indicated on the x-axis.</p>
+
+<div class="dashboard-panel">
+
+<img alt="" height="265" width="700" style="padding:5px;background:#fff"
+src="http://chart.apis.google.com/chart?&cht=lc&chs=700x265&chxt=x,y,r&chxr=0,0,10%7C1,0,100%7C2,0,
+100&chxl=0%3A%7C2010/02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%
+7C2010/07/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%
+7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10&chxtc=0,5&chd=t:99.0,99.2,99.4,99.5,99.6,99.6,99.6,99.7,100.6
+,101.1,99.9%7C63.4,62.5,61.6,60.6,61.5,61.7,62.3,63.5,73.0,76.4,78.6%7C22.6,23.2,24.3,25.4,29.4,30.2
+,32.7,35.3,46.2,51.3,55.1%7C0.0,0.0,0.0,0.0,4.0,28.3,32.0,34.9,45.9,51.0,54.9%7C0.0,0.0,0.0,0.0,0.0,
+0.0,0.0,0.0,0.8,1.2,1.8&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5%7Cb,c3df9b,0,1,0%7CtAndroid%201.6,
+638d23,1,0,15,,t::-5%7Cb,b0db6e,1,2,0%7CtAndroid%202.0.1,496c13,2,0,15,,t::-5%7Cb,9ddb3d,2,3,0%
+7CtAndroid%202.1,2f4708,3,5,15,,t::-5%7Cb,89cf19,3,4,0%7CB,6fad0c,4,5,0&chg=9,25&chdl=Android%201.5%
+20(API%20Level%203)%7CAndroid%201.6%20(API%20Level%204)%7CAndroid%202.0.1%20(API%20Level%206)%
+7CAndroid%202.1%20(API%20Level%207)%7CAndroid%202.2%20(API%20Level %208)&chco=add274,
+9ad145,84c323,6ba213,507d08" />
+
+<p><em>Last historical dataset collected during two weeks ending on July 1, 2010</em></p>
+
+
+</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index f8130ea50e9d..89fdd2d30352 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -49,7 +49,7 @@ ending on the data collection date noted below.</p>
<div class="dashboard-panel">
<img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.1,57.8,41.0&chl=Small%20/%20ldpi|
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.4,54.5,44.1&chl=Small%20/%20ldpi|
Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
<table>
@@ -60,14 +60,14 @@ Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
<th scope="col">High Density</th>
</tr>
<tr><th scope="row">Small</th>
-<td class='cent hi'>1.1%</td>
+<td class='cent hi'>1.4%</td>
<td></td>
<td></td>
</tr>
<tr><th scope="row">Normal</th>
<td></td>
-<td class='cent hi'>57.8%</td>
-<td class='cent hi'>41.0%</td>
+<td class='cent hi'>54.5%</td>
+<td class='cent hi'>44.1%</td>
</tr>
<tr><th scope="row">Large</th>
<td></td>
@@ -76,6 +76,6 @@ Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
</tr>
</table>
-<p><em>Data collected during two weeks ending on June 16, 2010</em></p>
+<p><em>Data collected during two weeks ending on July 1, 2010</em></p>
</div>
diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd
index c3ba49566e70..77f7e43783b6 100644
--- a/docs/html/sdk/older_releases.jd
+++ b/docs/html/sdk/older_releases.jd
@@ -47,7 +47,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.6_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.6_r1.zip">android-sdk-
windows-1 .6_r1.zip</a>
</td>
<td>260529085 bytes</td>
@@ -57,7 +57,7 @@ windows-1 .6_r1.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
mac_x86-1 .6_r1.zip</a>
</td>
<td>247412515 bytes</td>
@@ -67,7 +67,7 @@ mac_x86-1 .6_r1.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.6_r1.tgz">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.6_r1.tgz">android-
sdk- linux_x86-1.6_r1.tgz</a>
</td>
<td>238224860 bytes</td>
@@ -92,7 +92,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.5_r3.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r3.zip">android-sdk-
windows-1 .5_r3.zip</a>
</td>
<td>191477853 bytes</td>
@@ -102,7 +102,7 @@ windows-1 .5_r3.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
mac_x86-1 .5_r3.zip</a>
</td>
<td>183024673 bytes</td>
@@ -112,7 +112,7 @@ mac_x86-1 .5_r3.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r3.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r3.zip">android-
sdk- linux_x86-1.5_r3.zip</a>
</td>
<td>178117561 bytes</td>
@@ -137,7 +137,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.1_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.1_r1.zip">android-sdk-
windows-1
.1_r1.zip</a>
</td>
@@ -148,7 +148,7 @@ windows-1
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
mac_x86-1
.1_r1.zip</a>
</td>
@@ -159,7 +159,7 @@ mac_x86-1
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.1_r1.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.1_r1.zip">android-
sdk-
linux_x86-1.1_r1.zip</a>
</td>
@@ -185,7 +185,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.0_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r2.zip">android-sdk-
windows-1
.0_r2.zip</a>
</td>
@@ -196,7 +196,7 @@ windows-1
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
mac_x86-1
.0_r2.zip</a>
</td>
@@ -207,7 +207,7 @@ mac_x86-1
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r2.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r2.zip">android-
sdk-
linux_x86-1.0_r2.zip</a>
</td>
@@ -241,7 +241,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.5_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r2.zip">android-sdk-
windows-1 .5_r2.zip</a>
</td>
<td>178346828 bytes</td>
@@ -251,7 +251,7 @@ windows-1 .5_r2.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
mac_x86-1 .5_r2.zip</a>
</td>
<td>169945128 bytes</td>
@@ -261,7 +261,7 @@ mac_x86-1 .5_r2.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r2.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r2.zip">android-
sdk- linux_x86-1.5_r2.zip</a>
</td>
<td>165035130 bytes</td>
@@ -286,7 +286,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.5_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r1.zip">android-sdk-
windows-1 .5_r1.zip</a>
</td>
<td>176263368 bytes</td>
@@ -296,7 +296,7 @@ windows-1 .5_r1.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
mac_x86-1 .5_r1.zip</a>
</td>
<td>167848675 bytes</td>
@@ -306,7 +306,7 @@ mac_x86-1 .5_r1.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r1.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r1.zip">android-
sdk- linux_x86-1.5_r1.zip</a>
</td>
<td>162938845 bytes</td>
@@ -331,7 +331,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-windows-1.0_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r1.zip">android-sdk-
windows-1 .0_r1.zip</a>
</td>
<td>89.7 MB bytes</td>
@@ -341,7 +341,7 @@ windows-1 .0_r1.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
+href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
mac_x86-1 .0_r1.zip</a>
</td>
<td>87.5 MB bytes</td>
@@ -351,7 +351,7 @@ mac_x86-1 .0_r1.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="/sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r1.zip">android-
+href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r1.zip">android-
sdk- linux_x86-1.0_r1.zip</a>
</td>
<td>87.8 MB bytes</td>
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
index fb36f1faa401..3b3711bb320f 100644
--- a/graphics/java/android/renderscript/FileA3D.java
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -36,7 +36,6 @@ public class FileA3D extends BaseObj {
UNKNOWN,
MESH,
- SIMPLE_MESH,
TYPE,
ELEMENT,
ALLOCATION,
@@ -89,10 +88,7 @@ public class FileA3D extends BaseObj {
switch (mClassID) {
case MESH:
- mLoadedObj = null;
- break;
- case SIMPLE_MESH:
- mLoadedObj = new SimpleMesh(objectID, mRS);
+ mLoadedObj = new Mesh(objectID, mRS);
break;
case TYPE:
mLoadedObj = new Type(objectID, mRS);
diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java
new file mode 100644
index 000000000000..5a538787d601
--- /dev/null
+++ b/graphics/java/android/renderscript/Mesh.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2008 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.renderscript;
+
+import java.util.Vector;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class Mesh extends BaseObj {
+
+ Allocation[] mVertexBuffers;
+ Allocation[] mIndexBuffers;
+ Primitive[] mPrimitives;
+
+ Mesh(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public int getVertexAllocationCount() {
+ if(mVertexBuffers == null) {
+ return 0;
+ }
+ return mVertexBuffers.length;
+ }
+ public Allocation getVertexAllocation(int slot) {
+ return mVertexBuffers[slot];
+ }
+
+ public int getPrimitiveCount() {
+ if(mIndexBuffers == null) {
+ return 0;
+ }
+ return mIndexBuffers.length;
+ }
+ public Allocation getIndexAllocation(int slot) {
+ return mIndexBuffers[slot];
+ }
+ public Primitive getPrimitive(int slot) {
+ return mPrimitives[slot];
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+
+ class Entry {
+ Type t;
+ Element e;
+ int size;
+ Primitive prim;
+ }
+
+ int mVertexTypeCount;
+ Entry[] mVertexTypes;
+ Vector mIndexTypes;
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mVertexTypeCount = 0;
+ mVertexTypes = new Entry[16];
+ mIndexTypes = new Vector();
+ }
+
+ public int addVertexType(Type t) throws IllegalStateException {
+ if (mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].t = t;
+ mVertexTypes[mVertexTypeCount].e = null;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public int addVertexType(Element e, int size) throws IllegalStateException {
+ if (mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].t = null;
+ mVertexTypes[mVertexTypeCount].e = e;
+ mVertexTypes[mVertexTypeCount].size = size;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public int addIndexType(Type t, Primitive p) {
+ int addedIndex = mIndexTypes.size();
+ Entry indexType = new Entry();
+ indexType.t = t;
+ indexType.e = null;
+ indexType.size = 0;
+ indexType.prim = p;
+ mIndexTypes.addElement(indexType);
+ return addedIndex;
+ }
+
+ public int addIndexType(Primitive p) {
+ int addedIndex = mIndexTypes.size();
+ Entry indexType = new Entry();
+ indexType.t = null;
+ indexType.e = null;
+ indexType.size = 0;
+ indexType.prim = p;
+ mIndexTypes.addElement(indexType);
+ return addedIndex;
+ }
+
+ public int addIndexType(Element e, int size, Primitive p) {
+ int addedIndex = mIndexTypes.size();
+ Entry indexType = new Entry();
+ indexType.t = null;
+ indexType.e = e;
+ indexType.size = size;
+ indexType.prim = p;
+ mIndexTypes.addElement(indexType);
+ return addedIndex;
+ }
+
+ Type newType(Element e, int size) {
+ Type.Builder tb = new Type.Builder(mRS, e);
+ tb.add(Dimension.X, size);
+ return tb.create();
+ }
+
+ static synchronized Mesh internalCreate(RenderScript rs, Builder b) {
+
+ int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size());
+ Mesh newMesh = new Mesh(id, rs);
+ newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()];
+ newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()];
+ newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount];
+
+ for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) {
+ Allocation alloc = null;
+ Entry entry = (Entry)b.mIndexTypes.elementAt(ct);
+ if (entry.t != null) {
+ alloc = Allocation.createTyped(rs, entry.t);
+ }
+ else if(entry.e != null) {
+ alloc = Allocation.createSized(rs, entry.e, entry.size);
+ }
+ int allocID = (alloc == null) ? 0 : alloc.getID();
+ rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct);
+ newMesh.mIndexBuffers[ct] = alloc;
+ newMesh.mPrimitives[ct] = entry.prim;
+ }
+
+ for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
+ Allocation alloc = null;
+ Entry entry = b.mVertexTypes[ct];
+ if (entry.t != null) {
+ alloc = Allocation.createTyped(rs, entry.t);
+ } else if(entry.e != null) {
+ alloc = Allocation.createSized(rs, entry.e, entry.size);
+ }
+ rs.nMeshBindVertex(id, alloc.getID(), ct);
+ newMesh.mVertexBuffers[ct] = alloc;
+ }
+
+ return newMesh;
+ }
+
+ public Mesh create() {
+ mRS.validate();
+ Mesh sm = internalCreate(mRS, this);
+ return sm;
+ }
+ }
+
+ public static class AllocationBuilder {
+ RenderScript mRS;
+
+ class Entry {
+ Allocation a;
+ Primitive prim;
+ }
+
+ int mVertexTypeCount;
+ Entry[] mVertexTypes;
+
+ Vector mIndexTypes;
+
+ public AllocationBuilder(RenderScript rs) {
+ mRS = rs;
+ mVertexTypeCount = 0;
+ mVertexTypes = new Entry[16];
+ mIndexTypes = new Vector();
+ }
+
+ public int addVertexAllocation(Allocation a) throws IllegalStateException {
+ if (mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].a = a;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public int addIndexAllocation(Allocation a, Primitive p) {
+ int addedIndex = mIndexTypes.size();
+ Entry indexType = new Entry();
+ indexType.a = a;
+ indexType.prim = p;
+ mIndexTypes.addElement(indexType);
+ return addedIndex;
+ }
+
+ public int addIndexType(Primitive p) {
+ int addedIndex = mIndexTypes.size();
+ Entry indexType = new Entry();
+ indexType.a = null;
+ indexType.prim = p;
+ mIndexTypes.addElement(indexType);
+ return addedIndex;
+ }
+
+ static synchronized Mesh internalCreate(RenderScript rs, AllocationBuilder b) {
+
+ int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size());
+ Mesh newMesh = new Mesh(id, rs);
+ newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()];
+ newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()];
+ newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount];
+
+ for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) {
+ Entry entry = (Entry)b.mIndexTypes.elementAt(ct);
+ int allocID = (entry.a == null) ? 0 : entry.a.getID();
+ rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct);
+ newMesh.mIndexBuffers[ct] = entry.a;
+ newMesh.mPrimitives[ct] = entry.prim;
+ }
+
+ for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
+ Entry entry = b.mVertexTypes[ct];
+ rs.nMeshBindVertex(id, entry.a.mID, ct);
+ newMesh.mVertexBuffers[ct] = entry.a;
+ }
+
+ return newMesh;
+ }
+
+ public Mesh create() {
+ mRS.validate();
+ Mesh sm = internalCreate(mRS, this);
+ return sm;
+ }
+ }
+
+
+ public static class TriangleMeshBuilder {
+ float mVtxData[];
+ int mVtxCount;
+ short mIndexData[];
+ int mIndexCount;
+ RenderScript mRS;
+ Element mElement;
+
+ float mNX = 0;
+ float mNY = 0;
+ float mNZ = -1;
+ float mS0 = 0;
+ float mT0 = 0;
+ float mR = 1;
+ float mG = 1;
+ float mB = 1;
+ float mA = 1;
+
+ int mVtxSize;
+ int mFlags;
+
+ public static final int COLOR = 0x0001;
+ public static final int NORMAL = 0x0002;
+ public static final int TEXTURE_0 = 0x0100;
+
+ public TriangleMeshBuilder(RenderScript rs, int vtxSize, int flags) {
+ mRS = rs;
+ mVtxCount = 0;
+ mIndexCount = 0;
+ mVtxData = new float[128];
+ mIndexData = new short[128];
+ mVtxSize = vtxSize;
+ mFlags = flags;
+
+ if (vtxSize < 2 || vtxSize > 3) {
+ throw new IllegalArgumentException("Vertex size out of range.");
+ }
+ }
+
+ private void makeSpace(int count) {
+ if ((mVtxCount + count) >= mVtxData.length) {
+ float t[] = new float[mVtxData.length * 2];
+ System.arraycopy(mVtxData, 0, t, 0, mVtxData.length);
+ mVtxData = t;
+ }
+ }
+
+ private void latch() {
+ if ((mFlags & COLOR) != 0) {
+ makeSpace(4);
+ mVtxData[mVtxCount++] = mR;
+ mVtxData[mVtxCount++] = mG;
+ mVtxData[mVtxCount++] = mB;
+ mVtxData[mVtxCount++] = mA;
+ }
+ if ((mFlags & TEXTURE_0) != 0) {
+ makeSpace(2);
+ mVtxData[mVtxCount++] = mS0;
+ mVtxData[mVtxCount++] = mT0;
+ }
+ if ((mFlags & NORMAL) != 0) {
+ makeSpace(3);
+ mVtxData[mVtxCount++] = mNX;
+ mVtxData[mVtxCount++] = mNY;
+ mVtxData[mVtxCount++] = mNZ;
+ }
+ }
+
+ public void addVertex(float x, float y) {
+ if (mVtxSize != 2) {
+ throw new IllegalStateException("add mistmatch with declared components.");
+ }
+ makeSpace(2);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ latch();
+ }
+
+ public void addVertex(float x, float y, float z) {
+ if (mVtxSize != 3) {
+ throw new IllegalStateException("add mistmatch with declared components.");
+ }
+ makeSpace(3);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ mVtxData[mVtxCount++] = z;
+ latch();
+ }
+
+ public void setTexture(float s, float t) {
+ if ((mFlags & TEXTURE_0) == 0) {
+ throw new IllegalStateException("add mistmatch with declared components.");
+ }
+ mS0 = s;
+ mT0 = t;
+ }
+
+ public void setNormal(float x, float y, float z) {
+ if ((mFlags & NORMAL) == 0) {
+ throw new IllegalStateException("add mistmatch with declared components.");
+ }
+ mNX = x;
+ mNY = y;
+ mNZ = z;
+ }
+
+ public void setColor(float r, float g, float b, float a) {
+ if ((mFlags & COLOR) == 0) {
+ throw new IllegalStateException("add mistmatch with declared components.");
+ }
+ mR = r;
+ mG = g;
+ mB = b;
+ mA = a;
+ }
+
+ public void addTriangle(int idx1, int idx2, int idx3) {
+ if((idx1 >= mVtxCount) || (idx1 < 0) ||
+ (idx2 >= mVtxCount) || (idx2 < 0) ||
+ (idx3 >= mVtxCount) || (idx3 < 0)) {
+ throw new IllegalStateException("Index provided greater than vertex count.");
+ }
+ if ((mIndexCount + 3) >= mIndexData.length) {
+ short t[] = new short[mIndexData.length * 2];
+ System.arraycopy(mIndexData, 0, t, 0, mIndexData.length);
+ mIndexData = t;
+ }
+ mIndexData[mIndexCount++] = (short)idx1;
+ mIndexData[mIndexCount++] = (short)idx2;
+ mIndexData[mIndexCount++] = (short)idx3;
+ }
+
+ public Mesh create(boolean uploadToBufferObject) {
+ Element.Builder b = new Element.Builder(mRS);
+ int floatCount = mVtxSize;
+ b.add(Element.createVector(mRS,
+ Element.DataType.FLOAT_32,
+ mVtxSize), "position");
+ if ((mFlags & COLOR) != 0) {
+ floatCount += 4;
+ b.add(Element.F32_4(mRS), "color");
+ }
+ if ((mFlags & TEXTURE_0) != 0) {
+ floatCount += 2;
+ b.add(Element.F32_2(mRS), "texture0");
+ }
+ if ((mFlags & NORMAL) != 0) {
+ floatCount += 3;
+ b.add(Element.F32_3(mRS), "normal");
+ }
+ mElement = b.create();
+
+ Builder smb = new Builder(mRS);
+ smb.addVertexType(mElement, mVtxCount / floatCount);
+ smb.addIndexType(Element.U16(mRS), mIndexCount, Primitive.TRIANGLE);
+
+ Mesh sm = smb.create();
+
+ sm.getVertexAllocation(0).data(mVtxData);
+ if(uploadToBufferObject) {
+ sm.getVertexAllocation(0).uploadToBufferObject();
+ }
+
+ sm.getIndexAllocation(0).data(mIndexData);
+ sm.getIndexAllocation(0).uploadToBufferObject();
+
+ return sm;
+ }
+ }
+}
+
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index b2e5b02cadec..c7e8ca5929bc 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -186,6 +186,10 @@ public class RenderScript {
native void nLightSetColor(int l, float r, float g, float b);
native void nLightSetPosition(int l, float x, float y, float z);
+ native int nMeshCreate(int vtxCount, int indexCount);
+ native void nMeshBindVertex(int id, int alloc, int slot);
+ native void nMeshBindIndex(int id, int alloc, int prim, int slot);
+
native int nSimpleMeshCreate(int batchID, int idxID, int[] vtxID, int prim);
native void nSimpleMeshBindVertex(int id, int alloc, int slot);
native void nSimpleMeshBindIndex(int id, int alloc);
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index c61a21595084..a6d2489c2944 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1351,6 +1351,33 @@ nLightSetPosition(JNIEnv *_env, jobject _this, jint light, float x, float y, flo
// ---------------------------------------------------------------------------
static jint
+nMeshCreate(JNIEnv *_env, jobject _this, jint vtxCount, jint idxCount)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nMeshCreate, con(%p), vtxCount(%i), idxCount(%i)", con, vtxCount, idxCount);
+ int id = (int)rsMeshCreate(con, vtxCount, idxCount);
+ return id;
+}
+
+static void
+nMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nMeshBindVertex, con(%p), Mesh(%p), Alloc(%p), slot(%i)", con, (RsMesh)s, (RsAllocation)alloc, slot);
+ rsMeshBindVertex(con, (RsMesh)s, (RsAllocation)alloc, slot);
+}
+
+static void
+nMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint primID, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nMeshBindIndex, con(%p), Mesh(%p), Alloc(%p)", con, (RsMesh)s, (RsAllocation)alloc);
+ rsMeshBindIndex(con, (RsMesh)s, (RsAllocation)alloc, primID, slot);
+}
+
+// ---------------------------------------------------------------------------
+
+static jint
nSimpleMeshCreate(JNIEnv *_env, jobject _this, jint batchID, jint indexID, jintArray vtxIDs, jint primID)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -1367,16 +1394,16 @@ static void
nSimpleMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nSimpleMeshBindVertex, con(%p), SimpleMesh(%p), Alloc(%p), slot(%i)", con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
- rsSimpleMeshBindVertex(con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
+ LOG_API("nSimpleMeshBindVertex, con(%p), Mesh(%p), Alloc(%p), slot(%i)", con, (RsMesh)s, (RsAllocation)alloc, slot);
+ rsSimpleMeshBindVertex(con, (RsMesh)s, (RsAllocation)alloc, slot);
}
static void
nSimpleMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
- LOG_API("nSimpleMeshBindIndex, con(%p), SimpleMesh(%p), Alloc(%p)", con, (RsSimpleMesh)s, (RsAllocation)alloc);
- rsSimpleMeshBindIndex(con, (RsSimpleMesh)s, (RsAllocation)alloc);
+ LOG_API("nSimpleMeshBindIndex, con(%p), Mesh(%p), Alloc(%p)", con, (RsMesh)s, (RsAllocation)alloc);
+ rsSimpleMeshBindIndex(con, (RsMesh)s, (RsAllocation)alloc);
}
// ---------------------------------------------------------------------------
@@ -1513,6 +1540,10 @@ static JNINativeMethod methods[] = {
{"nSimpleMeshBindVertex", "(III)V", (void*)nSimpleMeshBindVertex },
{"nSimpleMeshBindIndex", "(II)V", (void*)nSimpleMeshBindIndex },
+{"nMeshCreate", "(II)I", (void*)nMeshCreate },
+{"nMeshBindVertex", "(III)V", (void*)nMeshBindVertex },
+{"nMeshBindIndex", "(IIII)V", (void*)nMeshBindIndex },
+
};
static int registerFuncs(JNIEnv *_env)
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 3192d03a0643..fd30ba58d4e9 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -35,6 +35,10 @@ public:
static CameraSource *Create();
static CameraSource *CreateFromCamera(const sp<Camera> &camera);
+ void enableTimeLapseMode(
+ int64_t timeBetweenTimeLapseFrameCaptureUs, int32_t videoFrameRate);
+ void disableTimeLapseMode();
+
virtual ~CameraSource();
virtual status_t start(MetaData *params = NULL);
@@ -71,6 +75,14 @@ private:
bool mCollectStats;
bool mStarted;
+ // Time between capture of two frames during time lapse recording
+ // Negative value indicates that timelapse is disabled.
+ int64_t mTimeBetweenTimeLapseFrameCaptureUs;
+ // Time between two frames in final video (1/frameRate)
+ int64_t mTimeBetweenTimeLapseVideoFramesUs;
+ // Real timestamp of the last encoded time lapse frame
+ int64_t mLastTimeLapseFrameRealTimestampUs;
+
CameraSource(const sp<Camera> &camera);
void dataCallbackTimestamp(
diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h
index 69ad837413be..194f1fc92529 100644
--- a/include/media/stagefright/foundation/ALooper.h
+++ b/include/media/stagefright/foundation/ALooper.h
@@ -39,7 +39,10 @@ struct ALooper : public RefBase {
handler_id registerHandler(const sp<AHandler> &handler);
void unregisterHandler(handler_id handlerID);
- status_t start(bool runOnCallingThread = false);
+ status_t start(
+ bool runOnCallingThread = false,
+ bool canCallJava = false);
+
status_t stop();
static int64_t GetNowUs();
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 139c6205529f..c674cbaf3471 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -60,6 +60,8 @@ struct AMessage : public RefBase {
sp<AMessage> dup() const;
+ AString debugString(int32_t indent = 0) const;
+
protected:
virtual ~AMessage();
diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h
index 4a3ca77571a5..56693dac736e 100644
--- a/libs/hwui/GenerationCache.h
+++ b/libs/hwui/GenerationCache.h
@@ -33,9 +33,13 @@ public:
template<typename K, typename V>
class GenerationCache {
public:
- GenerationCache(unsigned int maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
+ GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
~GenerationCache() { clear(); };
+ enum Capacity {
+ kUnlimitedCapacity,
+ };
+
void setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener);
void clear();
@@ -44,12 +48,11 @@ public:
V* get(K* key);
void put(K* key, V* value);
V* remove(K* key);
+ void removeOldest();
- unsigned int size() const;
+ uint32_t size() const;
private:
- void removeOldest();
-
template<typename EntryKey, typename EntryValue>
struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
Entry() { }
@@ -69,7 +72,7 @@ private:
void attachToCache(sp<Entry<K*, V*> > entry);
void detachFromCache(sp<Entry<K*, V*> > entry);
- unsigned int mMaxCapacity;
+ uint32_t mMaxCapacity;
OnEntryRemoved<K*, V*>* mListener;
@@ -80,7 +83,7 @@ private:
}; // class GenerationCache
template<typename K, typename V>
-unsigned int GenerationCache<K, V>::size() const {
+uint32_t GenerationCache<K, V>::size() const {
return mCache.size();
}
@@ -124,7 +127,7 @@ V* GenerationCache<K, V>::get(K* key) {
template<typename K, typename V>
void GenerationCache<K, V>::put(K* key, V* value) {
- if (mCache.size() >= mMaxCapacity) {
+ if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
removeOldest();
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 091abb058c9e..9df1c6765c50 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -22,6 +22,7 @@
#include <SkCanvas.h>
+#include <cutils/properties.h>
#include <utils/Log.h>
#include "OpenGLRenderer.h"
@@ -33,7 +34,15 @@ namespace uirenderer {
// Defines
///////////////////////////////////////////////////////////////////////////////
-#define MAX_TEXTURE_COUNT 128
+// These properties are defined in mega-bytes
+#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
+#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
+
+// Converts a number of mega-bytes into bytes
+#define MB(s) s * 1024 * 1024
+
+#define DEFAULT_TEXTURE_CACHE_SIZE MB(20)
+#define DEFAULT_LAYER_CACHE_SIZE MB(10)
#define SV(x, y) { { x, y } }
#define FV(x, y, u, v) { { x, y }, { u, v } }
@@ -83,9 +92,14 @@ static const Blender gBlends[] = {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-OpenGLRenderer::OpenGLRenderer(): mTextureCache(MAX_TEXTURE_COUNT) {
+OpenGLRenderer::OpenGLRenderer(): mTextureCache(DEFAULT_TEXTURE_CACHE_SIZE) {
LOGD("Create OpenGLRenderer");
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
+ mTextureCache.setMaxSize(MB(atoi(property)));
+ }
+
mDrawColorShader = new DrawColorProgram;
mDrawTextureShader = new DrawTextureProgram;
@@ -111,6 +125,7 @@ void OpenGLRenderer::setViewport(int width, int height) {
mWidth = width;
mHeight = height;
+ mFirstSnapshot.height = height;
}
void OpenGLRenderer::prepare() {
@@ -170,10 +185,15 @@ int OpenGLRenderer::saveSnapshot() {
bool OpenGLRenderer::restoreSnapshot() {
bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
+ bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
sp<Snapshot> current = mSnapshot;
sp<Snapshot> previous = mSnapshot->previous;
+ if (restoreOrtho) {
+ memcpy(mOrthoMatrix, current->orthoMatrix, sizeof(mOrthoMatrix));
+ }
+
if (restoreLayer) {
composeLayer(current, previous);
}
@@ -197,21 +217,11 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
// The texture is currently as big as the window but drawn with
// a quad of the appropriate size
const Rect& layer = current->layer;
- Rect texCoords(current->layer);
- mSnapshot->transform.mapRect(texCoords);
-
- const float u1 = texCoords.left / float(mWidth);
- const float v1 = (mHeight - texCoords.top) / float(mHeight);
- const float u2 = texCoords.right / float(mWidth);
- const float v2 = (mHeight - texCoords.bottom) / float(mHeight);
-
- resetDrawTextureTexCoords(u1, v1, u2, v2);
drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
current->texture, current->alpha, current->mode, true, true);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
-
+ // TODO Don't delete these things, but cache them
glDeleteFramebuffers(1, &current->fbo);
glDeleteTextures(1, &current->texture);
}
@@ -268,14 +278,10 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time
- // TODO ***** IMPORTANT *****
- // Creating a texture-backed FBO works only if the texture is the same size
- // as the original rendering buffer (in this case, mWidth and mHeight.)
- // This is expensive and wasteful and must be fixed.
- // TODO Additionally we should use an FBO cache
+ // TODO Use an FBO cache
- const GLsizei width = mWidth; //right - left;
- const GLsizei height = mHeight; //bottom - right;
+ const GLsizei width = right - left;
+ const GLsizei height = bottom - top;
const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
@@ -287,7 +293,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
- LOGD("Framebuffer incomplete %d", status);
+ LOGD("Framebuffer incomplete (GL error code 0x%x)", status);
glDeleteFramebuffers(1, &snapshot->fbo);
glDeleteTextures(1, &snapshot->texture);
@@ -295,11 +301,34 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return false;
}
+ // Clear the FBO
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_SCISSOR_TEST);
+
snapshot->flags |= Snapshot::kFlagIsLayer;
snapshot->mode = mode;
snapshot->alpha = alpha / 255.0f;
snapshot->layer.set(left, top, right, bottom);
+ // Creates a new snapshot to draw into the FBO
+ saveSnapshot();
+ // TODO: This doesn't preserve other transformations (check Skia first)
+ mSnapshot->transform.loadTranslate(-left, -top, 0.0f);
+ mSnapshot->clipRect.set(left, top, right, bottom);
+ mSnapshot->height = bottom - top;
+ setScissorFromClip();
+
+ mSnapshot->flags = Snapshot::kFlagDirtyTransform | Snapshot::kFlagDirtyOrtho |
+ Snapshot::kFlagClipSet;
+ memcpy(mSnapshot->orthoMatrix, mOrthoMatrix, sizeof(mOrthoMatrix));
+
+ // Change the ortho projection
+ mat4 ortho;
+ ortho.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
+ ortho.copyTo(mOrthoMatrix);
+
return true;
}
@@ -343,7 +372,7 @@ void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
void OpenGLRenderer::setScissorFromClip() {
const Rect& clip = mSnapshot->getMappedClip();
- glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
+ glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
}
const Rect& OpenGLRenderer::getClipBounds() {
@@ -381,7 +410,7 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
- Texture* texture = mTextureCache.get(bitmap);
+ const Texture* texture = mTextureCache.get(bitmap);
int alpha;
SkXfermode::Mode mode;
@@ -391,11 +420,26 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const S
alpha / 255.0f, mode, texture->blend, true);
}
+void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
+ Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
+ const mat4 transform(*matrix);
+ transform.mapRect(r);
+
+ const Texture* texture = mTextureCache.get(bitmap);
+
+ int alpha;
+ SkXfermode::Mode mode;
+ getAlphaAndMode(paint, &alpha, &mode);
+
+ drawTextureRect(r.left, r.top, r.right, r.bottom, texture->id,
+ alpha / 255.0f, mode, texture->blend, true);
+}
+
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkMatrix* matrix, const SkPaint* paint) {
- Texture* texture = mTextureCache.get(bitmap);
+ const SkPaint* paint) {
+ const Texture* texture = mTextureCache.get(bitmap);
int alpha;
SkXfermode::Mode mode;
@@ -411,8 +455,6 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
resetDrawTextureTexCoords(u1, v1, u2, v2);
- // TODO: implement Matrix
-
drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture->id,
alpha / 255.0f, mode, texture->blend, true);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index a698e7979d93..bd5f84fbf83b 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -103,9 +103,9 @@ public:
bool clipRect(float left, float top, float right, float bottom);
void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
+ void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkMatrix* matrix, const SkPaint* paint);
+ float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint);
void drawColor(int color, SkXfermode::Mode mode);
void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index ca91b3437af6..d1809f35e1e0 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -51,6 +51,7 @@ public:
* snapshot.
*/
Snapshot(const sp<Snapshot> s):
+ height(s->height),
transform(s->transform),
clipRect(s->clipRect),
flags(kFlagDirtyTransform),
@@ -80,6 +81,10 @@ public:
* a new layer.
*/
kFlagIsLayer = 0x4,
+ /**
+ * Indicates that this snapshot has changed the ortho matrix.
+ */
+ kFlagDirtyOrtho = 0x8,
};
/**
@@ -95,6 +100,11 @@ public:
}
/**
+ * Height of the framebuffer the snapshot is rendering into.
+ */
+ int height;
+
+ /**
* Local transformation. Holds the current translation, scale and
* rotation values.
*/
@@ -141,6 +151,11 @@ public:
*/
SkXfermode::Mode mode;
+ /**
+ * Contains the previous ortho matrix.
+ */
+ float orthoMatrix[16];
+
private:
// Clipping rectangle mapped with the transform
Rect mappedClip;
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 6802c59f973f..d37013d683ba 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -41,11 +41,11 @@ struct Texture {
/**
* Width of the backing bitmap.
*/
- unsigned int width;
+ uint32_t width;
/**
* Height of the backing bitmap.
*/
- unsigned int height;
+ uint32_t height;
}; // struct Texture
}; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 7b8b31398188..93ee138a373c 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "OpenGLRenderer"
+
#include <GLES2/gl2.h>
#include "TextureCache.h"
@@ -21,7 +23,13 @@
namespace android {
namespace uirenderer {
-TextureCache::TextureCache(unsigned int maxEntries): mCache(maxEntries) {
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+TextureCache::TextureCache(uint32_t maxByteSize):
+ mCache(GenerationCache<SkBitmap, Texture>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(maxByteSize) {
mCache.setOnEntryRemovedListener(this);
}
@@ -29,28 +37,71 @@ TextureCache::~TextureCache() {
mCache.clear();
}
-void TextureCache::operator()(SkBitmap* key, Texture* value) {
- LOGD("Entry removed");
- if (value) {
- glDeleteTextures(1, &value->id);
- delete value;
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t TextureCache::getSize() {
+ return mSize;
+}
+
+uint32_t TextureCache::getMaxSize() {
+ return mMaxSize;
+}
+
+void TextureCache::setMaxSize(uint32_t maxSize) {
+ mMaxSize = maxSize;
+ while (mSize > mMaxSize) {
+ mCache.removeOldest();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void TextureCache::operator()(SkBitmap* bitmap, Texture* texture) {
+ if (bitmap) {
+ const uint32_t size = bitmap->rowBytes() * bitmap->height();
+ mSize -= size;
+ }
+
+ if (texture) {
+ glDeleteTextures(1, &texture->id);
+ delete texture;
}
}
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
Texture* TextureCache::get(SkBitmap* bitmap) {
Texture* texture = mCache.get(bitmap);
if (!texture) {
+ const uint32_t size = bitmap->rowBytes() * bitmap->height();
+ // Don't even try to cache a bitmap that's bigger than the cache
+ if (size < mMaxSize) {
+ while (mSize + size > mMaxSize) {
+ mCache.removeOldest();
+ }
+ }
+
texture = new Texture;
generateTexture(bitmap, texture, false);
- mCache.put(bitmap, texture);
+
+ if (size < mMaxSize) {
+ mSize += size;
+ mCache.put(bitmap, texture);
+ }
} else if (bitmap->getGenerationID() != texture->generation) {
generateTexture(bitmap, texture, true);
}
return texture;
}
-Texture* TextureCache::remove(SkBitmap* bitmap) {
- return mCache.remove(bitmap);
+void TextureCache::remove(SkBitmap* bitmap) {
+ mCache.remove(bitmap);
}
void TextureCache::clear() {
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index bf680616c4f0..250efc56f60f 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -25,21 +25,63 @@
namespace android {
namespace uirenderer {
+/**
+ * A simple LRU texture cache. The cache has a maximum size expressed in bytes.
+ * Any texture added to the cache causing the cache to grow beyond the maximum
+ * allowed size will also cause the oldest texture to be kicked out.
+ */
class TextureCache: public OnEntryRemoved<SkBitmap*, Texture*> {
public:
- TextureCache(unsigned int maxEntries);
+ TextureCache(uint32_t maxByteSize);
~TextureCache();
- void operator()(SkBitmap* key, Texture* value);
+ /**
+ * Used as a callback when an entry is removed from the cache.
+ * Do not invoke directly.
+ */
+ void operator()(SkBitmap* bitmap, Texture* texture);
+ /**
+ * Returns the texture associated with the specified bitmap. If the texture
+ * cannot be found in the cache, a new texture is generated.
+ */
Texture* get(SkBitmap* bitmap);
- Texture* remove(SkBitmap* bitmap);
+ /**
+ * Removes the texture associated with the specified bitmap. Returns NULL
+ * if the texture cannot be found. Upon remove the texture is freed.
+ */
+ void remove(SkBitmap* bitmap);
+ /**
+ * Clears the cache. This causes all textures to be deleted.
+ */
void clear();
+ /**
+ * Sets the maximum size of the cache in bytes.
+ */
+ void setMaxSize(uint32_t maxSize);
+ /**
+ * Returns the maximum size of the cache in bytes.
+ */
+ uint32_t getMaxSize();
+ /**
+ * Returns the current size of the cache in bytes.
+ */
+ uint32_t getSize();
+
private:
+ /**
+ * Generates the texture from a bitmap into the specified texture structure.
+ *
+ * @param regenerate If true, the bitmap data is reuploaded into the texture, but
+ * no new texture is generated.
+ */
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
GenerationCache<SkBitmap, Texture> mCache;
+
+ uint32_t mSize;
+ uint32_t mMaxSize;
}; // class TextureCache
}; // namespace uirenderer
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 7afc4f24c59c..37c418bec7e9 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -102,7 +102,6 @@ LOCAL_SRC_FILES:= \
rsScriptC_LibGL.cpp \
rsShaderCache.cpp \
rsSignal.cpp \
- rsSimpleMesh.cpp \
rsStream.cpp \
rsThreadIO.cpp \
rsType.cpp \
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 14283183e970..8e6b5c67e3d8 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -38,7 +38,7 @@ typedef void * RsFile;
typedef void * RsFont;
typedef void * RsSampler;
typedef void * RsScript;
-typedef void * RsSimpleMesh;
+typedef void * RsMesh;
typedef void * RsType;
typedef void * RsLight;
typedef void * RsObjectBase;
@@ -229,7 +229,6 @@ enum RsAnimationEdge {
enum RsA3DClassID {
RS_A3D_CLASS_ID_UNKNOWN,
RS_A3D_CLASS_ID_MESH,
- RS_A3D_CLASS_ID_SIMPLE_MESH,
RS_A3D_CLASS_ID_TYPE,
RS_A3D_CLASS_ID_ELEMENT,
RS_A3D_CLASS_ID_ALLOCATION,
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
index 144e5392a1d0..92259041b73f 100644
--- a/libs/rs/RenderScriptEnv.h
+++ b/libs/rs/RenderScriptEnv.h
@@ -9,7 +9,7 @@ typedef void * RsDevice;
typedef void * RsElement;
typedef void * RsSampler;
typedef void * RsScript;
-typedef void * RsSimpleMesh;
+typedef void * RsMesh;
typedef void * RsType;
typedef void * RsProgramFragment;
typedef void * RsProgramStore;
diff --git a/libs/rs/java/Fountain/res/raw/fountain.rs b/libs/rs/java/Fountain/res/raw/fountain.rs
index ef12d9accb8d..c8c10cd0388f 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.rs
+++ b/libs/rs/java/Fountain/res/raw/fountain.rs
@@ -8,7 +8,6 @@
#include "../../../../scriptc/rs_graphics.rsh"
static int newPart = 0;
-static float4 partColor;
rs_mesh partMesh;
typedef struct __attribute__((packed, aligned(4))) Point {
@@ -36,20 +35,21 @@ int root() {
p++;
}
- rsgDrawSimpleMesh(partMesh);
+ rsgDrawMesh(partMesh);
return 1;
}
-void addParticles(int rate, float x, float y, bool newColor)
+static float4 partColor[10];
+void addParticles(int rate, float x, float y, int index, bool newColor)
{
if (newColor) {
- partColor.x = rsRand(0.5f, 1.0f);
- partColor.y = rsRand(1.0f);
- partColor.z = rsRand(1.0f);
+ partColor[index].x = rsRand(0.5f, 1.0f);
+ partColor[index].y = rsRand(1.0f);
+ partColor[index].z = rsRand(1.0f);
}
- float rMax = ((float)rate) * 0.005f;
+ float rMax = ((float)rate) * 0.02f;
int size = rsAllocationGetDimX(rsGetAllocation(point));
- uchar4 c = rsPackColorTo8888(partColor);
+ uchar4 c = rsPackColorTo8888(partColor[index]);
Point_t * np = &point[newPart];
float2 p = {x, y};
diff --git a/libs/rs/java/Fountain/res/raw/fountain_bc.bc b/libs/rs/java/Fountain/res/raw/fountain_bc.bc
index ac6b7d4e5b0d..2c8ce8b9c6fb 100644
--- a/libs/rs/java/Fountain/res/raw/fountain_bc.bc
+++ b/libs/rs/java/Fountain/res/raw/fountain_bc.bc
Binary files differ
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index ffe2fad97c3a..cfe8e27aeecb 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -36,11 +36,10 @@ public class FountainRS {
ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
- SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
- int vtxSlot = smb.addVertexType(points.getType());
- smb.setPrimitive(Primitive.POINT);
- SimpleMesh sm = smb.create();
- sm.bindVertexAllocation(points.getAllocation(), vtxSlot);
+ Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+ smb.addVertexAllocation(points.getAllocation());
+ smb.addIndexType(Primitive.POINT);
+ Mesh sm = smb.create();
mScript = new ScriptC_Fountain(mRS, mRes, R.raw.fountain_bc, true);
mScript.set_partMesh(sm);
@@ -48,13 +47,20 @@ public class FountainRS {
mRS.contextBindRootScript(mScript);
}
- boolean holdingColor = false;
- public void newTouchPosition(int x, int y, int rate) {
+ boolean holdingColor[] = new boolean[10];
+ public void newTouchPosition(float x, float y, float pressure, int id) {
+ if (id > holdingColor.length) {
+ return;
+ }
+ int rate = (int)(pressure * pressure * 500.f);
+ if(rate > 500) {
+ rate = 500;
+ }
if (rate > 0) {
- mScript.invoke_addParticles(rate, x, y, !holdingColor);
- holdingColor = true;
+ mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
+ holdingColor[id] = true;
} else {
- holdingColor = false;
+ holdingColor[id] = false;
}
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
index dfd6a49d09a1..6082c1e878a7 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -73,15 +73,27 @@ public class FountainView extends RSSurfaceView {
{
int act = ev.getAction();
if (act == ev.ACTION_UP) {
- mRender.newTouchPosition(0, 0, 0);
+ mRender.newTouchPosition(0, 0, 0, 0);
return false;
}
- float rate = (ev.getPressure() * 50.f);
- rate *= rate;
- if(rate > 2000.f) {
- rate = 2000.f;
+
+ int count = ev.getHistorySize();
+ int pcount = ev.getPointerCount();
+
+ for (int p=0; p < pcount; p++) {
+ int id = ev.getPointerId(p);
+ mRender.newTouchPosition(ev.getX(p),
+ ev.getY(p),
+ ev.getPressure(p),
+ id);
+
+ for (int i=0; i < count; i++) {
+ mRender.newTouchPosition(ev.getHistoricalX(p, i),
+ ev.getHistoricalY(p, i),
+ ev.getHistoricalPressure(p, i),
+ id);
+ }
}
- mRender.newTouchPosition((int)ev.getX(), (int)ev.getY(), (int)rate);
return true;
}
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java b/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
index a4c598be46e1..0ec00096f525 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/ScriptC_Fountain.java
@@ -27,13 +27,13 @@ public class ScriptC_Fountain extends ScriptC {
}
private final static int mExportVarIdx_partMesh = 0;
- private SimpleMesh mExportVar_partMesh;
- public void set_partMesh(SimpleMesh v) {
+ private Mesh mExportVar_partMesh;
+ public void set_partMesh(Mesh v) {
mExportVar_partMesh = v;
setVar(mExportVarIdx_partMesh, (v == null) ? 0 : v.getID());
}
- public SimpleMesh get_partMesh() {
+ public Mesh get_partMesh() {
return mExportVar_partMesh;
}
@@ -50,11 +50,12 @@ public class ScriptC_Fountain extends ScriptC {
}
private final static int mExportFuncIdx_addParticles = 0;
- public void invoke_addParticles(int rate, float x, float y, boolean newColor) {
- FieldPacker addParticles_fp = new FieldPacker(16);
+ public void invoke_addParticles(int rate, float x, float y, int index, boolean newColor) {
+ FieldPacker addParticles_fp = new FieldPacker(20);
addParticles_fp.addI32(rate);
addParticles_fp.addF32(x);
addParticles_fp.addF32(y);
+ addParticles_fp.addI32(index);
addParticles_fp.addBoolean(newColor);
addParticles_fp.skip(3);
invoke(mExportFuncIdx_addParticles, addParticles_fp);
diff --git a/libs/rs/java/ModelViewer/res/raw/modelviewer.rs b/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
index 91194e827912..559bf4856472 100644
--- a/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
+++ b/libs/rs/java/ModelViewer/res/raw/modelviewer.rs
@@ -62,7 +62,7 @@ int root(int launchID) {
rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
rsgProgramVertexLoadModelMatrix(&matrix);
- rsgDrawSimpleMesh(gTestMesh);
+ rsgDrawMesh(gTestMesh);
color(0.3f, 0.3f, 0.3f, 1.0f);
rsgDrawText("Renderscript model test", 30, 695);
diff --git a/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc b/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
index a64e7258b50b..fb8502860f72 100644
--- a/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
+++ b/libs/rs/java/ModelViewer/res/raw/modelviewer_bc.bc
Binary files differ
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d
index c0c66aed5e56..430fe950ffd6 100644
--- a/libs/rs/java/ModelViewer/res/raw/robot.a3d
+++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
index b6485dcdfbb5..37eb9c18fa19 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ModelViewerRS.java
@@ -55,7 +55,7 @@ public class ModelViewerRS {
private Allocation mGridImage;
private Allocation mAllocPV;
- private SimpleMesh mMesh;
+ private Mesh mMesh;
private Font mItalic;
private Allocation mTextAlloc;
@@ -149,15 +149,15 @@ public class ModelViewerRS {
FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
FileA3D.IndexEntry entry = model.getIndexEntry(0);
- if(entry == null || entry.getClassID() != FileA3D.ClassID.SIMPLE_MESH) {
+ if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) {
Log.e("rs", "could not load model");
}
else {
- mMesh = (SimpleMesh)entry.getObject();
+ mMesh = (Mesh)entry.getObject();
mScript.set_gTestMesh(mMesh);
}
- mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 10);
+ mItalic = Font.create(mRS, mRes, "DroidSerif-Italic.ttf", 8);
mScript.set_gItalic(mItalic);
initTextAllocation();
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
index d3a2a292e7d6..06c10ab22efb 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/ScriptC_Modelviewer.java
@@ -60,13 +60,13 @@ public class ScriptC_Modelviewer extends ScriptC {
}
private final static int mExportVarIdx_gTestMesh = 3;
- private SimpleMesh mExportVar_gTestMesh;
- public void set_gTestMesh(SimpleMesh v) {
+ private Mesh mExportVar_gTestMesh;
+ public void set_gTestMesh(Mesh v) {
mExportVar_gTestMesh = v;
setVar(mExportVarIdx_gTestMesh, (v == null) ? 0 : v.getID());
}
- public SimpleMesh get_gTestMesh() {
+ public Mesh get_gTestMesh() {
return mExportVar_gTestMesh;
}
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 3694b6590f7e..172ba661df17 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -478,8 +478,34 @@ FontCreateFromFile {
ret RsFont
}
+MeshCreate {
+ ret RsMesh
+ param uint32_t vtxCount
+ param uint32_t idxCount
+ }
+
+MeshBindIndex {
+ param RsMesh mesh
+ param RsAllocation idx
+ param uint32_t primType
+ param uint32_t slot
+ }
+
+MeshBindPrimitive {
+ param RsMesh mesh
+ param RsAllocation prim
+ param uint32_t primType
+ param uint32_t slot
+ }
+
+MeshBindVertex {
+ param RsMesh mesh
+ param RsAllocation vtx
+ param uint32_t slot
+ }
+
SimpleMeshCreate {
- ret RsSimpleMesh
+ ret RsMesh
param RsAllocation prim
param RsAllocation index
param RsAllocation *vtx
@@ -489,17 +515,17 @@ SimpleMeshCreate {
SimpleMeshBindIndex {
- param RsSimpleMesh mesh
+ param RsMesh mesh
param RsAllocation idx
}
SimpleMeshBindPrimitive {
- param RsSimpleMesh mesh
+ param RsMesh mesh
param RsAllocation prim
}
SimpleMeshBindVertex {
- param RsSimpleMesh mesh
+ param RsMesh mesh
param RsAllocation vtx
param uint32_t slot
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 73f478adb357..06433a17f149 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -24,7 +24,6 @@
#include "rsType.h"
#include "rsMatrix.h"
#include "rsAllocation.h"
-#include "rsSimpleMesh.h"
#include "rsMesh.h"
#include "rsDevice.h"
#include "rsScriptC.h"
diff --git a/libs/rs/rsContextHostStub.h b/libs/rs/rsContextHostStub.h
index be1fff6dd071..c437606cdb48 100644
--- a/libs/rs/rsContextHostStub.h
+++ b/libs/rs/rsContextHostStub.h
@@ -24,7 +24,6 @@
#include "rsType.h"
#include "rsMatrix.h"
#include "rsAllocation.h"
-#include "rsSimpleMesh.h"
#include "rsMesh.h"
//#include "rsDevice.h"
#include "rsScriptC.h"
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
index 4fac421e4da0..5709f2a8e79d 100644
--- a/libs/rs/rsFileA3D.cpp
+++ b/libs/rs/rsFileA3D.cpp
@@ -258,9 +258,6 @@ ObjectBase *FileA3D::initializeFromEntry(size_t index) {
case RS_A3D_CLASS_ID_MESH:
entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream);
break;
- case RS_A3D_CLASS_ID_SIMPLE_MESH:
- entry->mRsObj = SimpleMesh::createFromStream(mRSC, mReadStream);
- break;
case RS_A3D_CLASS_ID_TYPE:
entry->mRsObj = Type::createFromStream(mRSC, mReadStream);
break;
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index bd9cd275999c..4f90f36b1c40 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -35,43 +35,138 @@ Mesh::Mesh(Context *rsc) : ObjectBase(rsc)
{
mAllocFile = __FILE__;
mAllocLine = __LINE__;
- mVerticies = NULL;
- mVerticiesCount = 0;
mPrimitives = NULL;
mPrimitivesCount = 0;
+ mVertexBuffers = NULL;
+ mVertexTypes = NULL;
+ mVertexBufferCount = 0;
}
Mesh::~Mesh()
{
+ if(mVertexTypes) {
+ delete[] mVertexTypes;
+ }
+
+ if(mVertexBuffers) {
+ delete[] mVertexBuffers;
+ }
+
+ if(mPrimitives) {
+ for(uint32_t i = 0; i < mPrimitivesCount; i ++) {
+ delete mPrimitives[i];
+ }
+ delete[] mPrimitives;
+ }
}
-void Mesh::serialize(OStream *stream) const
+void Mesh::render(Context *rsc) const
{
- // Need to identify ourselves
- stream->addU32((uint32_t)getClassId());
+ for(uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+ renderPrimitive(rsc, ct);
+ }
+}
- String8 name(getName());
- stream->addString(&name);
+void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
+ if (primIndex >= mPrimitivesCount) {
+ LOGE("Invalid primitive index");
+ return;
+ }
- stream->addU32(mVerticiesCount);
+ Primitive_t *prim = mPrimitives[primIndex];
- for(uint32_t vCount = 0; vCount < mVerticiesCount; vCount ++) {
- Verticies_t *verts = mVerticies[vCount];
+ if (prim->mIndexBuffer.get()) {
+ renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX());
+ return;
+ }
- stream->addU32(verts->mAllocationCount);
+ if (prim->mPrimitiveBuffer.get()) {
+ renderPrimitiveRange(rsc, primIndex, 0, prim->mPrimitiveBuffer->getType()->getDimX());
+ return;
+ }
+
+ renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX());
+}
- for (uint32_t aCount = 0; aCount < verts->mAllocationCount; aCount++) {
- verts->mAllocations[aCount]->serialize(stream);
+void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const
+{
+ if (len < 1 || primIndex >= mPrimitivesCount) {
+ return;
+ }
+
+ rsc->checkError("Mesh::renderPrimitiveRange 1");
+ VertexArray va;
+ for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
+ mVertexBuffers[ct]->uploadCheck(rsc);
+ if (mVertexBuffers[ct]->getIsBufferObject()) {
+ va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
+ } else {
+ va.setActiveBuffer(mVertexBuffers[ct]->getPtr());
}
- stream->addU32(verts->mVertexDataSize);
+ mVertexBuffers[ct]->getType()->enableGLVertexBuffer(&va);
+ }
+ va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+
+ rsc->checkError("Mesh::renderPrimitiveRange 2");
+ Primitive_t *prim = mPrimitives[primIndex];
+ if (prim->mIndexBuffer.get()) {
+ prim->mIndexBuffer->uploadCheck(rsc);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
+ glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+ } else {
+ glDrawArrays(prim->mGLPrimitive, start, len);
+ }
+
+ rsc->checkError("Mesh::renderPrimitiveRange");
+}
- stream->addU32(verts->mOffsetCoord);
- stream->addU32(verts->mOffsetTex);
- stream->addU32(verts->mOffsetNorm);
- stream->addU32(verts->mSizeCoord);
- stream->addU32(verts->mSizeTex);
- stream->addU32(verts->mSizeNorm );
+void Mesh::uploadAll(Context *rsc)
+{
+ for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) {
+ if (mVertexBuffers[ct].get()) {
+ mVertexBuffers[ct]->deferedUploadToBufferObject(rsc);
+ }
+ }
+
+ for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+ if (mPrimitives[ct]->mIndexBuffer.get()) {
+ mPrimitives[ct]->mIndexBuffer->deferedUploadToBufferObject(rsc);
+ }
+ if (mPrimitives[ct]->mPrimitiveBuffer.get()) {
+ mPrimitives[ct]->mPrimitiveBuffer->deferedUploadToBufferObject(rsc);
+ }
+ }
+
+ rsc->checkError("Mesh::uploadAll");
+}
+
+void Mesh::updateGLPrimitives()
+{
+ for(uint32_t i = 0; i < mPrimitivesCount; i ++) {
+ switch(mPrimitives[i]->mPrimitive) {
+ case RS_PRIMITIVE_POINT: mPrimitives[i]->mGLPrimitive = GL_POINTS; break;
+ case RS_PRIMITIVE_LINE: mPrimitives[i]->mGLPrimitive = GL_LINES; break;
+ case RS_PRIMITIVE_LINE_STRIP: mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE: mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break;
+ case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE_FAN: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break;
+ }
+ }
+}
+
+void Mesh::serialize(OStream *stream) const
+{
+ // Need to identify ourselves
+ stream->addU32((uint32_t)getClassId());
+
+ String8 name(getName());
+ stream->addString(&name);
+
+ // Store number of vertex streams
+ stream->addU32(mVertexBufferCount);
+ for(uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) {
+ mVertexBuffers[vCount]->serialize(stream);
}
stream->addU32(mPrimitivesCount);
@@ -79,27 +174,22 @@ void Mesh::serialize(OStream *stream) const
for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
Primitive_t * prim = mPrimitives[pCount];
- stream->addU8((uint8_t)prim->mType);
+ stream->addU8((uint8_t)prim->mPrimitive);
- // We store the index to the vertices
- // So iterate over our vertices to find which one we point to
- uint32_t vertexIndex = 0;
- for(uint32_t vCount = 0; vCount < mVerticiesCount; vCount ++) {
- if(prim->mVerticies == mVerticies[vCount]) {
- vertexIndex = vCount;
- break;
- }
+ if(prim->mIndexBuffer.get()) {
+ stream->addU32(1);
+ prim->mIndexBuffer->serialize(stream);
}
- stream->addU32(vertexIndex);
-
- stream->addU32(prim->mIndexCount);
- for (uint32_t ct = 0; ct < prim->mIndexCount; ct++) {
- stream->addU16(prim->mIndicies[ct]);
+ else {
+ stream->addU32(0);
}
- stream->addU32(prim->mRestartCounts);
- for (uint32_t ct = 0; ct < prim->mRestartCounts; ct++) {
- stream->addU16(prim->mRestarts[ct]);
+ if(prim->mPrimitiveBuffer.get()) {
+ stream->addU32(1);
+ prim->mPrimitiveBuffer->serialize(stream);
+ }
+ else {
+ stream->addU32(0);
}
}
}
@@ -119,86 +209,46 @@ Mesh *Mesh::createFromStream(Context *rsc, IStream *stream)
stream->loadString(&name);
mesh->setName(name.string(), name.size());
- mesh->mVerticiesCount = stream->loadU32();
- if(mesh->mVerticiesCount) {
- mesh->mVerticies = new Verticies_t *[mesh->mVerticiesCount];
- }
- else {
- mesh->mVerticies = NULL;
- }
-
- for(uint32_t vCount = 0; vCount < mesh->mVerticiesCount; vCount ++) {
- Verticies_t *verts = new Verticies_t();
- // Store our vertices one the mesh
- mesh->mVerticies[vCount] = verts;
-
- verts->mAllocationCount = stream->loadU32();
- verts->mAllocations = new Allocation *[verts->mAllocationCount];
+ mesh->mVertexBufferCount = stream->loadU32();
+ if(mesh->mVertexBufferCount) {
+ mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount];
- LOGE("processChunk_Verticies count %i", verts->mAllocationCount);
- for (uint32_t aCount = 0; aCount < verts->mAllocationCount; aCount++) {
- verts->mAllocations[aCount] = Allocation::createFromStream(rsc, stream);
+ for(uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) {
+ Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
+ mesh->mVertexBuffers[vCount].set(vertexAlloc);
}
- verts->mVertexDataSize = stream->loadU32();
-
- verts->mOffsetCoord = stream->loadU32();
- verts->mOffsetTex = stream->loadU32();
- verts->mOffsetNorm = stream->loadU32();
-
- verts->mSizeCoord = stream->loadU32();
- verts->mSizeTex = stream->loadU32();
- verts->mSizeNorm = stream->loadU32();
}
mesh->mPrimitivesCount = stream->loadU32();
if(mesh->mPrimitivesCount) {
mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
- }
- else {
- mesh->mPrimitives = NULL;
- }
- // load all primitives
- for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
- Primitive_t * prim = new Primitive_t;
- mesh->mPrimitives[pCount] = prim;
+ // load all primitives
+ for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
+ Primitive_t * prim = new Primitive_t;
+ mesh->mPrimitives[pCount] = prim;
- prim->mType = (RsPrimitive)stream->loadU8();
-
- // We store the index to the vertices
- uint32_t vertexIndex = stream->loadU32();
- if(vertexIndex < mesh->mVerticiesCount) {
- prim->mVerticies = mesh->mVerticies[vertexIndex];
- }
- else {
- prim->mVerticies = NULL;
- }
+ prim->mPrimitive = (RsPrimitive)stream->loadU8();
- prim->mIndexCount = stream->loadU32();
- if(prim->mIndexCount){
- prim->mIndicies = new uint16_t[prim->mIndexCount];
- for (uint32_t ct = 0; ct < prim->mIndexCount; ct++) {
- prim->mIndicies[ct] = stream->loadU16();
+ // Check to see if the index buffer was stored
+ uint32_t isIndexPresent = stream->loadU32();
+ if(isIndexPresent) {
+ Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
+ prim->mIndexBuffer.set(indexAlloc);
}
- }
- else {
- prim->mIndicies = NULL;
- }
-
- prim->mRestartCounts = stream->loadU32();
- if (prim->mRestartCounts) {
- prim->mRestarts = new uint16_t[prim->mRestartCounts];
- for (uint32_t ct = 0; ct < prim->mRestartCounts; ct++) {
- prim->mRestarts[ct] = stream->loadU16();
+ // Check to see if the primitive buffer was stored
+ uint32_t isPrimitivePresent = stream->loadU32();
+ if(isPrimitivePresent) {
+ Allocation *primitiveAlloc = Allocation::createFromStream(rsc, stream);
+ prim->mPrimitiveBuffer.set(primitiveAlloc);
}
}
- else {
- prim->mRestarts = NULL;
- }
-
}
+ mesh->updateGLPrimitives();
+ mesh->uploadAll(rsc);
+
return mesh;
}
@@ -211,3 +261,103 @@ MeshContext::~MeshContext()
{
}
+namespace android {
+namespace renderscript {
+
+RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount)
+{
+ Mesh *sm = new Mesh(rsc);
+ sm->incUserRef();
+
+ sm->mPrimitivesCount = idxCount;
+ sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
+ for(uint32_t ct = 0; ct < idxCount; ct ++) {
+ sm->mPrimitives[ct] = new Mesh::Primitive_t;
+ }
+
+ sm->mVertexBufferCount = vtxCount;
+ sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+ sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+
+ return sm;
+}
+
+void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot)
+{
+ Mesh *sm = static_cast<Mesh *>(mv);
+ rsAssert(slot < sm->mVertexBufferCount);
+
+ sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot)
+{
+ Mesh *sm = static_cast<Mesh *>(mv);
+ rsAssert(slot < sm->mPrimitivesCount);
+
+ sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va);
+ sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
+ sm->updateGLPrimitives();
+}
+
+void rsi_MeshBindPrimitive(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot)
+{
+ Mesh *sm = static_cast<Mesh *>(mv);
+ rsAssert(slot < sm->mPrimitivesCount);
+
+ sm->mPrimitives[slot]->mPrimitiveBuffer.set((Allocation *)va);
+ sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
+ sm->updateGLPrimitives();
+}
+
+
+// Route all the simple mesh through mesh
+
+RsMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
+{
+ Mesh *sm = new Mesh(rsc);
+ sm->incUserRef();
+
+ sm->mPrimitivesCount = 1;
+ sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
+ sm->mPrimitives[0] = new Mesh::Primitive_t;
+
+ sm->mPrimitives[0]->mIndexType.set((const Type *)idx);
+ sm->mPrimitives[0]->mPrimitiveType.set((const Type *)prim);
+ sm->mPrimitives[0]->mPrimitive = (RsPrimitive)primType;
+ sm->updateGLPrimitives();
+
+ sm->mVertexBufferCount = vtxCount;
+ sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+ sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+ for (uint32_t ct=0; ct < vtxCount; ct++) {
+ sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
+ }
+
+ return sm;
+}
+
+void rsi_SimpleMeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot)
+{
+ Mesh *sm = static_cast<Mesh *>(mv);
+ rsAssert(slot < sm->mVertexBufferCount);
+
+ sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va)
+{
+ Mesh *sm = static_cast<Mesh *>(mv);
+ sm->mPrimitives[0]->mIndexBuffer.set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindPrimitive(Context *rsc, RsMesh mv, RsAllocation va)
+{
+ Mesh *sm = static_cast<Mesh *>(mv);
+ sm->mPrimitives[0]->mPrimitiveBuffer.set((Allocation *)va);
+}
+
+
+
+
+}}
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 8c7e8a4427c6..66174b725581 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -32,43 +32,35 @@ public:
Mesh(Context *);
~Mesh();
- struct Verticies_t
- {
- Allocation ** mAllocations;
- uint32_t mAllocationCount;
-
- size_t mVertexDataSize;
-
- size_t mOffsetCoord;
- size_t mOffsetTex;
- size_t mOffsetNorm;
-
- size_t mSizeCoord;
- size_t mSizeTex;
- size_t mSizeNorm;
-
- uint32_t mBufferObject;
- };
-
+ // Contains vertex data
+ // Position, normal, texcoord, etc could either be strided in one allocation
+ // of provided separetely in multiple ones
+ ObjectBaseRef<Allocation> *mVertexBuffers;
+ ObjectBaseRef<const Type> *mVertexTypes;
+ uint32_t mVertexBufferCount;
+
+ // Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference
+ // If both are null, mPrimitive only would be used to render the mesh
struct Primitive_t
{
- RsPrimitive mType;
- Verticies_t *mVerticies;
-
- uint32_t mIndexCount;
- uint16_t *mIndicies;
+ ObjectBaseRef<Allocation> mIndexBuffer;
+ ObjectBaseRef<Allocation> mPrimitiveBuffer;
+ ObjectBaseRef<const Type> mIndexType;
+ ObjectBaseRef<const Type> mPrimitiveType;
- uint32_t mRestartCounts;
- uint16_t *mRestarts;
+ RsPrimitive mPrimitive;
+ uint32_t mGLPrimitive;
};
- Verticies_t ** mVerticies;
- uint32_t mVerticiesCount;
-
Primitive_t ** mPrimitives;
uint32_t mPrimitivesCount;
- void analyzeElement();
+ void render(Context *) const;
+ void renderPrimitive(Context *, uint32_t primIndex) const;
+ void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+ void uploadAll(Context *);
+ void updateGLPrimitives();
+
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
static Mesh *createFromStream(Context *rsc, IStream *stream);
@@ -90,3 +82,4 @@ public:
#endif //ANDROID_RS_TRIANGLE_MESH_H
+
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index dbd398e34c42..7185009b7a34 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -43,10 +43,10 @@ using namespace android::renderscript;
// IO routines
//////////////////////////////////////////////////////////////////////////////
-static void SC_updateSimpleMesh(RsSimpleMesh mesh)
+static void SC_updateSimpleMesh(RsMesh mesh)
{
GET_TLS();
- SimpleMesh *sm = static_cast<SimpleMesh *>(mesh);
+ Mesh *sm = static_cast<Mesh *>(mesh);
sm->uploadAll(rsc);
}
@@ -220,24 +220,54 @@ static void SC_drawRect(float x1, float y1,
x1, y1, z);
}
-static void SC_drawSimpleMesh(RsSimpleMesh vsm)
+static void SC_drawSimpleMesh(RsMesh vsm)
{
GET_TLS();
- SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ Mesh *sm = static_cast<Mesh *>(vsm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->renderPrimitive(rsc, 0);
+}
+
+static void SC_drawSimpleMeshRange(RsMesh vsm, uint32_t start, uint32_t len)
+{
+ GET_TLS();
+ Mesh *sm = static_cast<Mesh *>(vsm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->renderPrimitiveRange(rsc, 0, start, len);
+}
+
+static void SC_drawMesh(RsMesh vsm)
+{
+ GET_TLS();
+ Mesh *sm = static_cast<Mesh *>(vsm);
if (!rsc->setupCheck()) {
return;
}
sm->render(rsc);
}
-static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
+static void SC_drawMeshPrimitive(RsMesh vsm, uint32_t primIndex)
{
GET_TLS();
- SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ Mesh *sm = static_cast<Mesh *>(vsm);
if (!rsc->setupCheck()) {
return;
}
- sm->renderRange(rsc, start, len);
+ sm->renderPrimitive(rsc, primIndex);
+}
+
+static void SC_drawMeshPrimitiveRange(RsMesh vsm, uint32_t primIndex, uint32_t start, uint32_t len)
+{
+ GET_TLS();
+ Mesh *sm = static_cast<Mesh *>(vsm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->renderPrimitiveRange(rsc, primIndex, start, len);
}
@@ -375,6 +405,10 @@ static ScriptCState::SymbolTable_t gSyms[] = {
{ "_Z17rsgDrawSimpleMesh7rs_mesh", (void *)&SC_drawSimpleMesh },
{ "_Z17rsgDrawSimpleMesh7rs_meshii", (void *)&SC_drawSimpleMeshRange },
+ { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh },
+ { "_Z11rsgDrawMesh7rs_meshi", (void *)&SC_drawMeshPrimitive },
+ { "_Z11rsgDrawMesh7rs_meshiii", (void *)&SC_drawMeshPrimitiveRange },
+
{ "rsgClearColor", (void *)&SC_ClearColor },
{ "rsgClearDepth", (void *)&SC_ClearDepth },
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
deleted file mode 100644
index e5c2eb5afa19..000000000000
--- a/libs/rs/rsSimpleMesh.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RS_BUILD_FOR_HOST
-#include "rsContext.h"
-
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#include <GLES/glext.h>
-#else
-#include "rsContextHostStub.h"
-
-#include <OpenGL/gl.h>
-#include <OpenGl/glext.h>
-#endif
-
-using namespace android;
-using namespace android::renderscript;
-
-
-
-
-SimpleMesh::SimpleMesh(Context *rsc) : ObjectBase(rsc)
-{
- mAllocFile = __FILE__;
- mAllocLine = __LINE__;
-}
-
-SimpleMesh::~SimpleMesh()
-{
- delete[] mVertexTypes;
- delete[] mVertexBuffers;
-}
-
-void SimpleMesh::render(Context *rsc) const
-{
- if (mPrimitiveType.get()) {
- renderRange(rsc, 0, mPrimitiveType->getDimX());
- return;
- }
-
- if (mIndexType.get()) {
- renderRange(rsc, 0, mIndexType->getDimX());
- return;
- }
-
- renderRange(rsc, 0, mVertexTypes[0]->getDimX());
-}
-
-void SimpleMesh::renderRange(Context *rsc, uint32_t start, uint32_t len) const
-{
- if (len < 1) {
- return;
- }
-
- rsc->checkError("SimpleMesh::renderRange 1");
- VertexArray va;
- for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
- mVertexBuffers[ct]->uploadCheck(rsc);
- if (mVertexBuffers[ct]->getIsBufferObject()) {
- va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID());
- } else {
- va.setActiveBuffer(mVertexBuffers[ct]->getPtr());
- }
- mVertexTypes[ct]->enableGLVertexBuffer(&va);
- }
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-
- rsc->checkError("SimpleMesh::renderRange 2");
- if (mIndexType.get()) {
- mIndexBuffer->uploadCheck(rsc);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
- glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
- } else {
- glDrawArrays(mGLPrimitive, start, len);
- }
-
- rsc->checkError("SimpleMesh::renderRange");
-}
-
-void SimpleMesh::uploadAll(Context *rsc)
-{
- for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
- if (mVertexBuffers[ct].get()) {
- mVertexBuffers[ct]->deferedUploadToBufferObject(rsc);
- }
- }
- if (mIndexBuffer.get()) {
- mIndexBuffer->deferedUploadToBufferObject(rsc);
- }
- if (mPrimitiveBuffer.get()) {
- mPrimitiveBuffer->deferedUploadToBufferObject(rsc);
- }
- rsc->checkError("SimpleMesh::uploadAll");
-}
-
-void SimpleMesh::updateGLPrimitive()
-{
- switch(mPrimitive) {
- case RS_PRIMITIVE_POINT: mGLPrimitive = GL_POINTS; break;
- case RS_PRIMITIVE_LINE: mGLPrimitive = GL_LINES; break;
- case RS_PRIMITIVE_LINE_STRIP: mGLPrimitive = GL_LINE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE: mGLPrimitive = GL_TRIANGLES; break;
- case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitive = GL_TRIANGLE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitive = GL_TRIANGLE_FAN; break;
- }
-}
-
-void SimpleMesh::serialize(OStream *stream) const
-{
- // Need to identify ourselves
- stream->addU32((uint32_t)getClassId());
-
- String8 name(getName());
- stream->addString(&name);
-
- // Add primitive type
- stream->addU8((uint8_t)mPrimitive);
-
- // And now serialize the allocations
- mIndexBuffer->serialize(stream);
-
- // We need to indicate if the primitive buffer is present
- if(mPrimitiveBuffer.get() != NULL) {
- // Write if the primitive buffer is present
- stream->addU32(1);
- mPrimitiveBuffer->serialize(stream);
- }
- else {
- // No buffer present, will need this when we read
- stream->addU32(0);
- }
-
- // Store number of vertex streams
- stream->addU32(mVertexTypeCount);
- for(uint32_t vCount = 0; vCount < mVertexTypeCount; vCount ++) {
- mVertexBuffers[vCount]->serialize(stream);
- }
-}
-
-SimpleMesh *SimpleMesh::createFromStream(Context *rsc, IStream *stream)
-{
- // First make sure we are reading the correct object
- RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
- if(classID != RS_A3D_CLASS_ID_SIMPLE_MESH) {
- LOGE("simple mesh loading skipped due to invalid class id");
- return NULL;
- }
-
- SimpleMesh * mesh = new SimpleMesh(rsc);
-
- String8 name;
- stream->loadString(&name);
- mesh->setName(name.string(), name.size());
-
- mesh->mPrimitive = (RsPrimitive)stream->loadU8();
- mesh->updateGLPrimitive();
-
- Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
- const Type *indexType = indexAlloc->getType();
- mesh->mIndexBuffer.set(indexAlloc);
- mesh->mIndexType.set(indexType);
-
- bool isPrimitivePresent = stream->loadU32() != 0;
- if(isPrimitivePresent) {
- mesh->mPrimitiveBuffer.set(Allocation::createFromStream(rsc, stream));
- mesh->mPrimitiveType.set(mesh->mPrimitiveBuffer->getType());
- }
-
- mesh->mVertexTypeCount = stream->loadU32();
- if(mesh->mVertexTypeCount) {
- mesh->mVertexTypes = new ObjectBaseRef<const Type>[mesh->mVertexTypeCount];
- mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexTypeCount];
-
- for(uint32_t vCount = 0; vCount < mesh->mVertexTypeCount; vCount ++) {
- Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
- const Type *vertexType = vertexAlloc->getType();
- mesh->mVertexBuffers[vCount].set(vertexAlloc);
- mesh->mVertexTypes[vCount].set(vertexType);
- }
- }
-
- mesh->uploadAll(rsc);
-
- return mesh;
-}
-
-
-SimpleMeshContext::SimpleMeshContext()
-{
-}
-
-SimpleMeshContext::~SimpleMeshContext()
-{
-}
-
-
-namespace android {
-namespace renderscript {
-
-
-RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
-{
- SimpleMesh *sm = new SimpleMesh(rsc);
- sm->incUserRef();
-
- sm->mIndexType.set((const Type *)idx);
- sm->mPrimitiveType.set((const Type *)prim);
-
- sm->mVertexTypeCount = vtxCount;
- sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
- sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
- for (uint32_t ct=0; ct < vtxCount; ct++) {
- sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
- }
-
- sm->mPrimitive = (RsPrimitive)primType;
- sm->updateGLPrimitive();
- return sm;
-}
-
-void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot)
-{
- SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
- rsAssert(slot < sm->mVertexTypeCount);
-
- sm->mVertexBuffers[slot].set((Allocation *)va);
-}
-
-void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va)
-{
- SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
- sm->mIndexBuffer.set((Allocation *)va);
-}
-
-void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va)
-{
- SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
- sm->mPrimitiveBuffer.set((Allocation *)va);
-}
-
-
-
-
-}}
-
diff --git a/libs/rs/rsSimpleMesh.h b/libs/rs/rsSimpleMesh.h
deleted file mode 100644
index 362c7fbac2d4..000000000000
--- a/libs/rs/rsSimpleMesh.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RS_SIMPLE_MESH_H
-#define ANDROID_RS_SIMPLE_MESH_H
-
-
-#include "RenderScript.h"
-
-// ---------------------------------------------------------------------------
-namespace android {
-namespace renderscript {
-
-
-// An element is a group of Components that occupies one cell in a structure.
-class SimpleMesh : public ObjectBase
-{
-public:
- SimpleMesh(Context *);
- ~SimpleMesh();
-
- ObjectBaseRef<const Type> mIndexType;
- ObjectBaseRef<const Type> mPrimitiveType;
- ObjectBaseRef<const Type> *mVertexTypes;
- uint32_t mVertexTypeCount;
-
- ObjectBaseRef<Allocation> mIndexBuffer;
- ObjectBaseRef<Allocation> mPrimitiveBuffer;
- ObjectBaseRef<Allocation> *mVertexBuffers;
-
- RsPrimitive mPrimitive;
- uint32_t mGLPrimitive;
-
-
- void render(Context *) const;
- void renderRange(Context *, uint32_t start, uint32_t len) const;
- void uploadAll(Context *);
- void updateGLPrimitive();
-
- virtual void serialize(OStream *stream) const;
- virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_SIMPLE_MESH; }
- static SimpleMesh *createFromStream(Context *rsc, IStream *stream);
-
-protected:
-};
-
-class SimpleMeshContext
-{
-public:
- SimpleMeshContext();
- ~SimpleMeshContext();
-
-
-};
-
-
-}
-}
-#endif //ANDROID_RS_SIMPLE_MESH_H
-
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index fba3d6d0acd0..1f1f1ac02a5e 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -32,6 +32,10 @@ extern void rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h
extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism);
extern void __attribute__((overloadable)) rsgDrawSimpleMesh(rs_mesh ism, int start, int len);
+extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism);
+extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism, int primitiveIndex);
+extern void __attribute__((overloadable)) rsgDrawMesh(rs_mesh ism, int primitiveIndex, int start, int len);
+
extern void rsgClearColor(float, float, float, float);
extern void rsgClearDepth(float);
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
index fa192563cb4b..65260325b21f 100644
--- a/libs/surfaceflinger/TextureManager.cpp
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -87,7 +87,7 @@ status_t TextureManager::initTexture(Image* pImage, int32_t format)
GLenum target = GL_TEXTURE_2D;
#if defined(GL_OES_texture_external)
if (GLExtensions::getInstance().haveTextureExternal()) {
- if (format && isSupportedYuvFormat(format)) {
+ if (format && isYuvFormat(format)) {
target = GL_TEXTURE_EXTERNAL_OES;
pImage->target = Texture::TEXTURE_EXTERNAL;
}
@@ -105,23 +105,32 @@ status_t TextureManager::initTexture(Image* pImage, int32_t format)
bool TextureManager::isSupportedYuvFormat(int format)
{
- return isYuvFormat(format);
+ switch (format) {
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YV16:
+ return true;
+ }
+ return false;
}
bool TextureManager::isYuvFormat(int format)
{
switch (format) {
- case HAL_PIXEL_FORMAT_NV16:
- case HAL_PIXEL_FORMAT_NV21:
- case HAL_PIXEL_FORMAT_IYUV:
- case HAL_PIXEL_FORMAT_YUV9:
- case HAL_PIXEL_FORMAT_YUY2:
- case HAL_PIXEL_FORMAT_UYVY:
- case HAL_PIXEL_FORMAT_NV12:
- case HAL_PIXEL_FORMAT_NV61:
- case HAL_PIXEL_FORMAT_NV12_ADRENO_TILED:
+ // supported YUV formats
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YV16:
+ // Legacy/deprecated YUV formats
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
return true;
}
+
+ // Any OEM format needs to be considered
+ if (format>=0x100 && format<=0x1FF)
+ return true;
+
return false;
}
@@ -255,7 +264,7 @@ status_t TextureManager::loadTexture(Texture* texture,
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, texture->potWidth, texture->potHeight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
- } else if (isYuvFormat(t.format)) {
+ } else if (isSupportedYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexImage2D(GL_TEXTURE_2D, 0,
GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
@@ -283,7 +292,7 @@ status_t TextureManager::loadTexture(Texture* texture,
0, bounds.top, t.width, bounds.height(),
GL_RGBA, GL_UNSIGNED_BYTE,
t.data + bounds.top*t.stride*4);
- } else if (isYuvFormat(t.format)) {
+ } else if (isSupportedYuvFormat(t.format)) {
// just show the Y plane of YUV buffers
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, bounds.top, t.width, bounds.height(),
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index c9a5950d1532..b205418e0f70 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -59,16 +59,13 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
// YUV format from the HAL are handled here
switch (format) {
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
- case HAL_PIXEL_FORMAT_YCrCb_422_SP:
- case HAL_PIXEL_FORMAT_YCbCr_422_P:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
- case HAL_PIXEL_FORMAT_CbYCrY_422_I:
+ case HAL_PIXEL_FORMAT_YV16:
info->bitsPerPixel = 16;
goto done;
- case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
- case HAL_PIXEL_FORMAT_YCbCr_420_P:
+ case HAL_PIXEL_FORMAT_YV12:
info->bitsPerPixel = 12;
done:
info->format = format;
diff --git a/media/jni/android_media_MtpServer.cpp b/media/jni/android_media_MtpServer.cpp
index 355a5eb4b140..e6a3835a9e4d 100644
--- a/media/jni/android_media_MtpServer.cpp
+++ b/media/jni/android_media_MtpServer.cpp
@@ -27,6 +27,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "private/android_filesystem_config.h"
#include "MtpServer.h"
@@ -65,7 +66,7 @@ public:
return false;
}
- MtpServer* server = new MtpServer(fd, mDatabasePath);
+ MtpServer* server = new MtpServer(fd, mDatabasePath, AID_SDCARD_RW, 0664, 0775);
server->addStorage(mStoragePath);
// temporary
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 8bc6e9ac0e50..3619013fa4f7 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -69,6 +69,7 @@ status_t StagefrightRecorder::setAudioSource(audio_source as) {
LOGV("setAudioSource: %d", as);
if (as < AUDIO_SOURCE_DEFAULT ||
as >= AUDIO_SOURCE_LIST_END) {
+ LOGE("Invalid audio source: %d", as);
return BAD_VALUE;
}
@@ -85,6 +86,7 @@ status_t StagefrightRecorder::setVideoSource(video_source vs) {
LOGV("setVideoSource: %d", vs);
if (vs < VIDEO_SOURCE_DEFAULT ||
vs >= VIDEO_SOURCE_LIST_END) {
+ LOGE("Invalid video source: %d", vs);
return BAD_VALUE;
}
@@ -101,6 +103,7 @@ status_t StagefrightRecorder::setOutputFormat(output_format of) {
LOGV("setOutputFormat: %d", of);
if (of < OUTPUT_FORMAT_DEFAULT ||
of >= OUTPUT_FORMAT_LIST_END) {
+ LOGE("Invalid output format: %d", of);
return BAD_VALUE;
}
@@ -117,6 +120,7 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
LOGV("setAudioEncoder: %d", ae);
if (ae < AUDIO_ENCODER_DEFAULT ||
ae >= AUDIO_ENCODER_LIST_END) {
+ LOGE("Invalid audio encoder: %d", ae);
return BAD_VALUE;
}
@@ -133,6 +137,7 @@ status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
LOGV("setVideoEncoder: %d", ve);
if (ve < VIDEO_ENCODER_DEFAULT ||
ve >= VIDEO_ENCODER_LIST_END) {
+ LOGE("Invalid video encoder: %d", ve);
return BAD_VALUE;
}
@@ -176,7 +181,7 @@ status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
LOGV("setCamera");
if (camera == 0) {
LOGE("camera is NULL");
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -185,7 +190,7 @@ status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
if (mCamera == 0) {
LOGE("Unable to connect to camera");
IPCThreadState::self()->restoreCallingIdentity(token);
- return UNKNOWN_ERROR;
+ return -EBUSY;
}
LOGV("Connected to camera");
@@ -206,11 +211,11 @@ status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) {
}
status_t StagefrightRecorder::setOutputFile(const char *path) {
- LOGE("setOutputFile(const char*) should not be called");
+ LOGE("setOutputFile(const char*) must not be called");
// We don't actually support this at all, as the media_server process
// no longer has permissions to create files.
- return UNKNOWN_ERROR;
+ return -EPERM;
}
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
@@ -219,6 +224,11 @@ status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t leng
CHECK_EQ(offset, 0);
CHECK_EQ(length, 0);
+ if (fd < 0) {
+ LOGE("Invalid file descriptor: %d", fd);
+ return -EBADF;
+ }
+
if (mOutputFd >= 0) {
::close(mOutputFd);
}
@@ -294,6 +304,7 @@ status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
LOGV("setParamAudioNumberOfChannels: %d", channels);
if (channels <= 0 || channels >= 3) {
LOGE("Invalid number of audio channels: %d", channels);
+ return BAD_VALUE;
}
// Additional check on the number of channels will be performed later.
@@ -331,21 +342,23 @@ status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
return OK;
}
-status_t StagefrightRecorder::setParamMaxDurationOrFileSize(int64_t limit,
- bool limit_is_duration) {
- LOGV("setParamMaxDurationOrFileSize: limit (%lld) for %s",
- limit, limit_is_duration?"duration":"size");
- if (limit_is_duration) { // limit is in ms
- if (limit <= 1000) { // XXX: 1 second
- LOGE("Max file duration is too short: %lld us", limit);
- }
- mMaxFileDurationUs = limit * 1000LL;
- } else {
- if (limit <= 1024) { // XXX: 1 kB
- LOGE("Max file size is too small: %lld bytes", limit);
- }
- mMaxFileSizeBytes = limit;
+status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
+ LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
+ if (timeUs <= 1000000LL) { // XXX: 1 second
+ LOGE("Max file duration is too short: %lld us", timeUs);
+ return BAD_VALUE;
}
+ mMaxFileDurationUs = timeUs;
+ return OK;
+}
+
+status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
+ LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
+ if (bytes <= 1024) { // XXX: 1 kB
+ LOGE("Max file size is too small: %lld bytes", bytes);
+ return BAD_VALUE;
+ }
+ mMaxFileSizeBytes = bytes;
return OK;
}
@@ -370,7 +383,7 @@ status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
// If interval < 0, only the first frame is I frame, and rest are all P frames
// If interval == 0, all frames are encoded as I frames. No P frames
-// If interval > 0, it is the time spacing between 2 neighboring I frames
+// If interval > 0, it is the time spacing (seconds) between 2 neighboring I frames
status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t interval) {
LOGV("setParamVideoIFramesInterval: %d seconds", interval);
mIFramesInterval = interval;
@@ -396,6 +409,7 @@ status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
status_t StagefrightRecorder::setParamTrackFrameStatus(int32_t nFrames) {
LOGV("setParamTrackFrameStatus: %d", nFrames);
if (nFrames <= 0) {
+ LOGE("Invalid number of frames to track: %d", nFrames);
return BAD_VALUE;
}
mTrackEveryNumberOfFrames = nFrames;
@@ -405,6 +419,7 @@ status_t StagefrightRecorder::setParamTrackFrameStatus(int32_t nFrames) {
status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
+ LOGE("Tracking time duration too short: %lld us", timeDurationUs);
return BAD_VALUE;
}
mTrackEveryTimeDurationUs = timeDurationUs;
@@ -417,14 +432,12 @@ status_t StagefrightRecorder::setParameter(
if (key == "max-duration") {
int64_t max_duration_ms;
if (safe_strtoi64(value.string(), &max_duration_ms)) {
- return setParamMaxDurationOrFileSize(
- max_duration_ms, true /* limit_is_duration */);
+ return setParamMaxFileDurationUs(1000LL * max_duration_ms);
}
} else if (key == "max-filesize") {
int64_t max_filesize_bytes;
if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
- return setParamMaxDurationOrFileSize(
- max_filesize_bytes, false /* limit is filesize */);
+ return setParamMaxFileSizeBytes(max_filesize_bytes);
}
} else if (key == "interleave-duration-us") {
int32_t durationUs;
@@ -528,7 +541,10 @@ status_t StagefrightRecorder::prepare() {
}
status_t StagefrightRecorder::start() {
+ CHECK(mOutputFd >= 0);
+
if (mWriter != NULL) {
+ LOGE("File writer is not avaialble");
return UNKNOWN_ERROR;
}
@@ -547,6 +563,7 @@ status_t StagefrightRecorder::start() {
return startAACRecording();
default:
+ LOGE("Unsupported output file format: %d", mOutputFormat);
return UNKNOWN_ERROR;
}
}
@@ -610,7 +627,6 @@ status_t StagefrightRecorder::startAACRecording() {
CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
- CHECK(mOutputFd >= 0);
CHECK(0 == "AACWriter is not implemented yet");
@@ -626,34 +642,34 @@ status_t StagefrightRecorder::startAMRRecording() {
mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
LOGE("Invalid encoder %d used for AMRNB recording",
mAudioEncoder);
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
if (mSampleRate != 8000) {
LOGE("Invalid sampling rate %d used for AMRNB recording",
mSampleRate);
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
} else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
LOGE("Invlaid encoder %d used for AMRWB recording",
mAudioEncoder);
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
if (mSampleRate != 16000) {
LOGE("Invalid sample rate %d used for AMRWB recording",
mSampleRate);
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
}
if (mAudioChannels != 1) {
LOGE("Invalid number of audio channels %d used for amr recording",
mAudioChannels);
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
LOGE("Invalid audio source: %d", mAudioSource);
- return UNKNOWN_ERROR;
+ return BAD_VALUE;
}
sp<MediaSource> audioEncoder = createAudioSource();
@@ -662,7 +678,6 @@ status_t StagefrightRecorder::startAMRRecording() {
return UNKNOWN_ERROR;
}
- CHECK(mOutputFd >= 0);
mWriter = new AMRWriter(dup(mOutputFd));
mWriter->addSource(audioEncoder);
@@ -729,6 +744,54 @@ void StagefrightRecorder::clipVideoFrameWidth() {
}
}
+status_t StagefrightRecorder::setupCameraSource() {
+ clipVideoBitRate();
+ clipVideoFrameRate();
+ clipVideoFrameWidth();
+ clipVideoFrameHeight();
+
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ if (mCamera == 0) {
+ mCamera = Camera::connect(mCameraId);
+ if (mCamera == 0) {
+ LOGE("Camera connection could not be established.");
+ return -EBUSY;
+ }
+ mFlags &= ~FLAGS_HOT_CAMERA;
+ mCamera->lock();
+ }
+
+ // Set the actual video recording frame size
+ CameraParameters params(mCamera->getParameters());
+ params.setPreviewSize(mVideoWidth, mVideoHeight);
+ params.setPreviewFrameRate(mFrameRate);
+ String8 s = params.flatten();
+ CHECK_EQ(OK, mCamera->setParameters(s));
+ CameraParameters newCameraParams(mCamera->getParameters());
+
+ // Check on video frame size
+ int frameWidth = 0, frameHeight = 0;
+ newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
+ if (frameWidth < 0 || frameWidth != mVideoWidth ||
+ frameHeight < 0 || frameHeight != mVideoHeight) {
+ LOGE("Failed to set the video frame size to %dx%d",
+ mVideoWidth, mVideoHeight);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ return UNKNOWN_ERROR;
+ }
+
+ // Check on video frame rate
+ int frameRate = newCameraParams.getPreviewFrameRate();
+ if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
+ LOGE("Failed to set frame rate to %d fps. The actual "
+ "frame rate is %d", mFrameRate, frameRate);
+ }
+
+ CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ return OK;
+}
+
void StagefrightRecorder::clipVideoFrameHeight() {
LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
@@ -746,146 +809,113 @@ void StagefrightRecorder::clipVideoFrameHeight() {
}
}
-status_t StagefrightRecorder::startMPEG4Recording() {
- mWriter = new MPEG4Writer(dup(mOutputFd));
- int32_t totalBitRate = 0;
-
- // Add audio source first if it exists
- if (mAudioSource != AUDIO_SOURCE_LIST_END) {
- sp<MediaSource> audioEncoder;
- switch(mAudioEncoder) {
- case AUDIO_ENCODER_AMR_NB:
- case AUDIO_ENCODER_AMR_WB:
- case AUDIO_ENCODER_AAC:
- audioEncoder = createAudioSource();
- break;
- default:
- LOGE("Unsupported audio encoder: %d", mAudioEncoder);
- return UNKNOWN_ERROR;
- }
+status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) {
+ status_t err = setupCameraSource();
+ if (err != OK) return err;
- if (audioEncoder == NULL) {
- return UNKNOWN_ERROR;
- }
- totalBitRate += mAudioBitRate;
- mWriter->addSource(audioEncoder);
+ sp<CameraSource> cameraSource = CameraSource::CreateFromCamera(mCamera);
+ CHECK(cameraSource != NULL);
+ if(mCaptureTimeLapse) {
+ cameraSource->enableTimeLapseMode(1E6, mFrameRate);
}
- if (mVideoSource == VIDEO_SOURCE_DEFAULT
- || mVideoSource == VIDEO_SOURCE_CAMERA) {
-
- clipVideoBitRate();
- clipVideoFrameRate();
- clipVideoFrameWidth();
- clipVideoFrameHeight();
-
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- if (mCamera == 0) {
- mCamera = Camera::connect(mCameraId);
- if (mCamera == 0) {
- LOGE("Camera connection could not be established.");
- return -EBUSY;
- }
- mFlags &= ~FLAGS_HOT_CAMERA;
- mCamera->lock();
- }
+ sp<MetaData> enc_meta = new MetaData;
+ enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
+ enc_meta->setInt32(kKeySampleRate, mFrameRate);
- // Set the actual video recording frame size
- CameraParameters params(mCamera->getParameters());
- params.setPreviewSize(mVideoWidth, mVideoHeight);
- params.setPreviewFrameRate(mFrameRate);
- String8 s = params.flatten();
- CHECK_EQ(OK, mCamera->setParameters(s));
- CameraParameters newCameraParams(mCamera->getParameters());
-
- // Check on video frame size
- int frameWidth = 0, frameHeight = 0;
- newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
- if (frameWidth < 0 || frameWidth != mVideoWidth ||
- frameHeight < 0 || frameHeight != mVideoHeight) {
- LOGE("Failed to set the video frame size to %dx%d",
- mVideoWidth, mVideoHeight);
- IPCThreadState::self()->restoreCallingIdentity(token);
- return UNKNOWN_ERROR;
- }
-
- // Check on video frame rate
- int frameRate = newCameraParams.getPreviewFrameRate();
- if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
- LOGE("Failed to set frame rate to %d fps. The actual "
- "frame rate is %d", mFrameRate, frameRate);
- }
-
- CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
- IPCThreadState::self()->restoreCallingIdentity(token);
+ switch (mVideoEncoder) {
+ case VIDEO_ENCODER_H263:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+ break;
- sp<CameraSource> cameraSource =
- CameraSource::CreateFromCamera(mCamera);
+ case VIDEO_ENCODER_MPEG_4_SP:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ break;
- CHECK(cameraSource != NULL);
+ case VIDEO_ENCODER_H264:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ break;
- sp<MetaData> enc_meta = new MetaData;
- enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
- enc_meta->setInt32(kKeySampleRate, mFrameRate);
+ default:
+ CHECK(!"Should not be here, unsupported video encoding.");
+ break;
+ }
- switch (mVideoEncoder) {
- case VIDEO_ENCODER_H263:
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
- break;
+ sp<MetaData> meta = cameraSource->getFormat();
- case VIDEO_ENCODER_MPEG_4_SP:
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
- break;
+ int32_t width, height, stride, sliceHeight;
+ CHECK(meta->findInt32(kKeyWidth, &width));
+ CHECK(meta->findInt32(kKeyHeight, &height));
+ CHECK(meta->findInt32(kKeyStride, &stride));
+ CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
- case VIDEO_ENCODER_H264:
- enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- break;
+ enc_meta->setInt32(kKeyWidth, width);
+ enc_meta->setInt32(kKeyHeight, height);
+ enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
+ enc_meta->setInt32(kKeyStride, stride);
+ enc_meta->setInt32(kKeySliceHeight, sliceHeight);
- default:
- CHECK(!"Should not be here, unsupported video encoding.");
- break;
- }
+ OMXClient client;
+ CHECK_EQ(client.connect(), OK);
- sp<MetaData> meta = cameraSource->getFormat();
+ sp<MediaSource> encoder = OMXCodec::Create(
+ client.interface(), enc_meta,
+ true /* createEncoder */, cameraSource);
+ if (encoder == NULL) {
+ return UNKNOWN_ERROR;
+ }
- int32_t width, height, stride, sliceHeight;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
- CHECK(meta->findInt32(kKeyStride, &stride));
- CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+ writer->addSource(encoder);
+ return OK;
+}
- enc_meta->setInt32(kKeyWidth, width);
- enc_meta->setInt32(kKeyHeight, height);
- enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
- enc_meta->setInt32(kKeyStride, stride);
- enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
+ sp<MediaSource> audioEncoder;
+ switch(mAudioEncoder) {
+ case AUDIO_ENCODER_AMR_NB:
+ case AUDIO_ENCODER_AMR_WB:
+ case AUDIO_ENCODER_AAC:
+ audioEncoder = createAudioSource();
+ break;
+ default:
+ LOGE("Unsupported audio encoder: %d", mAudioEncoder);
+ return UNKNOWN_ERROR;
+ }
- OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ if (audioEncoder == NULL) {
+ return UNKNOWN_ERROR;
+ }
+ writer->addSource(audioEncoder);
+ return OK;
+}
- sp<MediaSource> encoder =
- OMXCodec::Create(
- client.interface(), enc_meta,
- true /* createEncoder */, cameraSource);
+status_t StagefrightRecorder::startMPEG4Recording() {
+ int32_t totalBitRate = 0;
+ status_t err = OK;
+ sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd));
- CHECK(mOutputFd >= 0);
+ // Add audio source first if it exists
+ if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_LIST_END)) {
+ err = setupAudioEncoder(writer);
+ if (err != OK) return err;
+ totalBitRate += mAudioBitRate;
+ }
+ if (mVideoSource == VIDEO_SOURCE_DEFAULT
+ || mVideoSource == VIDEO_SOURCE_CAMERA) {
+ err = setupVideoEncoder(writer);
+ if (err != OK) return err;
totalBitRate += mVideoBitRate;
- mWriter->addSource(encoder);
}
- {
- // MPEGWriter specific handling
- MPEG4Writer *writer = ((MPEG4Writer *) mWriter.get());
- writer->setInterleaveDuration(mInterleaveDurationUs);
- }
+ reinterpret_cast<MPEG4Writer *>(writer.get())->
+ setInterleaveDuration(mInterleaveDurationUs);
if (mMaxFileDurationUs != 0) {
- mWriter->setMaxFileDuration(mMaxFileDurationUs);
+ writer->setMaxFileDuration(mMaxFileDurationUs);
}
if (mMaxFileSizeBytes != 0) {
- mWriter->setMaxFileSize(mMaxFileSizeBytes);
+ writer->setMaxFileSize(mMaxFileSizeBytes);
}
- mWriter->setListener(mListener);
sp<MetaData> meta = new MetaData;
meta->setInt64(kKeyTime, systemTime() / 1000);
meta->setInt32(kKeyFileType, mOutputFormat);
@@ -897,8 +927,9 @@ status_t StagefrightRecorder::startMPEG4Recording() {
if (mTrackEveryTimeDurationUs > 0) {
meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
}
- mWriter->start(meta.get());
- return OK;
+ writer->setListener(mListener);
+ mWriter = writer;
+ return mWriter->start(meta.get());
}
status_t StagefrightRecorder::pause() {
@@ -914,7 +945,7 @@ status_t StagefrightRecorder::stop() {
LOGV("stop");
if (mWriter != NULL) {
mWriter->stop();
- mWriter = NULL;
+ mWriter.clear();
}
if (mCamera != 0) {
@@ -925,7 +956,7 @@ status_t StagefrightRecorder::stop() {
mCamera->stopPreview();
}
mCamera->unlock();
- mCamera = NULL;
+ mCamera.clear();
IPCThreadState::self()->restoreCallingIdentity(token);
mFlags = 0;
}
@@ -966,6 +997,7 @@ status_t StagefrightRecorder::reset() {
mCameraId = 0;
mTrackEveryNumberOfFrames = 0;
mTrackEveryTimeDurationUs = 0;
+ mCaptureTimeLapse = false;
mEncoderProfiles = MediaProfiles::getInstance();
mOutputFd = -1;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index f4488b641c3f..dcb474798dd9 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -87,6 +87,8 @@ private:
int32_t mTrackEveryNumberOfFrames;
int64_t mTrackEveryTimeDurationUs;
+ bool mCaptureTimeLapse;
+
String8 mParams;
int mOutputFd;
int32_t mFlags;
@@ -97,6 +99,11 @@ private:
status_t startAMRRecording();
status_t startAACRecording();
sp<MediaSource> createAudioSource();
+ status_t setupCameraSource();
+ status_t setupAudioEncoder(const sp<MediaWriter>& writer);
+ status_t setupVideoEncoder(const sp<MediaWriter>& writer);
+
+ // Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
status_t setParamAudioEncodingBitRate(int32_t bitRate);
status_t setParamAudioNumberOfChannels(int32_t channles);
@@ -108,7 +115,8 @@ private:
status_t setParamTrackFrameStatus(int32_t nFrames);
status_t setParamInterleaveDuration(int32_t durationUs);
status_t setParam64BitFileOffset(bool use64BitFileOffset);
- status_t setParamMaxDurationOrFileSize(int64_t limit, bool limit_is_duration);
+ status_t setParamMaxFileDurationUs(int64_t timeUs);
+ status_t setParamMaxFileSizeBytes(int64_t bytes);
void clipVideoBitRate();
void clipVideoFrameRate();
void clipVideoFrameWidth();
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 6f4c980960e9..bb53d97b3b4f 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -116,6 +116,19 @@ CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) {
return new CameraSource(camera);
}
+void CameraSource::enableTimeLapseMode(
+ int64_t timeBetweenTimeLapseFrameCaptureUs, int32_t videoFrameRate) {
+ LOGV("starting time lapse mode");
+ mTimeBetweenTimeLapseFrameCaptureUs = timeBetweenTimeLapseFrameCaptureUs;
+ mTimeBetweenTimeLapseVideoFramesUs = (1E6/videoFrameRate);
+}
+
+void CameraSource::disableTimeLapseMode() {
+ LOGV("stopping time lapse mode");
+ mTimeBetweenTimeLapseFrameCaptureUs = -1;
+ mTimeBetweenTimeLapseVideoFramesUs = 0;
+}
+
CameraSource::CameraSource(const sp<Camera> &camera)
: mCamera(camera),
mFirstFrameTimeUs(0),
@@ -126,7 +139,10 @@ CameraSource::CameraSource(const sp<Camera> &camera)
mNumGlitches(0),
mGlitchDurationThresholdUs(200000),
mCollectStats(false),
- mStarted(false) {
+ mStarted(false),
+ mTimeBetweenTimeLapseFrameCaptureUs(-1),
+ mTimeBetweenTimeLapseVideoFramesUs(0),
+ mLastTimeLapseFrameRealTimestampUs(0) {
int64_t token = IPCThreadState::self()->clearCallingIdentity();
String8 s = mCamera->getParameters();
@@ -316,6 +332,35 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
++mNumGlitches;
}
+ // time lapse
+ if(mTimeBetweenTimeLapseFrameCaptureUs >= 0) {
+ if(mLastTimeLapseFrameRealTimestampUs == 0) {
+ // First time lapse frame. Initialize mLastTimeLapseFrameRealTimestampUs
+ // to current time (timestampUs) and save frame data.
+ LOGV("dataCallbackTimestamp timelapse: initial frame");
+
+ mLastTimeLapseFrameRealTimestampUs = timestampUs;
+ } else if (timestampUs <
+ (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) {
+ // Skip all frames from last encoded frame until
+ // sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed.
+ // Tell the camera to release its recording frame and return.
+ LOGV("dataCallbackTimestamp timelapse: skipping intermediate frame");
+
+ releaseOneRecordingFrame(data);
+ return;
+ } else {
+ // Desired frame has arrived after mTimeBetweenTimeLapseFrameCaptureUs time:
+ // - Reset mLastTimeLapseFrameRealTimestampUs to current time.
+ // - Artificially modify timestampUs to be one frame time (1/framerate) ahead
+ // of the last encoded frame's time stamp.
+ LOGV("dataCallbackTimestamp timelapse: got timelapse frame");
+
+ mLastTimeLapseFrameRealTimestampUs = timestampUs;
+ timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs;
+ }
+ }
+
mLastFrameTimestampUs = timestampUs;
if (mNumFramesReceived == 0) {
mFirstFrameTimeUs = timestampUs;
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 831fa2a2ba3b..cd4f34992f0d 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -31,8 +31,9 @@ namespace android {
ALooperRoster gLooperRoster;
struct ALooper::LooperThread : public Thread {
- LooperThread(ALooper *looper)
- : mLooper(looper) {
+ LooperThread(ALooper *looper, bool canCallJava)
+ : Thread(canCallJava),
+ mLooper(looper) {
}
virtual bool threadLoop() {
@@ -72,7 +73,7 @@ void ALooper::unregisterHandler(handler_id handlerID) {
gLooperRoster.unregisterHandler(handlerID);
}
-status_t ALooper::start(bool runOnCallingThread) {
+status_t ALooper::start(bool runOnCallingThread, bool canCallJava) {
if (runOnCallingThread) {
{
Mutex::Autolock autoLock(mLock);
@@ -96,7 +97,7 @@ status_t ALooper::start(bool runOnCallingThread) {
return INVALID_OPERATION;
}
- mThread = new LooperThread(this);
+ mThread = new LooperThread(this, canCallJava);
status_t err = mThread->run("ALooper");
if (err != OK) {
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index dfd1ae335098..26c6d42ca606 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -16,6 +16,8 @@
#include "AMessage.h"
+#include <ctype.h>
+
#include "AAtomizer.h"
#include "ADebug.h"
#include "ALooperRoster.h"
@@ -238,4 +240,105 @@ sp<AMessage> AMessage::dup() const {
return msg;
}
+static void appendIndent(AString *s, int32_t indent) {
+ static const char kWhitespace[] =
+ " "
+ " ";
+
+ CHECK_LT((size_t)indent, sizeof(kWhitespace));
+
+ s->append(kWhitespace, indent);
+}
+
+static bool isFourcc(uint32_t what) {
+ return isprint(what & 0xff)
+ && isprint((what >> 8) & 0xff)
+ && isprint((what >> 16) & 0xff)
+ && isprint((what >> 24) & 0xff);
+}
+
+AString AMessage::debugString(int32_t indent) const {
+ AString s = "AMessage(what = ";
+
+ AString tmp;
+ if (isFourcc(mWhat)) {
+ tmp = StringPrintf(
+ "'%c%c%c%c'",
+ (char)(mWhat >> 24),
+ (char)((mWhat >> 16) & 0xff),
+ (char)((mWhat >> 8) & 0xff),
+ (char)(mWhat & 0xff));
+ } else {
+ tmp = StringPrintf("0x%08x", mWhat);
+ }
+ s.append(tmp);
+
+ if (mTarget != 0) {
+ tmp = StringPrintf(", target = %d", mTarget);
+ s.append(tmp);
+ }
+ s.append(") = {\n");
+
+ for (size_t i = 0; i < mNumItems; ++i) {
+ const Item &item = mItems[i];
+
+ switch (item.mType) {
+ case kTypeInt32:
+ tmp = StringPrintf(
+ "int32_t %s = %d", item.mName, item.u.int32Value);
+ break;
+ case kTypeInt64:
+ tmp = StringPrintf(
+ "int64_t %s = %lld", item.mName, item.u.int64Value);
+ break;
+ case kTypeSize:
+ tmp = StringPrintf(
+ "size_t %s = %d", item.mName, item.u.sizeValue);
+ break;
+ case kTypeFloat:
+ tmp = StringPrintf(
+ "float %s = %f", item.mName, item.u.floatValue);
+ break;
+ case kTypeDouble:
+ tmp = StringPrintf(
+ "double %s = %f", item.mName, item.u.doubleValue);
+ break;
+ case kTypePointer:
+ tmp = StringPrintf(
+ "void *%s = %p", item.mName, item.u.ptrValue);
+ break;
+ case kTypeString:
+ tmp = StringPrintf(
+ "string %s = \"%s\"",
+ item.mName,
+ item.u.stringValue->c_str());
+ break;
+ case kTypeObject:
+ tmp = StringPrintf(
+ "RefBase *%s = %p", item.mName, item.u.refValue);
+ break;
+ case kTypeMessage:
+ tmp = StringPrintf(
+ "AMessage %s = %s",
+ item.mName,
+ static_cast<AMessage *>(
+ item.u.refValue)->debugString(
+ indent + strlen(item.mName) + 14).c_str());
+ break;
+ default:
+ TRESPASS();
+ }
+
+ appendIndent(&s, indent);
+ s.append(" ");
+ s.append(tmp);
+ s.append("\n");
+ }
+
+ appendIndent(&s, indent);
+ s.append("}");
+
+ return s;
+}
+
} // namespace android
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 3c9909b46a6f..13a643054cc2 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -32,6 +32,7 @@ LOCAL_SRC_FILES:= \
MtpRequestPacket.cpp \
MtpResponsePacket.cpp \
MtpServer.cpp \
+ MtpSqliteDatabase.cpp \
MtpStorageInfo.cpp \
MtpStringBuffer.cpp \
MtpStorage.cpp \
@@ -70,18 +71,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE := scantest
LOCAL_SRC_FILES:= \
scantest.cpp \
- MtpMediaScanner.cpp \
- MtpDatabase.cpp \
- MtpDataPacket.cpp \
- MtpPacket.cpp \
- MtpStringBuffer.cpp \
- MtpUtils.cpp \
- SqliteDatabase.cpp \
- SqliteStatement.cpp \
-#LOCAL_STATIC_LIBRARIES := libusbhost
-#LOCAL_LDLIBS := -lpthread
+LOCAL_STATIC_LIBRARIES := libmtp
LOCAL_C_INCLUDES := external/sqlite/dist
LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libmedia
diff --git a/media/mtp/MtpDatabase.cpp b/media/mtp/MtpDatabase.cpp
index 0f9b898448ec..eabd9937311f 100644
--- a/media/mtp/MtpDatabase.cpp
+++ b/media/mtp/MtpDatabase.cpp
@@ -18,196 +18,14 @@
#include "MtpDebug.h"
#include "MtpDatabase.h"
-#include "MtpDataPacket.h"
-#include "MtpUtils.h"
-#include "SqliteDatabase.h"
-#include "SqliteStatement.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sqlite3.h>
+#include "MtpTypes.h"
+#include "mtp.h"
namespace android {
-#define FILE_ID_COLUMN 1
-#define FILE_PATH_COLUMN 2
-#define FILE_FORMAT_COLUMN 3
-#define FILE_PARENT_COLUMN 4
-#define FILE_STORAGE_COLUMN 5
-#define FILE_SIZE_COLUMN 6
-#define FILE_MODIFIED_COLUMN 7
-
-#define AUDIO_ID_COLUMN 1
-#define AUDIO_TITLE_COLUMN 2
-#define AUDIO_ARTIST_COLUMN 3
-#define AUDIO_ALBUM_COLUMN 4
-#define AUDIO_ALBUM_ARTIST_COLUMN 5
-#define AUDIO_GENRE_COLUMN 6
-#define AUDIO_COMPOSER_COLUMN 7
-#define AUDIO_TRACK_NUMBER_COLUMN 8
-#define AUDIO_YEAR_COLUMN 9
-#define AUDIO_DURATION_COLUMN 10
-#define AUDIO_USE_COUNT_COLUMN 11
-#define AUDIO_SAMPLE_RATE_COLUMN 12
-#define AUDIO_NUM_CHANNELS_COLUMN 13
-#define AUDIO_AUDIO_WAVE_CODEC_COLUMN 14
-#define AUDIO_AUDIO_BIT_RATE_COLUMN 15
-
-#define FILE_TABLE_CREATE "CREATE TABLE IF NOT EXISTS files (" \
- "_id INTEGER PRIMARY KEY," \
- "path TEXT," \
- "format INTEGER," \
- "parent INTEGER," \
- "storage INTEGER," \
- "size INTEGER," \
- "date_modified INTEGER" \
- ");"
-
-#define AUDIO_TABLE_CREATE "CREATE TABLE IF NOT EXISTS audio (" \
- "id INTEGER PRIMARY KEY," \
- "title TEXT," \
- "artist TEXT," \
- "album TEXT," \
- "album_artist TEXT," \
- "genre TEXT," \
- "composer TEXT," \
- "track_number INTEGER," \
- "year INTEGER," \
- "duration INTEGER," \
- "use_count INTEGER," \
- "sample_rate INTEGER," \
- "num_channels INTEGER," \
- "audio_wave_codec TEXT," \
- "audio_bit_rate INTEGER" \
- ");"
-
-#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
-
-#define FILE_ID_QUERY "SELECT _id,format FROM files WHERE path = ?;"
-#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
-
-#define GET_OBJECT_INFO_QUERY "SELECT storage,format,parent,path,size,date_modified FROM files WHERE _id = ?;"
-#define FILE_INSERT "INSERT INTO files VALUES(?,?,?,?,?,?,?);"
-#define FILE_DELETE "DELETE FROM files WHERE _id = ?;"
-
-#define AUDIO_INSERT "INSERT INTO audio VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
-#define AUDIO_DELETE "DELETE FROM audio WHERE id = ?;"
-
-struct PropertyTableEntry {
- MtpObjectProperty property;
- int type;
- const char* columnName;
-};
-
-static const PropertyTableEntry kPropertyTable[] = {
- { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, "parent" },
- { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, "storage" },
- { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT32, "format" },
- { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, "path" },
- { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, "size" },
- { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, "date_modified" },
-};
-
-static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
- int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
- const PropertyTableEntry* entry = kPropertyTable;
- for (int i = 0; i < count; i++, entry++) {
- if (entry->property == property) {
- type = entry->type;
- columnName = entry->columnName;
- return true;
- }
- }
- return false;
-}
-
-
-
-MtpDatabase::MtpDatabase()
- : mFileIdQuery(NULL),
- mFilePathQuery(NULL),
- mObjectInfoQuery(NULL),
- mFileInserter(NULL),
- mFileDeleter(NULL),
- mAudioInserter(NULL),
- mAudioDeleter(NULL)
-{
-}
-
MtpDatabase::~MtpDatabase() {
}
-bool MtpDatabase::open(const char* path, bool create) {
- if (!SqliteDatabase::open(path, create))
- return false;
-
- // create tables and indices if necessary
- if (!exec(FILE_TABLE_CREATE)) {
- LOGE("could not create file table");
- return false;
- }
- if (!exec(PATH_INDEX_CREATE)) {
- LOGE("could not path index on file table");
- return false;
- }
- if (!exec(AUDIO_TABLE_CREATE)) {
- LOGE("could not create file table");
- return false;
- }
-
- if (!mFileIdQuery) {
- mFileIdQuery = new SqliteStatement(this);
- if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
- LOGE("could not compile FILE_ID_QUERY");
- exit(-1);
- }
- }
- if (!mFilePathQuery) {
- mFilePathQuery = new SqliteStatement(this);
- if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
- LOGE("could not compile FILE_PATH_QUERY");
- exit(-1);
- }
- }
- if (!mObjectInfoQuery) {
- mObjectInfoQuery = new SqliteStatement(this);
- if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
- LOGE("could not compile GET_OBJECT_INFO_QUERY");
- exit(-1);
- }
- }
- if (!mFileInserter) {
- mFileInserter = new SqliteStatement(this);
- if (!mFileInserter->prepare(FILE_INSERT)) {
- LOGE("could not compile FILE_INSERT\n");
- exit(-1);
- }
- }
- if (!mFileDeleter) {
- mFileDeleter = new SqliteStatement(this);
- if (!mFileDeleter->prepare(FILE_DELETE)) {
- LOGE("could not compile FILE_DELETE\n");
- exit(-1);
- }
- }
- if (!mAudioInserter) {
- mAudioInserter = new SqliteStatement(this);
- if (!mAudioInserter->prepare(AUDIO_INSERT)) {
- LOGE("could not compile AUDIO_INSERT\n");
- exit(-1);
- }
- }
- if (!mAudioDeleter) {
- mAudioDeleter = new SqliteStatement(this);
- if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
- LOGE("could not compile AUDIO_DELETE\n");
- exit(-1);
- }
- }
-
- return true;
-}
-
uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
switch (format) {
case MTP_FORMAT_AIFF:
@@ -260,322 +78,4 @@ uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
}
}
-MtpObjectHandle MtpDatabase::getObjectHandle(const char* path) {
- mFileIdQuery->reset();
- mFileIdQuery->bind(1, path);
- if (mFileIdQuery->step()) {
- int row = mFileIdQuery->getColumnInt(0);
- if (row > 0) {
- MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
- row |= getTableForFile(format);
- return row;
- }
- }
-
- return 0;
-}
-
-MtpObjectHandle MtpDatabase::addFile(const char* path,
- MtpObjectFormat format,
- MtpObjectHandle parent,
- MtpStorageID storage,
- uint64_t size,
- time_t modified) {
- mFileInserter->bind(FILE_PATH_COLUMN, path);
- mFileInserter->bind(FILE_FORMAT_COLUMN, format);
- mFileInserter->bind(FILE_PARENT_COLUMN, parent);
- mFileInserter->bind(FILE_STORAGE_COLUMN, storage);
- mFileInserter->bind(FILE_SIZE_COLUMN, size);
- mFileInserter->bind(FILE_MODIFIED_COLUMN, modified);
- mFileInserter->step();
- mFileInserter->reset();
- int result = lastInsertedRow();
- return (result <= 0 ? kInvalidObjectHandle : result);
-}
-
-MtpObjectHandle MtpDatabase::addAudioFile(MtpObjectHandle handle) {
- mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
- mAudioInserter->step();
- mAudioInserter->reset();
- int result = lastInsertedRow();
- handle |= kObjectHandleTableAudio;
- return (result > 0 ? handle : kInvalidObjectHandle);
-}
-
-MtpObjectHandle MtpDatabase::addAudioFile(MtpObjectHandle handle,
- const char* title,
- const char* artist,
- const char* album,
- const char* albumArtist,
- const char* genre,
- const char* composer,
- const char* mimeType,
- int track,
- int year,
- int duration) {
- mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
- if (title) mAudioInserter->bind(AUDIO_TITLE_COLUMN, title);
- if (artist) mAudioInserter->bind(AUDIO_ARTIST_COLUMN, artist);
- if (album) mAudioInserter->bind(AUDIO_ALBUM_COLUMN, album);
- if (albumArtist) mAudioInserter->bind(AUDIO_ALBUM_ARTIST_COLUMN, albumArtist);
- if (genre) mAudioInserter->bind(AUDIO_GENRE_COLUMN, genre);
- if (composer) mAudioInserter->bind(AUDIO_COMPOSER_COLUMN, composer);
- if (track) mAudioInserter->bind(AUDIO_TRACK_NUMBER_COLUMN, track);
- if (year) mAudioInserter->bind(AUDIO_YEAR_COLUMN, year);
- if (duration) mAudioInserter->bind(AUDIO_DURATION_COLUMN, duration);
- mAudioInserter->step();
- mAudioInserter->reset();
- int result = lastInsertedRow();
- if (result <= 0)
- return kInvalidObjectHandle;
- result |= kObjectHandleTableAudio;
- return result;
-}
-
-MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
- MtpObjectFormat format,
- MtpObjectHandle parent) {
- bool whereStorage = (storageID != 0xFFFFFFFF);
- bool whereFormat = (format != 0);
- bool whereParent = (parent != 0);
- char intBuffer[20];
-
- MtpString query("SELECT _id,format FROM files");
- if (whereStorage || whereFormat || whereParent)
- query += " WHERE";
- if (whereStorage) {
- snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
- query += " storage = ";
- query += intBuffer;
- }
- if (whereFormat) {
- snprintf(intBuffer, sizeof(intBuffer), "%d", format);
- if (whereStorage)
- query += " AND";
- query += " format = ";
- query += intBuffer;
- }
- if (whereParent) {
- if (parent != MTP_PARENT_ROOT)
- parent &= kObjectHandleIndexMask;
- snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
- if (whereStorage || whereFormat)
- query += " AND";
- query += " parent = ";
- query += intBuffer;
- }
- query += ";";
-
- SqliteStatement stmt(this);
- LOGV("%s", (const char *)query);
- stmt.prepare(query);
-
- MtpObjectHandleList* list = new MtpObjectHandleList();
- while (!stmt.isDone()) {
- if (stmt.step()) {
- int index = stmt.getColumnInt(0);
- LOGV("stmt.getColumnInt returned %d", index);
- if (index > 0) {
- MtpObjectFormat format = stmt.getColumnInt(1);
- index |= getTableForFile(format);
- list->push(index);
- }
- }
- }
- LOGV("list size: %d", list->size());
- return list;
-}
-
-
-MtpResponseCode MtpDatabase::getObjectProperty(MtpObjectHandle handle,
- MtpObjectProperty property,
- MtpDataPacket& packet) {
- int type;
- const char* columnName;
- char intBuffer[20];
-
- if (handle != MTP_PARENT_ROOT)
- handle &= kObjectHandleIndexMask;
-
- if (!getPropertyInfo(property, type, columnName))
- return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
- snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
-
- MtpString query("SELECT ");
- query += columnName;
- query += " FROM files WHERE _id = ";
- query += intBuffer;
- query += ";";
-
- SqliteStatement stmt(this);
- LOGV("%s", (const char *)query);
- stmt.prepare(query);
-
- if (!stmt.step())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-
- switch (type) {
- case MTP_TYPE_INT8:
- packet.putInt8(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_UINT8:
- packet.putUInt8(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_INT16:
- packet.putInt16(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_UINT16:
- packet.putUInt16(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_INT32:
- packet.putInt32(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_UINT32:
- packet.putUInt32(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_INT64:
- packet.putInt64(stmt.getColumnInt64(0));
- break;
- case MTP_TYPE_UINT64:
- packet.putUInt64(stmt.getColumnInt64(0));
- break;
- case MTP_TYPE_STR:
- packet.putString(stmt.getColumnString(0));
- break;
- default:
- LOGE("unsupported object type\n");
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- }
- return MTP_RESPONSE_OK;
-}
-
-MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet) {
- char date[20];
-
- if (handle != MTP_PARENT_ROOT)
- handle &= kObjectHandleIndexMask;
-
- mObjectInfoQuery->reset();
- mObjectInfoQuery->bind(1, handle);
- if (!mObjectInfoQuery->step())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-
- MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
- MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
- MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
- // extract name from path. do we want a separate database entry for this?
- const char* name = mObjectInfoQuery->getColumnString(3);
- const char* lastSlash = strrchr(name, '/');
- if (lastSlash)
- name = lastSlash + 1;
- int64_t size = mObjectInfoQuery->getColumnInt64(4);
- time_t modified = mObjectInfoQuery->getColumnInt(5);
- int associationType = (format == MTP_FORMAT_ASSOCIATION ?
- MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
- MTP_ASSOCIATION_TYPE_UNDEFINED);
-
- LOGV("storageID: %d, format: %d, parent: %d", storageID, format, parent);
-
- packet.putUInt32(storageID);
- packet.putUInt16(format);
- packet.putUInt16(0); // protection status
- packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
- packet.putUInt16(0); // thumb format
- packet.putUInt32(0); // thumb compressed size
- packet.putUInt32(0); // thumb pix width
- packet.putUInt32(0); // thumb pix height
- packet.putUInt32(0); // image pix width
- packet.putUInt32(0); // image pix height
- packet.putUInt32(0); // image bit depth
- packet.putUInt32(parent);
- packet.putUInt16(associationType);
- packet.putUInt32(0); // association desc
- packet.putUInt32(0); // sequence number
- packet.putString(name); // file name
- packet.putEmptyString();
- formatDateTime(modified, date, sizeof(date));
- packet.putString(date); // date modified
- packet.putEmptyString(); // keywords
-
- return MTP_RESPONSE_OK;
-}
-
-bool MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
- MtpString& filePath,
- int64_t& fileLength) {
- if (handle != MTP_PARENT_ROOT)
- handle &= kObjectHandleIndexMask;
- mFilePathQuery->reset();
- mFilePathQuery->bind(1, handle);
- if (!mFilePathQuery->step())
- return false;
-
- const char* path = mFilePathQuery->getColumnString(0);
- if (!path)
- return false;
- filePath = path;
- fileLength = mFilePathQuery->getColumnInt64(1);
- return true;
-}
-
-bool MtpDatabase::deleteFile(MtpObjectHandle handle) {
- uint32_t table = handle & kObjectHandleTableMask;
- handle &= kObjectHandleIndexMask;
- mFileDeleter->bind(1, handle);
- mFileDeleter->step();
- mFileDeleter->reset();
- if (table == kObjectHandleTableAudio) {
- mAudioDeleter->bind(1, handle);
- mAudioDeleter->step();
- mAudioDeleter->reset();
- }
-
- return true;
-}
-
-MtpObjectHandle* MtpDatabase::getFileList(int& outCount) {
- MtpObjectHandle* result = NULL;
- int count = 0;
- SqliteStatement stmt(this);
- stmt.prepare("SELECT count(*) FROM files;");
-
- MtpObjectHandleList* list = new MtpObjectHandleList();
- if (stmt.step())
- count = stmt.getColumnInt(0);
-
- if (count > 0) {
- result = new MtpObjectHandle[count];
- memset(result, 0, count * sizeof(*result));
- SqliteStatement stmt2(this);
- stmt2.prepare("SELECT _id,format FROM files;");
-
- for (int i = 0; i < count; i++) {
- if (!stmt2.step()) {
- LOGW("getFileList ended early");
- count = i;
- break;
- }
- MtpObjectHandle handle = stmt2.getColumnInt(0);
- MtpObjectFormat format = stmt2.getColumnInt(1);
- handle |= getTableForFile(format);
- result[i] = handle;
- }
- }
- outCount = count;
- return result;
-}
-
-/*
- for getObjectPropDesc
-
- packet.putUInt16(property);
- packet.putUInt16(dataType);
- packet.putUInt8(getSet);
- // default value DTS
- packet.putUInt32(groupCode);
- packet.putUInt8(formFlag);
- // form, variable
-*/
-
} // namespace android
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 51d5fb136d25..0c70d9fe6b79 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -23,65 +23,57 @@
namespace android {
class MtpDataPacket;
-class SqliteStatement;
-
-class MtpDatabase : public SqliteDatabase {
-private:
- SqliteStatement* mFileIdQuery;
- SqliteStatement* mFilePathQuery;
- SqliteStatement* mObjectInfoQuery;
- SqliteStatement* mFileInserter;
- SqliteStatement* mFileDeleter;
- SqliteStatement* mAudioInserter;
- SqliteStatement* mAudioDeleter;
+class MtpDatabase {
public:
- MtpDatabase();
- virtual ~MtpDatabase();
-
- static uint32_t getTableForFile(MtpObjectFormat format);
-
- bool open(const char* path, bool create);
- MtpObjectHandle getObjectHandle(const char* path);
- MtpObjectHandle addFile(const char* path,
+ virtual ~MtpDatabase();
+
+ static uint32_t getTableForFile(MtpObjectFormat format);
+
+ virtual MtpObjectHandle getObjectHandle(const char* path) = 0;
+ virtual MtpObjectHandle addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified) = 0;
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id) = 0;
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration) = 0;
+
+ virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
- MtpObjectHandle parent,
- MtpStorageID storage,
- uint64_t size,
- time_t modified);
-
- MtpObjectHandle addAudioFile(MtpObjectHandle id);
-
- MtpObjectHandle addAudioFile(MtpObjectHandle id,
- const char* title,
- const char* artist,
- const char* album,
- const char* albumArtist,
- const char* genre,
- const char* composer,
- const char* mimeType,
- int track,
- int year,
- int duration);
-
- MtpObjectHandleList* getObjectList(MtpStorageID storageID,
- MtpObjectFormat format,
- MtpObjectHandle parent);
+ MtpObjectHandle parent) = 0;
- MtpResponseCode getObjectProperty(MtpObjectHandle handle,
- MtpObjectProperty property,
- MtpDataPacket& packet);
+ virtual MtpResponseCode getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) = 0;
- MtpResponseCode getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet);
+ virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet) = 0;
- bool getObjectFilePath(MtpObjectHandle handle,
- MtpString& filePath,
- int64_t& fileLength);
- bool deleteFile(MtpObjectHandle handle);
+ virtual bool getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength) = 0;
+ virtual bool deleteFile(MtpObjectHandle handle) = 0;
// helper for media scanner
- MtpObjectHandle* getFileList(int& outCount);
+ virtual MtpObjectHandle* getFileList(int& outCount) = 0;
+
+ virtual void beginTransaction() = 0;
+ virtual void commitTransaction() = 0;
+ virtual void rollbackTransaction() = 0;
};
}; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 0b99cb19f139..b9eeec5953ca 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -25,9 +25,9 @@
#include <cutils/properties.h>
#include "MtpDebug.h"
-#include "MtpDatabase.h"
#include "MtpProperty.h"
#include "MtpServer.h"
+#include "MtpSqliteDatabase.h"
#include "MtpStorage.h"
#include "MtpStringBuffer.h"
@@ -113,16 +113,20 @@ static const MtpObjectFormat kSupportedPlaybackFormats[] = {
// MTP_FORMAT_PLS_PLAYLIST,
};
-MtpServer::MtpServer(int fd, const char* databasePath)
+MtpServer::MtpServer(int fd, const char* databasePath,
+ int fileGroup, int filePerm, int directoryPerm)
: mFD(fd),
mDatabasePath(databasePath),
mDatabase(NULL),
+ mFileGroup(fileGroup),
+ mFilePermission(filePerm),
+ mDirectoryPermission(directoryPerm),
mSessionID(0),
mSessionOpen(false),
mSendObjectHandle(kInvalidObjectHandle),
mSendObjectFileSize(0)
{
- mDatabase = new MtpDatabase();
+ mDatabase = new MtpSqliteDatabase();
mDatabase->open(databasePath, true);
initObjectProperties();
@@ -536,10 +540,11 @@ MtpResponseCode MtpServer::doSendObjectInfo() {
if (format == MTP_FORMAT_ASSOCIATION) {
mode_t mask = umask(0);
- int ret = mkdir((const char *)path, S_IRWXU | S_IRWXG | S_IRWXO);
+ int ret = mkdir((const char *)path, mDirectoryPermission);
umask(mask);
if (ret && ret != -EEXIST)
return MTP_RESPONSE_GENERAL_ERROR;
+ chown((const char *)path, getuid(), mFileGroup);
} else {
mSendObjectFilePath = path;
// save the handle for the SendObject call, which should follow
@@ -571,12 +576,19 @@ MtpResponseCode MtpServer::doSendObject() {
if (mfr.fd < 0) {
return MTP_RESPONSE_GENERAL_ERROR;
}
+ fchown(mfr.fd, getuid(), mFileGroup);
+ // set permissions
+ mode_t mask = umask(0);
+ fchmod(mfr.fd, mFilePermission);
+ umask(mask);
+
mfr.offset = 0;
mfr.length = mSendObjectFileSize;
// transfer the file
ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
close(mfr.fd);
+
// FIXME - we need to delete mSendObjectHandle from the database if this fails.
LOGV("MTP_RECEIVE_FILE returned %d", ret);
mSendObjectHandle = kInvalidObjectHandle;
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 40329c573835..25635afbe0ea 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -27,7 +27,7 @@
namespace android {
class MtpStorage;
-class MtpDatabase;
+class MtpSqliteDatabase;
class MtpProperty;
class MtpServer {
@@ -39,7 +39,13 @@ private:
// path to our sqlite3 database
const char* mDatabasePath;
- MtpDatabase* mDatabase;
+ MtpSqliteDatabase* mDatabase;
+
+ // group to own new files and folders
+ int mFileGroup;
+ // permissions for new files and directories
+ int mFilePermission;
+ int mDirectoryPermission;
// current session ID
MtpSessionID mSessionID;
@@ -61,7 +67,8 @@ private:
size_t mSendObjectFileSize;
public:
- MtpServer(int fd, const char* databasePath);
+ MtpServer(int fd, const char* databasePath,
+ int fileGroup, int filePerm, int directoryPerm);
virtual ~MtpServer();
void addStorage(const char* filePath);
diff --git a/media/mtp/MtpSqliteDatabase.cpp b/media/mtp/MtpSqliteDatabase.cpp
new file mode 100644
index 000000000000..fa3bdfe7cbfb
--- /dev/null
+++ b/media/mtp/MtpSqliteDatabase.cpp
@@ -0,0 +1,564 @@
+/*
+ * 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_TAG "MtpSqliteDatabase"
+
+#include "MtpDebug.h"
+#include "MtpSqliteDatabase.h"
+#include "MtpDataPacket.h"
+#include "MtpUtils.h"
+#include "SqliteDatabase.h"
+#include "SqliteStatement.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+
+namespace android {
+
+#define FILE_ID_COLUMN 1
+#define FILE_PATH_COLUMN 2
+#define FILE_FORMAT_COLUMN 3
+#define FILE_PARENT_COLUMN 4
+#define FILE_STORAGE_COLUMN 5
+#define FILE_SIZE_COLUMN 6
+#define FILE_MODIFIED_COLUMN 7
+
+#define AUDIO_ID_COLUMN 1
+#define AUDIO_TITLE_COLUMN 2
+#define AUDIO_ARTIST_COLUMN 3
+#define AUDIO_ALBUM_COLUMN 4
+#define AUDIO_ALBUM_ARTIST_COLUMN 5
+#define AUDIO_GENRE_COLUMN 6
+#define AUDIO_COMPOSER_COLUMN 7
+#define AUDIO_TRACK_NUMBER_COLUMN 8
+#define AUDIO_YEAR_COLUMN 9
+#define AUDIO_DURATION_COLUMN 10
+#define AUDIO_USE_COUNT_COLUMN 11
+#define AUDIO_SAMPLE_RATE_COLUMN 12
+#define AUDIO_NUM_CHANNELS_COLUMN 13
+#define AUDIO_AUDIO_WAVE_CODEC_COLUMN 14
+#define AUDIO_AUDIO_BIT_RATE_COLUMN 15
+
+#define FILE_TABLE_CREATE "CREATE TABLE IF NOT EXISTS files (" \
+ "_id INTEGER PRIMARY KEY," \
+ "path TEXT," \
+ "format INTEGER," \
+ "parent INTEGER," \
+ "storage INTEGER," \
+ "size INTEGER," \
+ "date_modified INTEGER" \
+ ");"
+
+#define AUDIO_TABLE_CREATE "CREATE TABLE IF NOT EXISTS audio (" \
+ "id INTEGER PRIMARY KEY," \
+ "title TEXT," \
+ "artist TEXT," \
+ "album TEXT," \
+ "album_artist TEXT," \
+ "genre TEXT," \
+ "composer TEXT," \
+ "track_number INTEGER," \
+ "year INTEGER," \
+ "duration INTEGER," \
+ "use_count INTEGER," \
+ "sample_rate INTEGER," \
+ "num_channels INTEGER," \
+ "audio_wave_codec TEXT," \
+ "audio_bit_rate INTEGER" \
+ ");"
+
+#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
+
+#define FILE_ID_QUERY "SELECT _id,format FROM files WHERE path = ?;"
+#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
+
+#define GET_OBJECT_INFO_QUERY "SELECT storage,format,parent,path,size,date_modified FROM files WHERE _id = ?;"
+#define FILE_INSERT "INSERT INTO files VALUES(?,?,?,?,?,?,?);"
+#define FILE_DELETE "DELETE FROM files WHERE _id = ?;"
+
+#define AUDIO_INSERT "INSERT INTO audio VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
+#define AUDIO_DELETE "DELETE FROM audio WHERE id = ?;"
+
+struct PropertyTableEntry {
+ MtpObjectProperty property;
+ int type;
+ const char* columnName;
+};
+
+static const PropertyTableEntry kPropertyTable[] = {
+ { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, "parent" },
+ { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, "storage" },
+ { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT32, "format" },
+ { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, "path" },
+ { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, "size" },
+ { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, "date_modified" },
+};
+
+static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
+ int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
+ const PropertyTableEntry* entry = kPropertyTable;
+ for (int i = 0; i < count; i++, entry++) {
+ if (entry->property == property) {
+ type = entry->type;
+ columnName = entry->columnName;
+ return true;
+ }
+ }
+ return false;
+}
+
+MtpSqliteDatabase::MtpSqliteDatabase()
+ : mDatabase(NULL),
+ mFileIdQuery(NULL),
+ mFilePathQuery(NULL),
+ mObjectInfoQuery(NULL),
+ mFileInserter(NULL),
+ mFileDeleter(NULL),
+ mAudioInserter(NULL),
+ mAudioDeleter(NULL)
+{
+}
+
+MtpSqliteDatabase::~MtpSqliteDatabase() {
+ delete mDatabase;
+ delete mFileIdQuery;
+ delete mFilePathQuery;
+ delete mObjectInfoQuery;
+ delete mFileInserter;
+ delete mFileDeleter;
+ delete mAudioInserter;
+ delete mAudioDeleter;
+}
+
+bool MtpSqliteDatabase::open(const char* path, bool create) {
+ mDatabase = new SqliteDatabase;
+
+ if (!mDatabase->open(path, create))
+ goto fail;
+
+ // create tables and indices if necessary
+ if (!mDatabase->exec(FILE_TABLE_CREATE)) {
+ LOGE("could not create file table");
+ goto fail;
+ }
+ if (!mDatabase->exec(PATH_INDEX_CREATE)) {
+ LOGE("could not path index on file table");
+ goto fail;
+ }
+ if (!mDatabase->exec(AUDIO_TABLE_CREATE)) {
+ LOGE("could not create file table");
+ goto fail;
+ }
+
+ if (!mFileIdQuery) {
+ mFileIdQuery = new SqliteStatement(mDatabase);
+ if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
+ LOGE("could not compile FILE_ID_QUERY");
+ goto fail;
+ }
+ }
+ if (!mFilePathQuery) {
+ mFilePathQuery = new SqliteStatement(mDatabase);
+ if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
+ LOGE("could not compile FILE_PATH_QUERY");
+ goto fail;
+ }
+ }
+ if (!mObjectInfoQuery) {
+ mObjectInfoQuery = new SqliteStatement(mDatabase);
+ if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
+ LOGE("could not compile GET_OBJECT_INFO_QUERY");
+ goto fail;
+ }
+ }
+ if (!mFileInserter) {
+ mFileInserter = new SqliteStatement(mDatabase);
+ if (!mFileInserter->prepare(FILE_INSERT)) {
+ LOGE("could not compile FILE_INSERT\n");
+ goto fail;
+ }
+ }
+ if (!mFileDeleter) {
+ mFileDeleter = new SqliteStatement(mDatabase);
+ if (!mFileDeleter->prepare(FILE_DELETE)) {
+ LOGE("could not compile FILE_DELETE\n");
+ goto fail;
+ }
+ }
+ if (!mAudioInserter) {
+ mAudioInserter = new SqliteStatement(mDatabase);
+ if (!mAudioInserter->prepare(AUDIO_INSERT)) {
+ LOGE("could not compile AUDIO_INSERT\n");
+ goto fail;
+ }
+ }
+ if (!mAudioDeleter) {
+ mAudioDeleter = new SqliteStatement(mDatabase);
+ if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
+ LOGE("could not compile AUDIO_DELETE\n");
+ goto fail;
+ }
+ }
+
+ return true;
+
+fail:
+ delete mDatabase;
+ delete mFileIdQuery;
+ delete mFilePathQuery;
+ delete mObjectInfoQuery;
+ delete mFileInserter;
+ delete mFileDeleter;
+ delete mAudioInserter;
+ delete mAudioDeleter;
+ mDatabase = NULL;
+ mFileIdQuery = NULL;
+ mFilePathQuery = NULL;
+ mObjectInfoQuery = NULL;
+ mFileInserter = NULL;
+ mFileDeleter = NULL;
+ mAudioInserter = NULL;
+ mAudioDeleter = NULL;
+ return false;
+}
+
+void MtpSqliteDatabase::close() {
+ if (mDatabase) {
+ mDatabase->close();
+ mDatabase = NULL;
+ }
+}
+
+MtpObjectHandle MtpSqliteDatabase::getObjectHandle(const char* path) {
+ mFileIdQuery->reset();
+ mFileIdQuery->bind(1, path);
+ if (mFileIdQuery->step()) {
+ int row = mFileIdQuery->getColumnInt(0);
+ if (row > 0) {
+ MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
+ row |= getTableForFile(format);
+ return row;
+ }
+ }
+
+ return 0;
+}
+
+MtpObjectHandle MtpSqliteDatabase::addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified) {
+ mFileInserter->bind(FILE_PATH_COLUMN, path);
+ mFileInserter->bind(FILE_FORMAT_COLUMN, format);
+ mFileInserter->bind(FILE_PARENT_COLUMN, parent);
+ mFileInserter->bind(FILE_STORAGE_COLUMN, storage);
+ mFileInserter->bind(FILE_SIZE_COLUMN, size);
+ mFileInserter->bind(FILE_MODIFIED_COLUMN, modified);
+ mFileInserter->step();
+ mFileInserter->reset();
+ int result = mDatabase->lastInsertedRow();
+ return (result <= 0 ? kInvalidObjectHandle : result);
+}
+
+MtpObjectHandle MtpSqliteDatabase::addAudioFile(MtpObjectHandle handle) {
+ mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
+ mAudioInserter->step();
+ mAudioInserter->reset();
+ int result = mDatabase->lastInsertedRow();
+ handle |= kObjectHandleTableAudio;
+ return (result > 0 ? handle : kInvalidObjectHandle);
+}
+
+MtpObjectHandle MtpSqliteDatabase::addAudioFile(MtpObjectHandle handle,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration) {
+ mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
+ if (title) mAudioInserter->bind(AUDIO_TITLE_COLUMN, title);
+ if (artist) mAudioInserter->bind(AUDIO_ARTIST_COLUMN, artist);
+ if (album) mAudioInserter->bind(AUDIO_ALBUM_COLUMN, album);
+ if (albumArtist) mAudioInserter->bind(AUDIO_ALBUM_ARTIST_COLUMN, albumArtist);
+ if (genre) mAudioInserter->bind(AUDIO_GENRE_COLUMN, genre);
+ if (composer) mAudioInserter->bind(AUDIO_COMPOSER_COLUMN, composer);
+ if (track) mAudioInserter->bind(AUDIO_TRACK_NUMBER_COLUMN, track);
+ if (year) mAudioInserter->bind(AUDIO_YEAR_COLUMN, year);
+ if (duration) mAudioInserter->bind(AUDIO_DURATION_COLUMN, duration);
+ mAudioInserter->step();
+ mAudioInserter->reset();
+ int result = mDatabase->lastInsertedRow();
+ if (result <= 0)
+ return kInvalidObjectHandle;
+ result |= kObjectHandleTableAudio;
+ return result;
+}
+
+MtpObjectHandleList* MtpSqliteDatabase::getObjectList(MtpStorageID storageID,
+ MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ bool whereStorage = (storageID != 0xFFFFFFFF);
+ bool whereFormat = (format != 0);
+ bool whereParent = (parent != 0);
+ char intBuffer[20];
+
+ MtpString query("SELECT _id,format FROM files");
+ if (whereStorage || whereFormat || whereParent)
+ query += " WHERE";
+ if (whereStorage) {
+ snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
+ query += " storage = ";
+ query += intBuffer;
+ }
+ if (whereFormat) {
+ snprintf(intBuffer, sizeof(intBuffer), "%d", format);
+ if (whereStorage)
+ query += " AND";
+ query += " format = ";
+ query += intBuffer;
+ }
+ if (whereParent) {
+ if (parent != MTP_PARENT_ROOT)
+ parent &= kObjectHandleIndexMask;
+ snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
+ if (whereStorage || whereFormat)
+ query += " AND";
+ query += " parent = ";
+ query += intBuffer;
+ }
+ query += ";";
+
+ SqliteStatement stmt(mDatabase);
+ LOGV("%s", (const char *)query);
+ stmt.prepare(query);
+
+ MtpObjectHandleList* list = new MtpObjectHandleList();
+ while (!stmt.isDone()) {
+ if (stmt.step()) {
+ int index = stmt.getColumnInt(0);
+ LOGV("stmt.getColumnInt returned %d", index);
+ if (index > 0) {
+ MtpObjectFormat format = stmt.getColumnInt(1);
+ index |= getTableForFile(format);
+ list->push(index);
+ }
+ }
+ }
+ LOGV("list size: %d", list->size());
+ return list;
+}
+
+
+MtpResponseCode MtpSqliteDatabase::getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ int type;
+ const char* columnName;
+ char intBuffer[20];
+
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+
+ if (!getPropertyInfo(property, type, columnName))
+ return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
+ snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
+
+ MtpString query("SELECT ");
+ query += columnName;
+ query += " FROM files WHERE _id = ";
+ query += intBuffer;
+ query += ";";
+
+ SqliteStatement stmt(mDatabase);
+ LOGV("%s", (const char *)query);
+ stmt.prepare(query);
+
+ if (!stmt.step())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ switch (type) {
+ case MTP_TYPE_INT8:
+ packet.putInt8(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT8:
+ packet.putUInt8(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT16:
+ packet.putInt16(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT16:
+ packet.putUInt16(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT32:
+ packet.putInt32(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT32:
+ packet.putUInt32(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT64:
+ packet.putInt64(stmt.getColumnInt64(0));
+ break;
+ case MTP_TYPE_UINT64:
+ packet.putUInt64(stmt.getColumnInt64(0));
+ break;
+ case MTP_TYPE_STR:
+ packet.putString(stmt.getColumnString(0));
+ break;
+ default:
+ LOGE("unsupported object type\n");
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpSqliteDatabase::getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet) {
+ char date[20];
+
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+
+ mObjectInfoQuery->reset();
+ mObjectInfoQuery->bind(1, handle);
+ if (!mObjectInfoQuery->step())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
+ MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
+ MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
+ // extract name from path. do we want a separate database entry for this?
+ const char* name = mObjectInfoQuery->getColumnString(3);
+ const char* lastSlash = strrchr(name, '/');
+ if (lastSlash)
+ name = lastSlash + 1;
+ int64_t size = mObjectInfoQuery->getColumnInt64(4);
+ time_t modified = mObjectInfoQuery->getColumnInt(5);
+ int associationType = (format == MTP_FORMAT_ASSOCIATION ?
+ MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
+ MTP_ASSOCIATION_TYPE_UNDEFINED);
+
+ LOGV("storageID: %d, format: %d, parent: %d", storageID, format, parent);
+
+ packet.putUInt32(storageID);
+ packet.putUInt16(format);
+ packet.putUInt16(0); // protection status
+ packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
+ packet.putUInt16(0); // thumb format
+ packet.putUInt32(0); // thumb compressed size
+ packet.putUInt32(0); // thumb pix width
+ packet.putUInt32(0); // thumb pix height
+ packet.putUInt32(0); // image pix width
+ packet.putUInt32(0); // image pix height
+ packet.putUInt32(0); // image bit depth
+ packet.putUInt32(parent);
+ packet.putUInt16(associationType);
+ packet.putUInt32(0); // association desc
+ packet.putUInt32(0); // sequence number
+ packet.putString(name); // file name
+ packet.putEmptyString();
+ formatDateTime(modified, date, sizeof(date));
+ packet.putString(date); // date modified
+ packet.putEmptyString(); // keywords
+
+ return MTP_RESPONSE_OK;
+}
+
+bool MtpSqliteDatabase::getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength) {
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+ mFilePathQuery->reset();
+ mFilePathQuery->bind(1, handle);
+ if (!mFilePathQuery->step())
+ return false;
+
+ const char* path = mFilePathQuery->getColumnString(0);
+ if (!path)
+ return false;
+ filePath = path;
+ fileLength = mFilePathQuery->getColumnInt64(1);
+ return true;
+}
+
+bool MtpSqliteDatabase::deleteFile(MtpObjectHandle handle) {
+ uint32_t table = handle & kObjectHandleTableMask;
+ handle &= kObjectHandleIndexMask;
+ mFileDeleter->bind(1, handle);
+ mFileDeleter->step();
+ mFileDeleter->reset();
+ if (table == kObjectHandleTableAudio) {
+ mAudioDeleter->bind(1, handle);
+ mAudioDeleter->step();
+ mAudioDeleter->reset();
+ }
+
+ return true;
+}
+
+MtpObjectHandle* MtpSqliteDatabase::getFileList(int& outCount) {
+ MtpObjectHandle* result = NULL;
+ int count = 0;
+ SqliteStatement stmt(mDatabase);
+ stmt.prepare("SELECT count(*) FROM files;");
+
+ MtpObjectHandleList* list = new MtpObjectHandleList();
+ if (stmt.step())
+ count = stmt.getColumnInt(0);
+
+ if (count > 0) {
+ result = new MtpObjectHandle[count];
+ memset(result, 0, count * sizeof(*result));
+ SqliteStatement stmt2(mDatabase);
+ stmt2.prepare("SELECT _id,format FROM files;");
+
+ for (int i = 0; i < count; i++) {
+ if (!stmt2.step()) {
+ LOGW("getFileList ended early");
+ count = i;
+ break;
+ }
+ MtpObjectHandle handle = stmt2.getColumnInt(0);
+ MtpObjectFormat format = stmt2.getColumnInt(1);
+ handle |= getTableForFile(format);
+ result[i] = handle;
+ }
+ }
+ outCount = count;
+ return result;
+}
+
+void MtpSqliteDatabase::beginTransaction() {
+ mDatabase->beginTransaction();
+}
+
+void MtpSqliteDatabase::commitTransaction() {
+ mDatabase->commitTransaction();
+}
+
+void MtpSqliteDatabase::rollbackTransaction() {
+ mDatabase->rollbackTransaction();
+}
+
+} // namespace android
diff --git a/media/mtp/MtpSqliteDatabase.h b/media/mtp/MtpSqliteDatabase.h
new file mode 100644
index 000000000000..74626a862479
--- /dev/null
+++ b/media/mtp/MtpSqliteDatabase.h
@@ -0,0 +1,96 @@
+/*
+ * 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 _MTP_SQLITE_DATABASE_H
+#define _MTP_SQLITE_DATABASE_H
+
+#include "MtpTypes.h"
+#include "MtpDatabase.h"
+
+class SqliteDatabase;
+
+namespace android {
+
+class MtpDataPacket;
+class SqliteStatement;
+
+class MtpSqliteDatabase : public MtpDatabase {
+private:
+ SqliteDatabase* mDatabase;
+ SqliteStatement* mFileIdQuery;
+ SqliteStatement* mFilePathQuery;
+ SqliteStatement* mObjectInfoQuery;
+ SqliteStatement* mFileInserter;
+ SqliteStatement* mFileDeleter;
+ SqliteStatement* mAudioInserter;
+ SqliteStatement* mAudioDeleter;
+
+public:
+ MtpSqliteDatabase();
+ virtual ~MtpSqliteDatabase();
+
+ bool open(const char* path, bool create);
+ void close();
+
+ virtual MtpObjectHandle getObjectHandle(const char* path);
+ virtual MtpObjectHandle addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified);
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id);
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration);
+
+ virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
+ MtpObjectFormat format,
+ MtpObjectHandle parent);
+
+ virtual MtpResponseCode getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet);
+
+ virtual bool getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength);
+ virtual bool deleteFile(MtpObjectHandle handle);
+
+ // helper for media scanner
+ virtual MtpObjectHandle* getFileList(int& outCount);
+
+ virtual void beginTransaction();
+ virtual void commitTransaction();
+ virtual void rollbackTransaction();
+};
+
+}; // namespace android
+
+#endif // _MTP_SQLITE_DATABASE_H
diff --git a/media/mtp/SqliteDatabase.h b/media/mtp/SqliteDatabase.h
index 56dd9dd86647..7d008f9104a9 100644
--- a/media/mtp/SqliteDatabase.h
+++ b/media/mtp/SqliteDatabase.h
@@ -29,8 +29,8 @@ public:
SqliteDatabase();
virtual ~SqliteDatabase();
- virtual bool open(const char* path, bool create);
- virtual void close();
+ bool open(const char* path, bool create);
+ void close();
bool exec(const char* sql);
int lastInsertedRow();
diff --git a/media/mtp/mtptest.cpp b/media/mtp/mtptest.cpp
index 9062494f8c74..af0f77fde057 100644
--- a/media/mtp/mtptest.cpp
+++ b/media/mtp/mtptest.cpp
@@ -27,6 +27,7 @@
#include "MtpServer.h"
#include "MtpStorage.h"
#include "f_mtp.h"
+#include "private/android_filesystem_config.h"
using namespace android;
@@ -76,7 +77,7 @@ int main(int argc, char* argv[]) {
enable_usb_function("usb_mass_storage", false);
enable_usb_function("mtp", true);
- MtpServer server(fd, "/data/data/mtp/mtp.db");
+ MtpServer server(fd, "/data/data/mtp/mtp.db", AID_SDCARD_RW, 0664, 0775);
server.addStorage(storagePath);
server.scanStorage();
server.run();
diff --git a/media/mtp/scantest.cpp b/media/mtp/scantest.cpp
index f910bb63ead3..3702a5d06e6a 100644
--- a/media/mtp/scantest.cpp
+++ b/media/mtp/scantest.cpp
@@ -16,7 +16,7 @@
#include <stdio.h>
-#include "MtpDatabase.h"
+#include "MtpSqliteDatabase.h"
#include "MtpMediaScanner.h"
using namespace android;
@@ -27,7 +27,7 @@ int main(int argc, char* argv[]) {
return -1;
}
- MtpDatabase* database = new MtpDatabase();
+ MtpSqliteDatabase* database = new MtpSqliteDatabase();
database->open("scantest.db", true);
MtpMediaScanner scanner(1, argv[1], database);
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 8c621b601736..fe8ed0003a0a 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -7,7 +7,8 @@ include $(CLEAR_VARS)
#
LOCAL_SRC_FILES:= \
activity.cpp \
- input.cpp
+ input.cpp \
+ native_window.cpp
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
new file mode 100644
index 000000000000..448cbfccb666
--- /dev/null
+++ b/native/android/native_window.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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_TAG "Surface"
+#include <utils/Log.h>
+
+#include <android/native_window.h>
+#include <surfaceflinger/Surface.h>
+
+using android::Surface;
+
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+ int value;
+ int res = window->query(window, what, &value);
+ return res < 0 ? res : value;
+}
+
+int32_t ANativeWindow_getWidth(ANativeWindow* window) {
+ return getWindowProp(window, NATIVE_WINDOW_WIDTH);
+}
+
+int32_t ANativeWindow_getHeight(ANativeWindow* window) {
+ return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
+}
+
+int32_t ANativeWindow_getFormat(ANativeWindow* window) {
+ return getWindowProp(window, NATIVE_WINDOW_FORMAT);
+}
+
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
+ int32_t height, int32_t format) {
+ native_window_set_buffers_geometry(window, width, height, format);
+ return 0;
+}
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index c5c8f9defda3..bf5c641fc162 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -24,15 +24,12 @@
#include <jni.h>
#include <android/input.h>
+#include <android/native_window.h>
#ifdef __cplusplus
extern "C" {
#endif
-// Temporary until native surface API is defined.
-struct ASurfaceHolder;
-typedef struct ASurfaceHolder ASurfaceHolder;
-
struct ANativeActivityCallbacks;
/**
@@ -129,30 +126,20 @@ typedef struct ANativeActivityCallbacks {
void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus);
/**
- * The drawing surface for this native activity has been created. You
- * can use the given surface object to start drawing. NOTE: surface
- * drawing API is not yet defined.
- */
- void (*onSurfaceCreated)(ANativeActivity* activity, ASurfaceHolder* surface);
-
- /**
- * The drawing surface for this native activity has changed. The surface
- * given here is guaranteed to be the same as the one last given to
- * onSurfaceCreated. This is simply to inform you about interesting
- * changed to that surface.
+ * The drawing window for this native activity has been created. You
+ * can use the given native window object to start drawing.
*/
- void (*onSurfaceChanged)(ANativeActivity* activity, ASurfaceHolder* surface,
- int format, int width, int height);
+ void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window);
/**
- * The drawing surface for this native activity is going to be destroyed.
- * You MUST ensure that you do not touch the surface object after returning
- * from this function: in the common case of drawing to the surface from
+ * The drawing window for this native activity is going to be destroyed.
+ * You MUST ensure that you do not touch the window object after returning
+ * from this function: in the common case of drawing to the window from
* another thread, that means the implementation of this callback must
* properly synchronize with the other thread to stop its drawing before
* returning from here.
*/
- void (*onSurfaceDestroyed)(ANativeActivity* activity, ASurfaceHolder* surface);
+ void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window);
/**
* The input queue for this native activity's window has been created.
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index e6d5fea0a2b1..678ba3d7c7e2 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -22,9 +22,51 @@
extern "C" {
#endif
+/*
+ * Pixel formats that a window can use.
+ */
+enum {
+ WINDOW_FORMAT_RGBA_8888 = 1,
+ WINDOW_FORMAT_RGBX_8888 = 2,
+ WINDOW_FORMAT_RGB_565 = 4,
+};
+
struct ANativeWindow;
typedef struct ANativeWindow ANativeWindow;
+/*
+ * Return the current width in pixels of the window surface. Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getWidth(ANativeWindow* window);
+
+/*
+ * Return the current height in pixels of the window surface. Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getHeight(ANativeWindow* window);
+
+/*
+ * Return the current pixel format of the window surface. Returns a
+ * negative value on error.
+ */
+int32_t ANativeWindow_getFormat(ANativeWindow* window);
+
+/*
+ * Change the format and size of the window buffers.
+ *
+ * The width and height control the number of pixels in the buffers, not the
+ * dimensions of the window on screen. If these are different than the
+ * window's physical size, then it buffer will be scaled to match that size
+ * when compositing it to the screen.
+ *
+ * The format may be one of the window format constants above.
+ *
+ * For all of these parameters, if 0 is supplied than the window's base
+ * value will come back in force.
+ */
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
+ int32_t height, int32_t format);
#ifdef __cplusplus
};
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index ba09d082feec..714fd3eec7c5 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -1045,6 +1045,10 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
+ if (share_list != EGL_NO_CONTEXT) {
+ egl_context_t* const c = get_context(share_list);
+ share_list = c->context;
+ }
EGLContext context = cnx->egl.eglCreateContext(
dp->disp[i].dpy, dp->disp[i].config[index],
share_list, attrib_list);
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index f031c79cd33e..ef66841f2792 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -181,4 +181,3 @@ JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv *
{
background = 1.0f - background;
}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index 4ddd45ca97e1..07bcce7056be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -584,7 +584,7 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks
}
if (expanded == null) {
String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id);
- Slog.e(TAG, "couldn't inflate view for notification " + ident);
+ Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
return null;
} else {
content.addView(expanded);
diff --git a/tests/HwAccelerationTest/res/drawable/sunset1.jpg b/tests/HwAccelerationTest/res/drawable/sunset1.jpg
new file mode 100644
index 000000000000..92851f3df924
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/sunset1.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/sunset2.png b/tests/HwAccelerationTest/res/drawable/sunset2.png
new file mode 100644
index 000000000000..3258ee745389
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/sunset2.png
Binary files differ