Merge changes Ib809d4c5,I05d69da4 into honeycomb
* changes:
This makes the events at the edge of the screen find the button.
some touch event debugging
diff --git a/api/current.xml b/api/current.xml
index 112c147..610542d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -85932,6 +85932,97 @@
</parameter>
</constructor>
</class>
+<class name="SurfaceTexture"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SurfaceTexture"
+ type="android.graphics.SurfaceTexture"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="texName" type="int">
+</parameter>
+</constructor>
+<method name="setOnFrameAvailableListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="l" type="android.graphics.SurfaceTexture.OnFrameAvailableListener">
+</parameter>
+</method>
+<method name="updateTexImage"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<interface name="SurfaceTexture.OnFrameAvailableListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onFrameAvailable"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="surfaceTexture" type="android.graphics.SurfaceTexture">
+</parameter>
+</method>
+</interface>
+<class name="SurfaceTexture.OutOfResourcesException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SurfaceTexture.OutOfResourcesException"
+ type="android.graphics.SurfaceTexture.OutOfResourcesException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="SurfaceTexture.OutOfResourcesException"
+ type="android.graphics.SurfaceTexture.OutOfResourcesException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</constructor>
+</class>
<class name="SweepGradient"
extends="android.graphics.Shader"
abstract="false"
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index e604e6b..54bf4af 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -226,6 +226,24 @@
public static final int HEALTH_PULSE_OXIMETER = 0x0914;
public static final int HEALTH_PULSE_RATE = 0x0918;
public static final int HEALTH_DATA_DISPLAY = 0x091C;
+
+ // Devices in PERIPHERAL major class
+ /**
+ * @hide
+ */
+ public static final int PERIPHERAL_NON_KEYBOARD_NON_POINTING = 0x0500;
+ /**
+ * @hide
+ */
+ public static final int PERIPHERAL_KEYBOARD = 0x0540;
+ /**
+ * @hide
+ */
+ public static final int PERIPHERAL_POINTING = 0x0580;
+ /**
+ * @hide
+ */
+ public static final int PERIPHERAL_KEYBOARD_POINTING = 0x05C0;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e15d003..24217d7 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -239,7 +239,7 @@
public static final String EXTRA_PAIRING_VARIANT =
"android.bluetooth.device.extra.PAIRING_VARIANT";
/** @hide */
- public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
+ public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
/**
* Broadcast Action: This intent is used to broadcast the {@link UUID}
@@ -276,58 +276,113 @@
public static final String ACTION_PAIRING_CANCEL =
"android.bluetooth.device.action.PAIRING_CANCEL";
- /** A bond attempt succeeded
- * @hide */
+ /**
+ * A bond attempt succeeded
+ * @hide
+ */
public static final int BOND_SUCCESS = 0;
- /** A bond attempt failed because pins did not match, or remote device did
+
+ /**
+ * A bond attempt failed because pins did not match, or remote device did
* not respond to pin request in time
- * @hide */
+ * @hide
+ */
public static final int UNBOND_REASON_AUTH_FAILED = 1;
- /** A bond attempt failed because the other side explicitly rejected
+
+ /**
+ * A bond attempt failed because the other side explicitly rejected
* bonding
- * @hide */
+ * @hide
+ */
public static final int UNBOND_REASON_AUTH_REJECTED = 2;
- /** A bond attempt failed because we canceled the bonding process
- * @hide */
+
+ /**
+ * A bond attempt failed because we canceled the bonding process
+ * @hide
+ */
public static final int UNBOND_REASON_AUTH_CANCELED = 3;
- /** A bond attempt failed because we could not contact the remote device
- * @hide */
+
+ /**
+ * A bond attempt failed because we could not contact the remote device
+ * @hide
+ */
public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
- /** A bond attempt failed because a discovery is in progress
- * @hide */
+
+ /**
+ * A bond attempt failed because a discovery is in progress
+ * @hide
+ */
public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
- /** A bond attempt failed because of authentication timeout
- * @hide */
+
+ /**
+ * A bond attempt failed because of authentication timeout
+ * @hide
+ */
public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
- /** A bond attempt failed because of repeated attempts
- * @hide */
+
+ /**
+ * A bond attempt failed because of repeated attempts
+ * @hide
+ */
public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
- /** A bond attempt failed because we received an Authentication Cancel
- * by remote end
- * @hide */
+
+ /**
+ * A bond attempt failed because we received an Authentication Cancel
+ * by remote end
+ * @hide
+ */
public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
- /** An existing bond was explicitly revoked
- * @hide */
+
+ /**
+ * An existing bond was explicitly revoked
+ * @hide
+ */
public static final int UNBOND_REASON_REMOVED = 9;
- /** The user will be prompted to enter a pin
- * @hide */
+ /**
+ * The user will be prompted to enter a pin
+ * @hide
+ */
public static final int PAIRING_VARIANT_PIN = 0;
- /** The user will be prompted to enter a passkey
- * @hide */
+
+ /**
+ * The user will be prompted to enter a passkey
+ * @hide
+ */
public static final int PAIRING_VARIANT_PASSKEY = 1;
- /** The user will be prompted to confirm the passkey displayed on the screen
- * @hide */
+
+ /**
+ * The user will be prompted to confirm the passkey displayed on the screen
+ * @hide
+ */
public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
- /** The user will be prompted to accept or deny the incoming pairing request
- * @hide */
+
+ /**
+ * The user will be prompted to accept or deny the incoming pairing request
+ * @hide
+ */
public static final int PAIRING_VARIANT_CONSENT = 3;
- /** The user will be prompted to enter the passkey displayed on remote device
- * @hide */
+
+ /**
+ * The user will be prompted to enter the passkey displayed on remote device
+ * This is used for Bluetooth 2.1 pairing.
+ * @hide
+ */
public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
- /** The user will be prompted to accept or deny the OOB pairing request
- * @hide */
- public static final int PAIRING_VARIANT_OOB_CONSENT = 5;
+
+ /**
+ * The user will be prompted to enter the PIN displayed on remote device.
+ * This is used for Bluetooth 2.0 pairing.
+ * @hide
+ */
+ public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
+
+ /**
+ * The user will be prompted to accept or deny the OOB pairing request
+ * @hide
+ */
+ public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
+
/**
* Used as an extra field in {@link #ACTION_UUID} intents,
* Contains the {@link android.os.ParcelUuid}s of the remote device which
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 80a80bd..21144f2 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -149,10 +149,6 @@
newState == BluetoothInputDevice.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
- } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
- Message msg = new Message();
- msg.what = AUTO_CONNECT_PROFILES;
- sendMessage(msg);
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
// This is technically not needed, but we can get stuck sometimes.
// For example, if incoming A2DP fails, we are not informed by Bluez
diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java
index 2cb2aec..16becf5 100644
--- a/core/java/android/database/BulkCursorToCursorAdaptor.java
+++ b/core/java/android/database/BulkCursorToCursorAdaptor.java
@@ -154,7 +154,10 @@
false /* the window will be accessed across processes */));
if (mCount != -1) {
mPos = -1;
- mWindow = null;
+ if (mWindow != null) {
+ mWindow.close();
+ mWindow = null;
+ }
// super.requery() will call onChanged. Do it here instead of relying on the
// observer from the far side so that observers can see a correct value for mCount
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index d15fb88..bd78063 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -17,12 +17,14 @@
package android.database;
import android.content.res.Resources;
+import android.database.sqlite.DatabaseObjectNotClosedException;
import android.database.sqlite.SQLiteClosable;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.StrictMode;
import android.util.Log;
import android.util.SparseIntArray;
@@ -45,6 +47,7 @@
private int nWindow;
private int mStartPos;
+ private final Throwable mStackTrace;
/**
* Creates a new empty window.
@@ -56,6 +59,7 @@
int rslt = native_init(sCursorWindowSize, localWindow);
printDebugMsgIfError(rslt);
recordNewWindow(Binder.getCallingPid(), nWindow);
+ mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
}
private void printDebugMsgIfError(int rslt) {
@@ -561,7 +565,16 @@
@Override
protected void finalize() {
- // Just in case someone forgot to call close...
+ if (nWindow == 0) {
+ return;
+ }
+ if (StrictMode.vmSqliteObjectLeaksEnabled()) {
+ StrictMode.onSqliteObjectLeaked(
+ "Releasing cursor in a finalizer. Please ensure " +
+ "that you explicitly call close() on your cursor: ",
+ mStackTrace);
+ }
+ recordClosingOfWindow(nWindow);
close_native();
}
@@ -593,6 +606,7 @@
IBinder nativeBinder = source.readStrongBinder();
mStartPos = source.readInt();
int rslt = native_init(nativeBinder);
+ mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
printDebugMsgIfError(rslt);
}
@@ -607,8 +621,7 @@
@Override
protected void onAllReferencesReleased() {
- int windowId = nWindow;
- recordClosingOfWindow(Binder.getCallingPid(), nWindow);
+ recordClosingOfWindow(nWindow);
close_native();
}
@@ -623,7 +636,7 @@
}
}
- private void recordClosingOfWindow(int pid, int window) {
+ private void recordClosingOfWindow(int window) {
synchronized (sWindowToPidMap) {
if (sWindowToPidMap.size() == 0) {
// this means we are not in the ContentProvider.
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 57a18bc..b1c84a1 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -958,13 +958,7 @@
sBlockSize = new StatFs("/data").getBlockSize();
}
sqliteDatabase.setPageSize(sBlockSize);
- //STOPSHIP - uncomment the following line
- //sqliteDatabase.setJournalMode(path, "TRUNCATE");
- // STOPSHIP remove the following lines
- if (!path.equalsIgnoreCase(MEMORY_DB_PATH)) {
- sqliteDatabase.enableWriteAheadLogging();
- }
- // END STOPSHIP
+ sqliteDatabase.setJournalMode(path, "TRUNCATE");
// add this database to the list of databases opened in this process
synchronized(mActiveDatabases) {
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index c04bb52..ae729d2d 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -493,7 +493,7 @@
mWakeLock.acquire();
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
- intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
@@ -523,6 +523,9 @@
String pendingOutgoingAddress =
mBluetoothService.getPendingOutgoingBonding();
+ BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
+ int btDeviceClass = btClass.getDeviceClass();
+
if (address.equals(pendingOutgoingAddress)) {
// we initiated the bonding
@@ -533,10 +536,8 @@
return;
}
- BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
-
// try 0000 once if the device looks dumb
- switch (btClass.getDeviceClass()) {
+ switch (btDeviceClass) {
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
@@ -546,6 +547,27 @@
if (mBluetoothService.attemptAutoPair(address)) return;
}
}
+
+ // STOPSHIP: Hack for MOT keyboards
+ boolean motKeyboard = false;
+ String name = mBluetoothService.getRemoteName(address);
+ if (name == null && address.startsWith("00:0F:F6") ||
+ (name != null && name.startsWith("Motorola"))) {
+ motKeyboard = true;
+ }
+
+ if (!motKeyboard) {
+ if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD ||
+ btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) {
+ // Its a keyboard. Follow the HID spec recommendation of creating the
+ // passkey and displaying it to the user.
+ // Generate a variable PIN. This is not truly random but good enough.
+ int pin = (int) Math.floor(Math.random() * 10000);
+ sendDisplayPinIntent(address, pin);
+ return;
+ }
+ }
+
// Acquire wakelock during PIN code request to bring up LCD display
mWakeLock.acquire();
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
@@ -565,7 +587,7 @@
mWakeLock.acquire();
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
- intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
@@ -573,6 +595,19 @@
mWakeLock.release();
}
+ private void sendDisplayPinIntent(String address, int pin) {
+ // Acquire wakelock during PIN code request to bring up LCD display
+ mWakeLock.acquire();
+ Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ //Release wakelock to allow the LCD to go off after the PIN popup notifcation.
+ mWakeLock.release();
+ }
+
private void onRequestOobData(String objectPath , int nativeData) {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 67b22fa..311002c 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -85,7 +85,7 @@
protected void setupRenderer(boolean record) {
if (record) {
- mRenderer = nCreateDisplayListRenderer();
+ mRenderer = nGetDisplayListRenderer(mRenderer);
} else {
mRenderer = nCreateRenderer();
}
@@ -93,28 +93,33 @@
if (mRenderer == 0) {
throw new IllegalStateException("Could not create GLES20Canvas renderer");
} else {
- if (mFinalizer == null) {
- mFinalizer = new CanvasFinalizer(mRenderer);
- } else {
- mFinalizer.replaceNativeObject(mRenderer);
- }
+ mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer);
}
}
- private native int nCreateRenderer();
- private native int nCreateDisplayListRenderer();
-
+ private native int nCreateRenderer();
+ private static native int nGetDisplayListRenderer(int renderer);
private static native void nDestroyRenderer(int renderer);
private static class CanvasFinalizer {
int mRenderer;
- CanvasFinalizer(int renderer) {
+ // Factory method returns new instance if old one is null, or old instance
+ // otherwise, destroying native renderer along the way as necessary
+ static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) {
+ if (oldFinalizer == null) {
+ return new CanvasFinalizer(renderer);
+ }
+ oldFinalizer.replaceNativeObject(renderer);
+ return oldFinalizer;
+ }
+
+ private CanvasFinalizer(int renderer) {
mRenderer = renderer;
}
- void replaceNativeObject(int newRenderer) {
- if (mRenderer != 0) {
+ private void replaceNativeObject(int newRenderer) {
+ if (mRenderer != 0 && newRenderer != mRenderer) {
nDestroyRenderer(mRenderer);
}
mRenderer = newRenderer;
@@ -199,10 +204,10 @@
///////////////////////////////////////////////////////////////////////////
int getDisplayList() {
- return nCreateDisplayList(mRenderer);
+ return nGetDisplayList(mRenderer);
}
- private native int nCreateDisplayList(int renderer);
+ private native int nGetDisplayList(int renderer);
static void destroyDisplayList(int displayList) {
nDestroyDisplayList(displayList);
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index bd18fdd..c548659 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -70,11 +70,7 @@
mRecorded = true;
mNativeDisplayList = mCanvas.getDisplayList();
- if (mFinalizer == null) {
- mFinalizer = new DisplayListFinalizer(mNativeDisplayList);
- } else {
- mFinalizer.replaceNativeObject(mNativeDisplayList);
- }
+ mFinalizer = DisplayListFinalizer.getFinalizer(mFinalizer, mNativeDisplayList);
}
}
@@ -86,12 +82,23 @@
private static class DisplayListFinalizer {
int mNativeDisplayList;
- DisplayListFinalizer(int nativeDisplayList) {
+ // Factory method returns new instance if old one is null, or old instance
+ // otherwise, destroying native display list along the way as necessary
+ static DisplayListFinalizer getFinalizer(DisplayListFinalizer oldFinalizer,
+ int nativeDisplayList) {
+ if (oldFinalizer == null) {
+ return new DisplayListFinalizer(nativeDisplayList);
+ }
+ oldFinalizer.replaceNativeObject(nativeDisplayList);
+ return oldFinalizer;
+ }
+
+ private DisplayListFinalizer(int nativeDisplayList) {
mNativeDisplayList = nativeDisplayList;
}
- void replaceNativeObject(int newNativeDisplayList) {
- if (mNativeDisplayList != 0) {
+ private void replaceNativeObject(int newNativeDisplayList) {
+ if (mNativeDisplayList != 0 && mNativeDisplayList != newNativeDisplayList) {
GLES20Canvas.destroyDisplayList(mNativeDisplayList);
}
mNativeDisplayList = newNativeDisplayList;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bd268e1..d068d82 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4599,6 +4599,8 @@
if (isEnterActionKey(keyCode)) {
switchOutDrawHistory();
+ boolean wantsKeyEvents = nativeCursorNodePointer() == 0
+ || nativeCursorWantsKeyEvents();
if (event.getRepeatCount() == 0) {
if (mSelectingText) {
return true; // discard press if copy in progress
@@ -4609,10 +4611,10 @@
// Already checked mNativeClass, so we do not need to check it
// again.
nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
- return true;
+ if (!wantsKeyEvents) return true;
}
// Bubble up the key event as WebView doesn't handle it
- return false;
+ if (!wantsKeyEvents) return false;
}
if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
@@ -4771,11 +4773,14 @@
}
clearTextEntry();
nativeShowCursorTimed();
- if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+ if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+ return true;
+ }
+ if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) {
mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
nativeCursorNodePointer());
+ return true;
}
- return true;
}
// TODO: should we pass all the keys to DOM or check the meta tag
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 075ecbc..2fd5bb1 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -260,8 +260,9 @@
public final float getReadingLevelScale() {
// The reading scale is at least 0.5f apart from the overview scale.
final float MIN_SCALE_DIFF = 0.5f;
- return Math.max(getZoomOverviewScale() + MIN_SCALE_DIFF,
- DEFAULT_READING_LEVEL_SCALE);
+ return computeScaleWithLimits(
+ Math.max(getZoomOverviewScale() + MIN_SCALE_DIFF,
+ DEFAULT_READING_LEVEL_SCALE));
}
public final float getInvDefaultScale() {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 96c1ed3..f927fae 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -47,9 +47,7 @@
private boolean mReserveOverflow;
private OverflowMenuButton mOverflowButton;
private MenuPopupHelper mOverflowPopup;
-
- private float mButtonPaddingLeft;
- private float mButtonPaddingRight;
+
private float mDividerPadding;
private Drawable mDivider;
@@ -94,16 +92,9 @@
Configuration.SCREENLAYOUT_SIZE_XLARGE;
TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
- final int buttonStyle = a.getResourceId(
- com.android.internal.R.styleable.Theme_actionButtonStyle, 0);
mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical);
a.recycle();
- a = context.obtainStyledAttributes(buttonStyle, com.android.internal.R.styleable.View);
- mButtonPaddingLeft = a.getDimension(com.android.internal.R.styleable.View_paddingLeft, 0);
- mButtonPaddingRight = a.getDimension(com.android.internal.R.styleable.View_paddingRight, 0);
- a.recycle();
-
mDividerPadding = DIVIDER_PADDING * res.getDisplayMetrics().density;
setBaselineAligned(false);
@@ -295,10 +286,7 @@
}
private LayoutParams makeActionViewLayoutParams(View view) {
- LayoutParams params = generateLayoutParams(view.getLayoutParams());
- params.leftMargin = (int) mButtonPaddingLeft;
- params.rightMargin = (int) mButtonPaddingRight;
- return params;
+ return generateLayoutParams(view.getLayoutParams());
}
private class OverflowMenuButton extends ImageButton {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 241bc3e..c635b39 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -111,6 +111,7 @@
android/graphics/Rasterizer.cpp \
android/graphics/Region.cpp \
android/graphics/Shader.cpp \
+ android/graphics/SurfaceTexture.cpp \
android/graphics/TextLayout.cpp \
android/graphics/Typeface.cpp \
android/graphics/Utils.cpp \
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
new file mode 100644
index 0000000..2645045
--- /dev/null
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "SurfaceTexture"
+
+#include <stdio.h>
+
+#include <gui/SurfaceTexture.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "android/graphics/GraphicsJNI.h"
+#include "jni.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static const char* const OutOfResourcesException =
+ "android/graphics/SurfaceTexture$OutOfResourcesException";
+
+struct st_t {
+ jfieldID surfaceTexture;
+};
+static st_t st;
+
+// ----------------------------------------------------------------------------
+
+static void setSurfaceTexture(JNIEnv* env, jobject clazz,
+ const sp<SurfaceTexture>& surfaceTexture)
+{
+ SurfaceTexture* const p =
+ (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture);
+ if (surfaceTexture.get()) {
+ surfaceTexture->incStrong(clazz);
+ }
+ if (p) {
+ p->decStrong(clazz);
+ }
+ env->SetIntField(clazz, st.surfaceTexture, (int)surfaceTexture.get());
+}
+
+sp<SurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
+{
+ sp<SurfaceTexture> surfaceTexture(
+ (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture));
+ return surfaceTexture;
+}
+
+// ----------------------------------------------------------------------------
+
+static void SurfaceTexture_init(JNIEnv* env, jobject clazz, jint texName)
+{
+ sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+
+ if (surfaceTexture == 0) {
+ doThrow(env, OutOfResourcesException);
+ return;
+ }
+ setSurfaceTexture(env, clazz, surfaceTexture);
+}
+
+static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz)
+{
+ sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+ surfaceTexture->updateTexImage();
+}
+
+// ----------------------------------------------------------------------------
+
+const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
+static void nativeClassInit(JNIEnv* env, jclass clazz);
+
+static JNINativeMethod gSurfaceTextureMethods[] = {
+ {"nativeClassInit", "()V", (void*)nativeClassInit },
+ {"init", "(I)V", (void*)SurfaceTexture_init },
+ {"updateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
+};
+
+static void nativeClassInit(JNIEnv* env, jclass clazz)
+{
+ st.surfaceTexture = env->GetFieldID(clazz,
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
+}
+
+int register_android_graphics_SurfaceTexture(JNIEnv* env)
+{
+ int err = 0;
+ err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
+ gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
+ return err;
+}
+
+} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index c3d3572..b4c868f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -417,16 +417,21 @@
// Display lists
// ----------------------------------------------------------------------------
-static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(
- JNIEnv* env, jobject canvas) {
- return new DisplayListRenderer;
-}
-
-static DisplayList* android_view_GLES20Canvas_createDisplayList(JNIEnv* env,
+static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
jobject canvas, DisplayListRenderer* renderer) {
return renderer->getDisplayList();
}
+static OpenGLRenderer* android_view_GLES20Canvas_getDisplayListRenderer(JNIEnv* env,
+ jobject clazz, DisplayListRenderer* renderer) {
+ if (renderer == NULL) {
+ renderer = new DisplayListRenderer;
+ } else {
+ renderer->reset();
+ }
+ return renderer;
+}
+
static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
delete displayList;
@@ -517,9 +522,9 @@
{ "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_getClipBounds },
- { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
- { "nCreateDisplayList", "(I)I", (void*) android_view_GLES20Canvas_createDisplayList },
+ { "nGetDisplayList", "(I)I", (void*) android_view_GLES20Canvas_getDisplayList },
{ "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
+ { "nGetDisplayListRenderer", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListRenderer },
{ "nDrawDisplayList", "(II)V", (void*) android_view_GLES20Canvas_drawDisplayList },
#endif
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 94fcc2f..e502b1e 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -29,7 +29,11 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
- style="?attr/actionButtonStyle" />
+ android:paddingLeft="4dip"
+ android:paddingRight="4dip"
+ android:minHeight="56dip"
+ android:scaleType="center"
+ android:background="@null" />
<Button android:id="@+id/textButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index c30c4f2..2bbb4d0 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -16,7 +16,9 @@
<com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight">
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip">
<!-- Icon will be inserted here. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 470fb36..ec5ef83 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1030,7 +1030,7 @@
</style>
<style name="Widget.ActionButton">
- <item name="android:background">@null</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
</style>
@@ -1651,8 +1651,8 @@
</style>
<style name="Widget.Holo.ActionButton" parent="Widget.ActionButton">
- <item name="android:paddingLeft">4dip</item>
- <item name="android:paddingRight">4dip</item>
+ <item name="android:paddingLeft">16dip</item>
+ <item name="android:paddingRight">16dip</item>
<item name="android:minHeight">56dip</item>
<item name="android:scaleType">center</item>
</style>
@@ -1981,7 +1981,6 @@
<style name="Widget.Holo.Light.ActionButton.Overflow">
<item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
- <item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
</style>
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
new file mode 100644
index 0000000..883c4eb
--- /dev/null
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package android.graphics;
+
+/**
+ * Captures frames from an image stream as an OpenGL ES texture.
+ *
+ * <p>The image stream may come from either video playback or camera preview. A SurfaceTexture may
+ * be used in place of a SurfaceHolder when specifying the output destination of a MediaPlayer or
+ * Camera object. This will cause all the frames from that image stream to be sent to the
+ * SurfaceTexture object rather than to the device's display. When {@link #updateTexImage} is
+ * called, the contents of the texture object specified when the SurfaceTexture was created is
+ * updated to contain the most recent image from the image stream. This may cause some frames of
+ * the stream to be skipped.
+ *
+ * <p>The texture object uses the GL_TEXTURE_EXTERNAL_OES texture target, which is defined by the
+ * OES_EGL_image_external OpenGL ES extension. This limits how the texture may be used.
+ */
+public class SurfaceTexture {
+
+ @SuppressWarnings("unused")
+ private int mSurfaceTexture;
+
+ /**
+ * Callback interface for being notified that a new stream frame is available.
+ */
+ public interface OnFrameAvailableListener {
+ void onFrameAvailable(SurfaceTexture surfaceTexture);
+ }
+
+ /**
+ * Exception thrown when a surface couldn't be created or resized
+ */
+ public static class OutOfResourcesException extends Exception {
+ public OutOfResourcesException() {
+ }
+ public OutOfResourcesException(String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * Construct a new SurfaceTexture to stream images to a given OpenGL texture.
+ *
+ * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
+ */
+ public SurfaceTexture(int texName) {
+ init(texName);
+ }
+
+ /**
+ * Register a callback to be invoked when a new image frame becomes available to the
+ * SurfaceTexture. Note that this callback may be called on an arbitrary thread, so it is not
+ * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
+ * thread invoking the callback.
+ */
+ public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
+ // TODO: Implement this!
+ }
+
+ /**
+ * Update the texture image to the most recent frame from the image stream. This may only be
+ * called while the OpenGL ES context that owns the texture is bound to the thread. It will
+ * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
+ */
+ public native void updateTexImage();
+
+ private native void init(int texName);
+
+ /*
+ * We use a class initializer to allow the native code to cache some
+ * field offsets.
+ */
+ private static native void nativeClassInit();
+ static { nativeClassInit(); }
+}
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index c95f31e..e5f7e62 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -19,6 +19,7 @@
#include <utils/Timers.h>
#include <camera/ICameraClient.h>
+#include <gui/ISurfaceTexture.h>
namespace android {
@@ -175,6 +176,9 @@
// pass the buffered Surface to the camera service
status_t setPreviewDisplay(const sp<Surface>& surface);
+ // pass the buffered ISurfaceTexture to the camera service
+ status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+
// start preview mode, must call setPreviewDisplay first
status_t startPreview();
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index b69e075..b2310a6 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -24,6 +24,7 @@
#include <binder/IMemory.h>
#include <utils/String8.h>
#include <camera/Camera.h>
+#include <gui/ISurfaceTexture.h>
namespace android {
@@ -48,6 +49,10 @@
// pass the buffered Surface to the camera service
virtual status_t setPreviewDisplay(const sp<Surface>& surface) = 0;
+ // pass the buffered ISurfaceTexture to the camera service
+ virtual status_t setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) = 0;
+
// set the preview callback flag to affect how the received frames from
// preview are handled.
virtual void setPreviewCallbackFlag(int flag) = 0;
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
new file mode 100644
index 0000000..77d37f1
--- /dev/null
+++ b/include/gui/ISurfaceTexture.h
@@ -0,0 +1,91 @@
+/*
+ * 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_GUI_ISURFACETEXTURE_H
+#define ANDROID_GUI_ISURFACETEXTURE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <binder/IInterface.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class ISurfaceTexture : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(SurfaceTexture);
+
+ // requestBuffer requests a new buffer for the given index. The server (i.e.
+ // the ISurfaceTexture implementation) assigns the newly created buffer to
+ // the given slot index, and the client is expected to mirror the
+ // slot->buffer mapping so that it's not necessary to transfer a
+ // GraphicBuffer for every dequeue operation.
+ virtual sp<GraphicBuffer> requestBuffer(int slot, uint32_t w, uint32_t h,
+ uint32_t format, uint32_t usage) = 0;
+
+ // setBufferCount sets the number of buffer slots available. Calling this
+ // will also cause all buffer slots to be emptied. The caller should empty
+ // its mirrored copy of the buffer slots when calling this method.
+ virtual status_t setBufferCount(int bufferCount) = 0;
+
+ // dequeueBuffer requests a new buffer slot for the client to use. Ownership
+ // of the slot is transfered to the client, meaning that the server will not
+ // use the contents of the buffer associated with that slot. The slot index
+ // returned may or may not contain a buffer. If the slot is empty the client
+ // should call requestBuffer to assign a new buffer to that slot. The client
+ // is expected to either call cancelBuffer on the dequeued slot or to fill
+ // in the contents of its associated buffer contents and call queueBuffer.
+ virtual status_t dequeueBuffer(int *slot) = 0;
+
+ // queueBuffer indicates that the client has finished filling in the
+ // contents of the buffer associated with slot and transfers ownership of
+ // that slot back to the server. It is not valid to call queueBuffer on a
+ // slot that is not owned by the client or one for which a buffer associated
+ // via requestBuffer.
+ virtual status_t queueBuffer(int slot) = 0;
+
+ // cancelBuffer indicates that the client does not wish to fill in the
+ // buffer associated with slot and transfers ownership of the slot back to
+ // the server.
+ virtual void cancelBuffer(int slot) = 0;
+
+ virtual status_t setCrop(const Rect& reg) = 0;
+ virtual status_t setTransform(uint32_t transform) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnSurfaceTexture : public BnInterface<ISurfaceTexture>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_ISURFACETEXTURE_H
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
new file mode 100644
index 0000000..ff92e08
--- /dev/null
+++ b/include/gui/SurfaceTexture.h
@@ -0,0 +1,139 @@
+/*
+ * 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_GUI_SURFACETEXTURE_H
+#define ANDROID_GUI_SURFACETEXTURE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class SurfaceTexture : public BnSurfaceTexture {
+public:
+ enum { MIN_BUFFER_SLOTS = 3 };
+ enum { NUM_BUFFER_SLOTS = 32 };
+
+ // tex indicates the name OpenGL texture to which images are to be streamed.
+ // This texture name cannot be changed once the SurfaceTexture is created.
+ SurfaceTexture(GLuint tex);
+
+ virtual ~SurfaceTexture();
+
+ // setBufferCount updates the number of available buffer slots. After
+ // calling this all buffer slots are both unallocated and owned by the
+ // SurfaceTexture object (i.e. they are not owned by the client).
+ virtual status_t setBufferCount(int bufferCount);
+
+ virtual sp<GraphicBuffer> requestBuffer(int buf, uint32_t w, uint32_t h,
+ uint32_t format, uint32_t usage);
+
+ // dequeueBuffer gets the next buffer slot index for the client to use. If a
+ // buffer slot is available then that slot index is written to the location
+ // pointed to by the buf argument and a status of OK is returned. If no
+ // slot is available then a status of -EBUSY is returned and buf is
+ // unmodified.
+ virtual status_t dequeueBuffer(int *buf);
+
+ virtual status_t queueBuffer(int buf);
+ virtual void cancelBuffer(int buf);
+ virtual status_t setCrop(const Rect& reg);
+ virtual status_t setTransform(uint32_t transform);
+
+ // updateTexImage sets the image contents of the target texture to that of
+ // the most recently queued buffer.
+ //
+ // This call may only be made while the OpenGL ES context to which the
+ // target texture belongs is bound to the calling thread.
+ status_t updateTexImage();
+
+private:
+
+ // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
+ // all slots.
+ void freeAllBuffers();
+
+ // createImage creates a new EGLImage from a GraphicBuffer.
+ EGLImageKHR createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer);
+
+ enum { INVALID_BUFFER_SLOT = -1 };
+
+ struct BufferSlot {
+ // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+ // if no buffer has been allocated.
+ sp<GraphicBuffer> mGraphicBuffer;
+
+ // mEglImage is the EGLImage created from mGraphicBuffer.
+ EGLImageKHR mEglImage;
+
+ // mEglDisplay is the EGLDisplay used to create mEglImage.
+ EGLDisplay mEglDisplay;
+
+ // mOwnedByClient indicates whether the slot is currently accessible to a
+ // client and should not be used by the SurfaceTexture object. It gets
+ // set to true when dequeueBuffer returns the slot and is reset to false
+ // when the client calls either queueBuffer or cancelBuffer on the slot.
+ bool mOwnedByClient;
+ };
+
+ // mSlots is the array of buffer slots that must be mirrored on the client
+ // side. This allows buffer ownership to be transferred between the client
+ // and server without sending a GraphicBuffer over binder. The entire array
+ // is initialized to NULL at construction time, and buffers are allocated
+ // for a slot when requestBuffer is called with that slot's index.
+ BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+ // mBufferCount is the number of buffer slots that the client and server
+ // must maintain. It defaults to MIN_BUFFER_SLOTS and can be changed by
+ // calling setBufferCount.
+ int mBufferCount;
+
+ // mCurrentTexture is the buffer slot index of the buffer that is currently
+ // bound to the OpenGL texture. A value of INVALID_BUFFER_SLOT, indicating
+ // that no buffer is currently bound to the texture.
+ int mCurrentTexture;
+
+ // mLastQueued is the buffer slot index of the most recently enqueued buffer.
+ // At construction time it is initialized to INVALID_BUFFER_SLOT, and is
+ // updated each time queueBuffer is called.
+ int mLastQueued;
+
+ // mTexName is the name of the OpenGL texture to which streamed images will
+ // be bound when updateTexImage is called. It is set at construction time
+ // changed with a call to setTexName.
+ const GLuint mTexName;
+
+ // mMutex is the mutex used to prevent concurrent access to the member
+ // variables of SurfaceTexture objects. It must be locked whenever the
+ // member variables are accessed.
+ Mutex mMutex;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_SURFACETEXTURE_H
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
new file mode 100644
index 0000000..dd1d490
--- /dev/null
+++ b/include/gui/SurfaceTextureClient.h
@@ -0,0 +1,118 @@
+/*
+ * 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_GUI_SURFACETEXTURECLIENT_H
+#define ANDROID_GUI_SURFACETEXTURECLIENT_H
+
+#include <gui/ISurfaceTexture.h>
+#include <gui/SurfaceTexture.h>
+
+#include <ui/egl/android_natives.h>
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class SurfaceTextureClient
+ : public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
+{
+public:
+ SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);
+
+private:
+
+ // can't be copied
+ SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
+ SurfaceTextureClient(const SurfaceTextureClient& rhs);
+
+ // ANativeWindow hooks
+ static int setSwapInterval(ANativeWindow* window, int interval);
+ static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
+ static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int query(ANativeWindow* window, int what, int* value);
+ static int perform(ANativeWindow* window, int operation, ...);
+
+ int setSwapInterval(int interval);
+ int dequeueBuffer(android_native_buffer_t** buffer);
+ int lockBuffer(android_native_buffer_t* buffer);
+ int queueBuffer(android_native_buffer_t* buffer);
+ int cancelBuffer(android_native_buffer_t* buffer);
+ int query(int what, int* value);
+ int perform(int operation, va_list args);
+
+ int dispatchSetUsage(va_list args);
+ int dispatchConnect(va_list args);
+ int dispatchDisconnect(va_list args);
+ int dispatchSetCrop(va_list args);
+ int dispatchSetBufferCount(va_list args);
+ int dispatchSetBuffersGeometry(va_list args);
+ int dispatchSetBuffersTransform(va_list args);
+
+ int connect(int api);
+ int disconnect(int api);
+ int setUsage(uint32_t reqUsage);
+ int setCrop(Rect const* rect);
+ int setBufferCount(int bufferCount);
+ int setBuffersGeometry(int w, int h, int format);
+ int setBuffersTransform(int transform);
+
+ void freeAllBuffers();
+
+ enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
+ enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
+ enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+
+ // mSurfaceTexture is the interface to the surface texture server. All
+ // operations on the surface texture client ultimately translate into
+ // interactions with the server using this interface.
+ sp<ISurfaceTexture> mSurfaceTexture;
+
+ // mSlots stores the buffers that have been allocated for each buffer slot.
+ // It is initialized to null pointers, and gets filled in with the result of
+ // ISurfaceTexture::requestBuffer when the client dequeues a buffer from a
+ // slot that has not yet been used. The buffer allocated to a slot will also
+ // be replaced if the requested buffer usage or geometry differs from that
+ // of the buffer allocated to a slot.
+ sp<GraphicBuffer> mSlots[NUM_BUFFER_SLOTS];
+
+ // mReqWidth is the buffer width that will be requested at the next dequeue
+ // operation. It is initialized to 1.
+ uint32_t mReqWidth;
+
+ // mReqHeight is the buffer height that will be requested at the next deuque
+ // operation. It is initialized to 1.
+ uint32_t mReqHeight;
+
+ // mReqFormat is the buffer pixel format that will be requested at the next
+ // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
+ uint32_t mReqFormat;
+
+ // mReqUsage is the set of buffer usage flags that will be requested
+ // at the next deuque operation. It is initialized to 0.
+ uint32_t mReqUsage;
+
+ // mMutex is the mutex used to prevent concurrent access to the member
+ // variables of SurfaceTexture objects. It must be locked whenever the
+ // member variables are accessed.
+ Mutex mMutex;
+};
+
+}; // namespace android
+
+#endif // ANDROID_GUI_SURFACETEXTURECLIENT_H
diff --git a/include/media/stagefright/ColorConverter.h b/include/media/stagefright/ColorConverter.h
index 2b61f58..2ae8a5b 100644
--- a/include/media/stagefright/ColorConverter.h
+++ b/include/media/stagefright/ColorConverter.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <stdint.h>
+#include <utils/Errors.h>
#include <OMX_Video.h>
@@ -32,7 +33,7 @@
bool isValid() const;
- void convert(
+ status_t convert(
const void *srcBits,
size_t srcWidth, size_t srcHeight,
size_t srcCropLeft, size_t srcCropTop,
@@ -63,16 +64,16 @@
uint8_t *initClip();
- void convertCbYCrY(
+ status_t convertCbYCrY(
const BitmapParams &src, const BitmapParams &dst);
- void convertYUV420Planar(
+ status_t convertYUV420Planar(
const BitmapParams &src, const BitmapParams &dst);
- void convertQCOMYUV420SemiPlanar(
+ status_t convertQCOMYUV420SemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
- void convertYUV420SemiPlanar(
+ status_t convertYUV420SemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
ColorConverter(const ColorConverter &);
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 693fbfb..1bab7d7 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -131,6 +131,13 @@
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
+
+ /* Create a new GraphicBuffer for the client to use. SurfaceFlinger will
+ * not maintain a reference to the GraphicBuffer, so the underlying native
+ * handle will be freed once the client references are released.
+ */
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) const = 0;
};
// ----------------------------------------------------------------------------
@@ -144,6 +151,7 @@
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
CREATE_CLIENT_CONNECTION,
+ CREATE_GRAPHIC_BUFFER,
GET_CBLK,
OPEN_GLOBAL_TRANSACTION,
CLOSE_GLOBAL_TRANSACTION,
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index aa65d93..8b256f4 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -121,6 +121,7 @@
friend class Surface;
friend class BpSurface;
friend class BnSurface;
+ friend class SurfaceTextureClient;
friend class LightRefBase<GraphicBuffer>;
GraphicBuffer(const GraphicBuffer& rhs);
GraphicBuffer& operator = (const GraphicBuffer& rhs);
diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk
index 03ff229..2f16923 100644
--- a/libs/camera/Android.mk
+++ b/libs/camera/Android.mk
@@ -14,7 +14,8 @@
libbinder \
libhardware \
libsurfaceflinger_client \
- libui
+ libui \
+ libgui
LOCAL_MODULE:= libcamera_client
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index ab626ad..907f119 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -182,6 +182,20 @@
}
}
+// pass the buffered ISurfaceTexture to the camera service
+status_t Camera::setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture)
+{
+ LOGV("setPreviewTexture(%p)", surfaceTexture.get());
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ if (surfaceTexture != 0) {
+ return c->setPreviewTexture(surfaceTexture);
+ } else {
+ LOGD("app passed NULL surface");
+ return c->setPreviewTexture(0);
+ }
+}
+
// start preview mode
status_t Camera::startPreview()
{
diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp
index 7ba8d12..0881d65 100644
--- a/libs/camera/ICamera.cpp
+++ b/libs/camera/ICamera.cpp
@@ -28,6 +28,7 @@
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_PREVIEW_DISPLAY,
+ SET_PREVIEW_TEXTURE,
SET_PREVIEW_CALLBACK_FLAG,
START_PREVIEW,
STOP_PREVIEW,
@@ -78,6 +79,18 @@
return reply.readInt32();
}
+ // pass the buffered SurfaceTexture to the camera service
+ status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture)
+ {
+ LOGV("setPreviewTexture");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ sp<IBinder> b(surfaceTexture->asBinder());
+ data.writeStrongBinder(b);
+ remote()->transact(SET_PREVIEW_TEXTURE, data, &reply);
+ return reply.readInt32();
+ }
+
// set the preview callback flag to affect how the received frames from
// preview are handled. See Camera.h for details.
void setPreviewCallbackFlag(int flag)
@@ -296,6 +309,13 @@
reply->writeInt32(setPreviewDisplay(surface));
return NO_ERROR;
} break;
+ case SET_PREVIEW_TEXTURE: {
+ LOGV("SET_PREVIEW_TEXTURE");
+ CHECK_INTERFACE(ICamera, data, reply);
+ sp<ISurfaceTexture> st = interface_cast<ISurfaceTexture>(data.readStrongBinder());
+ reply->writeInt32(setPreviewTexture(st));
+ return NO_ERROR;
+ } break;
case SET_PREVIEW_CALLBACK_FLAG: {
LOGV("SET_PREVIEW_CALLBACK_TYPE");
CHECK_INTERFACE(ICamera, data, reply);
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 249558a..d1a6af1 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -4,17 +4,25 @@
LOCAL_SRC_FILES:= \
ISensorEventConnection.cpp \
ISensorServer.cpp \
+ ISurfaceTexture.cpp \
Sensor.cpp \
SensorChannel.cpp \
SensorEventQueue.cpp \
- SensorManager.cpp
+ SensorManager.cpp \
+ SurfaceTexture.cpp \
+ SurfaceTextureClient.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libhardware \
- libhardware_legacy
+ libhardware_legacy \
+ libui \
+ libEGL \
+ libGLESv2 \
+ libsurfaceflinger_client
+
LOCAL_MODULE:= libgui
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
new file mode 100644
index 0000000..90bca3c
--- /dev/null
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/Timers.h>
+
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
+
+#include <gui/ISurfaceTexture.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+ REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ SET_BUFFER_COUNT,
+ DEQUEUE_BUFFER,
+ QUEUE_BUFFER,
+ CANCEL_BUFFER,
+ SET_CROP,
+ SET_TRANSFORM,
+};
+
+
+class BpSurfaceTexture : public BpInterface<ISurfaceTexture>
+{
+public:
+ BpSurfaceTexture(const sp<IBinder>& impl)
+ : BpInterface<ISurfaceTexture>(impl)
+ {
+ }
+
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInt32(bufferIdx);
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(usage);
+ remote()->transact(REQUEST_BUFFER, data, &reply);
+ sp<GraphicBuffer> buffer;
+ bool nonNull = reply.readInt32();
+ if (nonNull) {
+ buffer = new GraphicBuffer();
+ reply.read(*buffer);
+ }
+ return buffer;
+ }
+
+ virtual status_t setBufferCount(int bufferCount)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInt32(bufferCount);
+ remote()->transact(SET_BUFFER_COUNT, data, &reply);
+ status_t err = reply.readInt32();
+ return err;
+ }
+
+ virtual status_t dequeueBuffer(int *buf) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ remote()->transact(DEQUEUE_BUFFER, data, &reply);
+ *buf = reply.readInt32();
+ int result = reply.readInt32();
+ return result;
+ }
+
+ virtual status_t queueBuffer(int buf) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInt32(buf);
+ remote()->transact(QUEUE_BUFFER, data, &reply);
+ status_t result = reply.readInt32();
+ return result;
+ }
+
+ virtual void cancelBuffer(int buf) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInt32(buf);
+ remote()->transact(CANCEL_BUFFER, data, &reply);
+ }
+
+ virtual status_t setCrop(const Rect& reg) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeFloat(reg.left);
+ data.writeFloat(reg.top);
+ data.writeFloat(reg.right);
+ data.writeFloat(reg.bottom);
+ remote()->transact(SET_CROP, data, &reply);
+ status_t result = reply.readInt32();
+ return result;
+ }
+
+ virtual status_t setTransform(uint32_t transform) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInt32(transform);
+ remote()->transact(SET_TRANSFORM, data, &reply);
+ status_t result = reply.readInt32();
+ return result;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture");
+
+// ----------------------------------------------------------------------
+
+status_t BnSurfaceTexture::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case REQUEST_BUFFER: {
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ int bufferIdx = data.readInt32();
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t usage = data.readInt32();
+ sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format,
+ usage));
+ reply->writeInt32(buffer != 0);
+ if (buffer != 0) {
+ reply->write(*buffer);
+ }
+ return NO_ERROR;
+ } break;
+ case SET_BUFFER_COUNT: {
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ int bufferCount = data.readInt32();
+ int result = setBufferCount(bufferCount);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ } break;
+ case DEQUEUE_BUFFER: {
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ int buf;
+ int result = dequeueBuffer(&buf);
+ reply->writeInt32(buf);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ } break;
+ case QUEUE_BUFFER: {
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ int buf = data.readInt32();
+ status_t result = queueBuffer(buf);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ } break;
+ case CANCEL_BUFFER: {
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ int buf = data.readInt32();
+ cancelBuffer(buf);
+ return NO_ERROR;
+ } break;
+ case SET_CROP: {
+ Rect reg;
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ reg.left = data.readFloat();
+ reg.top = data.readFloat();
+ reg.right = data.readFloat();
+ reg.bottom = data.readFloat();
+ status_t result = setCrop(reg);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ } break;
+ case SET_TRANSFORM: {
+ Rect reg;
+ CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ uint32_t transform = data.readInt32();
+ status_t result = setTransform(transform);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ } break;
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
new file mode 100644
index 0000000..9579996
--- /dev/null
+++ b/libs/gui/SurfaceTexture.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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 "SurfaceTexture"
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <gui/SurfaceTexture.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <utils/Log.h>
+
+namespace android {
+
+SurfaceTexture::SurfaceTexture(GLuint tex) :
+ mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
+ mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
+}
+
+SurfaceTexture::~SurfaceTexture() {
+ freeAllBuffers();
+}
+
+status_t SurfaceTexture::setBufferCount(int bufferCount) {
+ Mutex::Autolock lock(mMutex);
+ freeAllBuffers();
+ mBufferCount = bufferCount;
+ return OK;
+}
+
+sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+ Mutex::Autolock lock(mMutex);
+ if (buf < 0 || mBufferCount <= buf) {
+ LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, buf);
+ return 0;
+ }
+ usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
+ format, usage));
+ if (graphicBuffer == 0) {
+ LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
+ } else {
+ mSlots[buf].mGraphicBuffer = graphicBuffer;
+ if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
+ mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+ }
+ }
+ return graphicBuffer;
+}
+
+status_t SurfaceTexture::dequeueBuffer(int *buf) {
+ Mutex::Autolock lock(mMutex);
+ int found = INVALID_BUFFER_SLOT;
+ for (int i = 0; i < mBufferCount; i++) {
+ if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) {
+ mSlots[i].mOwnedByClient = true;
+ found = i;
+ break;
+ }
+ }
+ if (found == INVALID_BUFFER_SLOT) {
+ return -EBUSY;
+ }
+ *buf = found;
+ return OK;
+}
+
+status_t SurfaceTexture::queueBuffer(int buf) {
+ Mutex::Autolock lock(mMutex);
+ if (buf < 0 || mBufferCount <= buf) {
+ LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, buf);
+ return -EINVAL;
+ } else if (!mSlots[buf].mOwnedByClient) {
+ LOGE("queueBuffer: slot %d is not owned by the client", buf);
+ return -EINVAL;
+ } else if (mSlots[buf].mGraphicBuffer == 0) {
+ LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
+ buf);
+ return -EINVAL;
+ }
+ mSlots[buf].mOwnedByClient = false;
+ mLastQueued = buf;
+ return OK;
+}
+
+void SurfaceTexture::cancelBuffer(int buf) {
+ Mutex::Autolock lock(mMutex);
+ if (buf < 0 || mBufferCount <= buf) {
+ LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
+ buf);
+ return;
+ } else if (!mSlots[buf].mOwnedByClient) {
+ LOGE("cancelBuffer: slot %d is not owned by the client", buf);
+ return;
+ }
+ mSlots[buf].mOwnedByClient = false;
+}
+
+status_t SurfaceTexture::setCrop(const Rect& reg) {
+ Mutex::Autolock lock(mMutex);
+ // XXX: How should we handle crops?
+ return OK;
+}
+
+status_t SurfaceTexture::setTransform(uint32_t transform) {
+ Mutex::Autolock lock(mMutex);
+ // XXX: How should we handle transforms?
+ return OK;
+}
+
+status_t SurfaceTexture::updateTexImage() {
+ Mutex::Autolock lock(mMutex);
+
+ // We always bind the texture even if we don't update its contents.
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
+
+ // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
+ // so this check will fail until a buffer gets queued.
+ if (mCurrentTexture != mLastQueued) {
+ // XXX: Figure out the right target.
+ mCurrentTexture = mLastQueued;
+ EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
+ if (image == EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
+ image = createImage(dpy, graphicBuffer);
+ mSlots[mCurrentTexture].mEglImage = image;
+ mSlots[mCurrentTexture].mEglDisplay = dpy;
+ }
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+ GLint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ LOGE("error binding external texture image %p (slot %d): %#04x",
+ image, mCurrentTexture, error);
+ return -EINVAL;
+ }
+ }
+ return OK;
+}
+
+void SurfaceTexture::freeAllBuffers() {
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ mSlots[i].mGraphicBuffer = 0;
+ mSlots[i].mOwnedByClient = false;
+ if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+ mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
+ }
+}
+
+EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer) {
+ EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE,
+ };
+ EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
+ EGLint error = eglGetError();
+ if (error != EGL_SUCCESS) {
+ LOGE("error creating EGLImage: %#x", error);
+ } else if (image == EGL_NO_IMAGE_KHR) {
+ LOGE("no error reported, but no image was returned by "
+ "eglCreateImageKHR");
+ }
+ return image;
+}
+
+}; // namespace android
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
new file mode 100644
index 0000000..8a59144
--- /dev/null
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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 "SurfaceTextureClient"
+
+#include <gui/SurfaceTextureClient.h>
+
+#include <utils/Log.h>
+
+namespace android {
+
+SurfaceTextureClient::SurfaceTextureClient(
+ const sp<ISurfaceTexture>& surfaceTexture):
+ mSurfaceTexture(surfaceTexture), mReqWidth(1), mReqHeight(1),
+ mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() {
+ // Initialize the ANativeWindow function pointers.
+ ANativeWindow::setSwapInterval = setSwapInterval;
+ ANativeWindow::dequeueBuffer = dequeueBuffer;
+ ANativeWindow::cancelBuffer = cancelBuffer;
+ ANativeWindow::lockBuffer = lockBuffer;
+ ANativeWindow::queueBuffer = queueBuffer;
+ ANativeWindow::query = query;
+ ANativeWindow::perform = perform;
+}
+
+int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->setSwapInterval(interval);
+}
+
+int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+ android_native_buffer_t** buffer) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->dequeueBuffer(buffer);
+}
+
+int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+ android_native_buffer_t* buffer) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->cancelBuffer(buffer);
+}
+
+int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+ android_native_buffer_t* buffer) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->lockBuffer(buffer);
+}
+
+int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+ android_native_buffer_t* buffer) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->queueBuffer(buffer);
+}
+
+int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->query(what, value);
+}
+
+int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ SurfaceTextureClient* c = getSelf(window);
+ return c->perform(operation, args);
+}
+
+int SurfaceTextureClient::setSwapInterval(int interval) {
+ return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
+ Mutex::Autolock lock(mMutex);
+ int buf = -1;
+ status_t err = mSurfaceTexture->dequeueBuffer(&buf);
+ if (err < 0) {
+ return err;
+ }
+ sp<GraphicBuffer>& gbuf(mSlots[buf]);
+ if (gbuf == 0 || gbuf->getWidth() != mReqWidth ||
+ gbuf->getHeight() != mReqHeight ||
+ uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
+ (gbuf->getUsage() & mReqUsage) != mReqUsage) {
+ gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
+ mReqFormat, mReqUsage);
+ if (gbuf == 0) {
+ return NO_MEMORY;
+ }
+ }
+ *buffer = gbuf.get();
+ return OK;
+}
+
+int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
+ Mutex::Autolock lock(mMutex);
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].get() == buffer) {
+ mSurfaceTexture->cancelBuffer(i);
+ return OK;
+ }
+ }
+ return BAD_VALUE;
+}
+
+int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
+ Mutex::Autolock lock(mMutex);
+ return OK;
+}
+
+int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
+ Mutex::Autolock lock(mMutex);
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].get() == GraphicBuffer::getSelf(buffer)) {
+ return mSurfaceTexture->queueBuffer(i);
+ }
+ }
+ LOGE("queueBuffer: unknown buffer queued");
+ return BAD_VALUE;
+}
+
+int SurfaceTextureClient::query(int what, int* value) {
+ Mutex::Autolock lock(mMutex);
+ // XXX: Implement this!
+ return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::perform(int operation, va_list args)
+{
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_CONNECT:
+ res = dispatchConnect(args);
+ break;
+ case NATIVE_WINDOW_DISCONNECT:
+ res = dispatchDisconnect(args);
+ break;
+ case NATIVE_WINDOW_SET_USAGE:
+ res = dispatchSetUsage(args);
+ break;
+ case NATIVE_WINDOW_SET_CROP:
+ res = dispatchSetCrop(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ res = dispatchSetBufferCount(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ res = dispatchSetBuffersGeometry(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ res = dispatchSetBuffersTransform(args);
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ return res;
+}
+
+int SurfaceTextureClient::dispatchConnect(va_list args) {
+ int api = va_arg(args, int);
+ return connect(api);
+}
+
+int SurfaceTextureClient::dispatchDisconnect(va_list args) {
+ int api = va_arg(args, int);
+ return disconnect(api);
+}
+
+int SurfaceTextureClient::dispatchSetUsage(va_list args) {
+ int usage = va_arg(args, int);
+ return setUsage(usage);
+}
+
+int SurfaceTextureClient::dispatchSetCrop(va_list args) {
+ android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+ return setCrop(reinterpret_cast<Rect const*>(rect));
+}
+
+int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
+ size_t bufferCount = va_arg(args, size_t);
+ return setBufferCount(bufferCount);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ int f = va_arg(args, int);
+ return setBuffersGeometry(w, h, f);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
+ int transform = va_arg(args, int);
+ return setBuffersTransform(transform);
+}
+
+int SurfaceTextureClient::connect(int api) {
+ // XXX: Implement this!
+ return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::disconnect(int api) {
+ // XXX: Implement this!
+ return INVALID_OPERATION;
+}
+
+int SurfaceTextureClient::setUsage(uint32_t reqUsage)
+{
+ Mutex::Autolock lock(mMutex);
+ mReqUsage = reqUsage;
+ return OK;
+}
+
+int SurfaceTextureClient::setCrop(Rect const* rect)
+{
+ Mutex::Autolock lock(mMutex);
+
+ // empty/invalid rects are not allowed
+ if (rect->isEmpty())
+ return BAD_VALUE;
+
+ status_t err = mSurfaceTexture->setCrop(*rect);
+ LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s",
+ strerror(-err));
+
+ return err;
+}
+
+int SurfaceTextureClient::setBufferCount(int bufferCount)
+{
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mSurfaceTexture->setBufferCount(bufferCount);
+ LOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
+ bufferCount, strerror(-err));
+
+ if (err == NO_ERROR) {
+ freeAllBuffers();
+ }
+
+ return err;
+}
+
+int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
+{
+ Mutex::Autolock lock(mMutex);
+
+ if (w<0 || h<0 || format<0)
+ return BAD_VALUE;
+
+ if ((w && !h) || (!w && h))
+ return BAD_VALUE;
+
+ mReqWidth = w;
+ mReqHeight = h;
+ mReqFormat = format;
+
+ return NO_ERROR;
+}
+
+int SurfaceTextureClient::setBuffersTransform(int transform)
+{
+ Mutex::Autolock lock(mMutex);
+ status_t err = mSurfaceTexture->setTransform(transform);
+ return err;
+}
+
+void SurfaceTextureClient::freeAllBuffers() {
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ mSlots[i] = 0;
+ }
+}
+
+}; // namespace android
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 77d628a..afb82bf 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -82,6 +82,43 @@
///////////////////////////////////////////////////////////////////////////////
DisplayList::DisplayList(const DisplayListRenderer& recorder) {
+ initFromDisplayListRenderer(recorder);
+}
+
+DisplayList::~DisplayList() {
+ sk_free((void*) mReader.base());
+
+ Caches& caches = Caches::getInstance();
+
+ for (size_t i = 0; i < mBitmapResources.size(); i++) {
+ caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
+ }
+ mBitmapResources.clear();
+
+ for (size_t i = 0; i < mShaderResources.size(); i++) {
+ caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i));
+ }
+ mShaderResources.clear();
+
+ for (size_t i = 0; i < mPaints.size(); i++) {
+ delete mPaints.itemAt(i);
+ }
+ mPaints.clear();
+
+ for (size_t i = 0; i < mMatrices.size(); i++) {
+ delete mMatrices.itemAt(i);
+ }
+ mMatrices.clear();
+
+ if (mPathHeap) {
+ for (int i = 0; i < mPathHeap->count(); i++) {
+ caches.pathCache.removeDeferred(&(*mPathHeap)[i]);
+ }
+ mPathHeap->safeUnref();
+ }
+}
+
+void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder) {
const SkWriter32& writer = recorder.writeStream();
init();
@@ -132,39 +169,6 @@
}
}
-DisplayList::~DisplayList() {
- sk_free((void*) mReader.base());
-
- Caches& caches = Caches::getInstance();
-
- for (size_t i = 0; i < mBitmapResources.size(); i++) {
- caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
- }
- mBitmapResources.clear();
-
- for (size_t i = 0; i < mShaderResources.size(); i++) {
- caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i));
- }
- mShaderResources.clear();
-
- for (size_t i = 0; i < mPaints.size(); i++) {
- delete mPaints.itemAt(i);
- }
- mPaints.clear();
-
- for (size_t i = 0; i < mMatrices.size(); i++) {
- delete mMatrices.itemAt(i);
- }
- mMatrices.clear();
-
- if (mPathHeap) {
- for (int i = 0; i < mPathHeap->count(); i++) {
- caches.pathCache.removeDeferred(&(*mPathHeap)[i]);
- }
- mPathHeap->safeUnref();
- }
-}
-
void DisplayList::init() {
mPathHeap = NULL;
}
@@ -327,6 +331,7 @@
DisplayListRenderer::DisplayListRenderer():
mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) {
mPathHeap = NULL;
+ mDisplayList = NULL;
}
DisplayListRenderer::~DisplayListRenderer() {
@@ -367,6 +372,15 @@
// Operations
///////////////////////////////////////////////////////////////////////////////
+DisplayList* DisplayListRenderer::getDisplayList() {
+ if (mDisplayList == NULL) {
+ mDisplayList = new DisplayList(*this);
+ } else {
+ mDisplayList->initFromDisplayListRenderer(*this);
+ }
+ return mDisplayList;
+}
+
void DisplayListRenderer::setViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b608381..fedb174 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -110,6 +110,8 @@
SetupShadow
};
+ void initFromDisplayListRenderer(const DisplayListRenderer& recorder);
+
void replay(OpenGLRenderer& renderer);
private:
@@ -216,6 +218,8 @@
DisplayListRenderer();
~DisplayListRenderer();
+ DisplayList* getDisplayList();
+
void setViewport(int width, int height);
void prepare(bool opaque);
@@ -266,10 +270,6 @@
void reset();
- DisplayList* getDisplayList() const {
- return new DisplayList(*this);
- }
-
const SkWriter32& writeStream() const {
return mWriter;
}
@@ -422,6 +422,8 @@
SkRefCntRecorder mRCRecorder;
SkRefCntRecorder mTFRecorder;
+ DisplayList *mDisplayList;
+
friend class DisplayList;
}; // class DisplayListRenderer
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index b8a7a79..a42b49d 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -26,6 +26,7 @@
#include <binder/IServiceManager.h>
#include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
#include <surfaceflinger/ISurfaceComposer.h>
@@ -169,6 +170,25 @@
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(usage);
+ remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER, data,
+ &reply);
+ sp<GraphicBuffer> graphicBuffer;
+ bool nonNull = (bool)reply.readInt32();
+ if (nonNull) {
+ graphicBuffer = new GraphicBuffer();
+ reply.read(*graphicBuffer);
+ }
+ return graphicBuffer;
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -247,6 +267,18 @@
reply->writeInt32(f);
reply->writeInt32(res);
} break;
+ case CREATE_GRAPHIC_BUFFER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ PixelFormat format = data.readInt32();
+ uint32_t usage = data.readInt32();
+ sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage));
+ reply->writeInt32(result != 0);
+ if (result != 0) {
+ reply->write(*result);
+ }
+ } break;
case TURN_ELECTRON_BEAM_OFF: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
int32_t mode = data.readInt32();
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 97c541a..439e4ce 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -733,8 +733,8 @@
}
char value[PROPERTY_VALUE_MAX];
- if (property_get("media.httplive.enable-nuplayer", value, NULL)
- && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
+ if (!property_get("media.httplive.disable-nuplayer", value, NULL)
+ || (strcasecmp(value, "true") && strcmp(value, "1"))) {
if (!strncasecmp("http://", url, 7)) {
size_t len = strlen(url);
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index f63774a..8efd963 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1506,7 +1506,7 @@
OMXCodec::~OMXCodec() {
mSource.clear();
- CHECK(mState == LOADED || mState == ERROR);
+ CHECK(mState == LOADED || mState == ERROR || mState == LOADED_TO_IDLE);
status_t err = mOMX->freeNode(mNode);
CHECK_EQ(err, (status_t)OK);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 6331a63..8cd2998 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -238,7 +238,7 @@
(OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
CHECK(converter.isValid());
- converter.convert(
+ err = converter.convert(
(const uint8_t *)buffer->data() + buffer->range_offset(),
width, height,
crop_left, crop_top, crop_right, crop_bottom,
@@ -252,6 +252,13 @@
decoder->stop();
+ if (err != OK) {
+ LOGE("Colorconverter failed to convert frame.");
+
+ delete frame;
+ frame = NULL;
+ }
+
return frame;
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 600f040..d518c97 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -16,6 +16,7 @@
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -72,7 +73,7 @@
return mCropBottom - mCropTop + 1;
}
-void ColorConverter::convert(
+status_t ColorConverter::convert(
const void *srcBits,
size_t srcWidth, size_t srcHeight,
size_t srcCropLeft, size_t srcCropTop,
@@ -81,7 +82,9 @@
size_t dstWidth, size_t dstHeight,
size_t dstCropLeft, size_t dstCropTop,
size_t dstCropRight, size_t dstCropBottom) {
- CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
+ if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
+ return ERROR_UNSUPPORTED;
+ }
BitmapParams src(
const_cast<void *>(srcBits),
@@ -93,21 +96,23 @@
dstWidth, dstHeight,
dstCropLeft, dstCropTop, dstCropRight, dstCropBottom);
+ status_t err;
+
switch (mSrcFormat) {
case OMX_COLOR_FormatYUV420Planar:
- convertYUV420Planar(src, dst);
+ err = convertYUV420Planar(src, dst);
break;
case OMX_COLOR_FormatCbYCrY:
- convertCbYCrY(src, dst);
+ err = convertCbYCrY(src, dst);
break;
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
- convertQCOMYUV420SemiPlanar(src, dst);
+ err = convertQCOMYUV420SemiPlanar(src, dst);
break;
case OMX_COLOR_FormatYUV420SemiPlanar:
- convertYUV420SemiPlanar(src, dst);
+ err = convertYUV420SemiPlanar(src, dst);
break;
default:
@@ -116,17 +121,21 @@
break;
}
}
+
+ return err;
}
-void ColorConverter::convertCbYCrY(
+status_t ColorConverter::convertCbYCrY(
const BitmapParams &src, const BitmapParams &dst) {
// XXX Untested
uint8_t *kAdjustedClip = initClip();
- CHECK((src.mCropLeft & 1) == 0);
- CHECK_EQ(src.cropWidth(), dst.cropWidth());
- CHECK_EQ(src.cropHeight(), dst.cropHeight());
+ if (!((src.mCropLeft & 1) == 0
+ && src.cropWidth() == dst.cropWidth()
+ && src.cropHeight() == dst.cropHeight())) {
+ return ERROR_UNSUPPORTED;
+ }
uint32_t *dst_ptr = (uint32_t *)dst.mBits
+ (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -172,16 +181,20 @@
src_ptr += src.mWidth * 2;
dst_ptr += dst.mWidth / 2;
}
+
+ return OK;
}
-void ColorConverter::convertYUV420Planar(
+status_t ColorConverter::convertYUV420Planar(
const BitmapParams &src, const BitmapParams &dst) {
- uint8_t *kAdjustedClip = initClip();
+ if (!((dst.mWidth & 3) == 0
+ && (src.mCropLeft & 1) == 0
+ && src.cropWidth() == dst.cropWidth()
+ && src.cropHeight() == dst.cropHeight())) {
+ return ERROR_UNSUPPORTED;
+ }
- CHECK((dst.mWidth & 3) == 0);
- CHECK((src.mCropLeft & 1) == 0);
- CHECK_EQ(src.cropWidth(), dst.cropWidth());
- CHECK_EQ(src.cropHeight(), dst.cropHeight());
+ uint8_t *kAdjustedClip = initClip();
uint32_t *dst_ptr = (uint32_t *)dst.mBits
+ (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -259,16 +272,20 @@
dst_ptr += dst.mWidth / 2;
}
+
+ return OK;
}
-void ColorConverter::convertQCOMYUV420SemiPlanar(
+status_t ColorConverter::convertQCOMYUV420SemiPlanar(
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *kAdjustedClip = initClip();
- CHECK((dst.mWidth & 3) == 0);
- CHECK((src.mCropLeft & 1) == 0);
- CHECK_EQ(src.cropWidth(), dst.cropWidth());
- CHECK_EQ(src.cropHeight(), dst.cropHeight());
+ if (!((dst.mWidth & 3) == 0
+ && (src.mCropLeft & 1) == 0
+ && src.cropWidth() == dst.cropWidth()
+ && src.cropHeight() == dst.cropHeight())) {
+ return ERROR_UNSUPPORTED;
+ }
uint32_t *dst_ptr = (uint32_t *)dst.mBits
+ (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -324,18 +341,22 @@
dst_ptr += dst.mWidth / 2;
}
+
+ return OK;
}
-void ColorConverter::convertYUV420SemiPlanar(
+status_t ColorConverter::convertYUV420SemiPlanar(
const BitmapParams &src, const BitmapParams &dst) {
// XXX Untested
uint8_t *kAdjustedClip = initClip();
- CHECK((dst.mWidth & 3) == 0);
- CHECK((src.mCropLeft & 1) == 0);
- CHECK_EQ(src.cropWidth(), dst.cropWidth());
- CHECK_EQ(src.cropHeight(), dst.cropHeight());
+ if (!((dst.mWidth & 3) == 0
+ && (src.mCropLeft & 1) == 0
+ && src.cropWidth() == dst.cropWidth()
+ && src.cropHeight() == dst.cropHeight())) {
+ return ERROR_UNSUPPORTED;
+ }
uint32_t *dst_ptr = (uint32_t *)dst.mBits
+ (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
@@ -391,6 +412,8 @@
dst_ptr += dst.mWidth / 2;
}
+
+ return OK;
}
uint8_t *ColorConverter::initClip() {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 6fd0171..9e63c41 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -158,8 +158,8 @@
mBandwidthItems.sort(SortByBandwidth);
char value[PROPERTY_VALUE_MAX];
- if (!property_get("media.httplive.enable-nuplayer", value, NULL)
- || (strcasecmp(value, "true") && strcmp(value, "1"))) {
+ if (property_get("media.httplive.disable-nuplayer", value, NULL)
+ && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
// The "legacy" player cannot deal with audio format changes,
// some streams use different audio encoding parameters for
// their lowest bandwidth stream.
@@ -340,6 +340,7 @@
void LiveSession::onDownloadNext() {
size_t bandwidthIndex = getBandwidthIndex();
+rinse_repeat:
int64_t nowUs = ALooper::GetNowUs();
if (mLastPlaylistFetchTimeUs < 0
@@ -437,6 +438,18 @@
if (mSeqNumber < firstSeqNumberInPlaylist
|| mSeqNumber > lastSeqNumberInPlaylist) {
+ if (mSeqNumber < firstSeqNumberInPlaylist
+ && mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
+ // Go back to the previous bandwidth.
+
+ LOGI("new bandwidth does not have the sequence number "
+ "we're looking for, switching back to previous bandwidth");
+
+ mLastPlaylistFetchTimeUs = -1;
+ bandwidthIndex = mPrevBandwidthIndex;
+ goto rinse_repeat;
+ }
+
if (!mPlaylist->isComplete()
&& mSeqNumber > lastSeqNumberInPlaylist
&& mNumRetries < kMaxNumRetries) {
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 87975af..b52fc69 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -49,7 +49,8 @@
libcutils \
libmedia \
libcamera_client \
- libsurfaceflinger_client
+ libsurfaceflinger_client \
+ libgui
LOCAL_MODULE:= libcameraservice
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 15f6a44..3d8ca7a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -27,6 +27,7 @@
#include <binder/MemoryHeapBase.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
+#include <gui/SurfaceTextureClient.h>
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
#include <media/mediaplayer.h>
@@ -306,6 +307,8 @@
mCameraFacing = cameraFacing;
mClientPid = clientPid;
mMsgEnabled = 0;
+ mSurface = 0;
+ mPreviewWindow = 0;
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
@@ -470,19 +473,16 @@
// return if no change in surface.
// asBinder() is safe on NULL (returns NULL)
- if (getISurface(surface)->asBinder() == mSurface->asBinder()) {
+ if (getISurface(surface)->asBinder() == mSurface) {
return result;
}
if (mSurface != 0) {
LOG1("clearing old preview surface %p", mSurface.get());
}
- if (surface != 0) {
- mSurface = getISurface(surface);
- } else {
- mSurface = 0;
- }
+ mSurface = getISurface(surface)->asBinder();
mPreviewWindow = surface;
+
// If preview has been already started, register preview
// buffers now.
if (mHardware->previewEnabled()) {
@@ -496,6 +496,45 @@
return result;
}
+// set the SurfaceTexture that the preview will use
+status_t CameraService::Client::setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
+ getCallingPid());
+ Mutex::Autolock lock(mLock);
+ status_t result = checkPidAndHardware();
+ if (result != NO_ERROR) return result;
+
+ // return if no change in surface.
+ // asBinder() is safe on NULL (returns NULL)
+ if (surfaceTexture->asBinder() == mSurface) {
+ return result;
+ }
+
+ if (mSurface != 0) {
+ LOG1("clearing old preview surface %p", mSurface.get());
+ }
+ mSurface = surfaceTexture->asBinder();
+ if (surfaceTexture != 0) {
+ mPreviewWindow = new SurfaceTextureClient(surfaceTexture);
+ } else {
+ mPreviewWindow = 0;
+ }
+
+ // If preview has been already started, set overlay or register preview
+ // buffers now.
+ if (mHardware->previewEnabled()) {
+ // XXX: What if the new preview window is 0?
+ if (mPreviewWindow != 0) {
+ native_window_set_buffers_transform(mPreviewWindow.get(),
+ mOrientation);
+ result = mHardware->setPreviewWindow(mPreviewWindow);
+ }
+ }
+
+ return result;
+}
+
// set the preview callback flag to affect how the received frames from
// preview are handled.
void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
@@ -960,23 +999,6 @@
}
disableMsgType(CAMERA_MSG_SHUTTER);
- // It takes some time before yuvPicture callback to be called.
- // Register the buffer for raw image here to reduce latency.
- if (mSurface != 0) {
- int w, h;
- CameraParameters params(mHardware->getParameters());
- if (size == NULL) {
- params.getPictureSize(&w, &h);
- } else {
- w = size->width;
- h = size->height;
- w &= ~1;
- h &= ~1;
- LOG1("Snapshot image width=%d, height=%d", w, h);
- }
- IPCThreadState::self()->flushCommands();
- }
-
mLock.unlock();
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d78d7e5..ccb9cf7 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -94,6 +94,7 @@
virtual status_t lock();
virtual status_t unlock();
virtual status_t setPreviewDisplay(const sp<Surface>& surface);
+ virtual status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
virtual void setPreviewCallbackFlag(int flag);
virtual status_t startPreview();
virtual void stopPreview();
@@ -180,7 +181,8 @@
// Ensures atomicity among the public methods
mutable Mutex mLock;
- sp<ISurface> mSurface;
+ // This is a binder of Surface or SurfaceTexture.
+ sp<IBinder> mSurface;
sp<ANativeWindow> mPreviewWindow;
// If the user want us to return a copy of the preview frame (instead
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 825d90b..c982ea5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2267,6 +2267,25 @@
// ---------------------------------------------------------------------------
+sp<GraphicBuffer> SurfaceFlinger::createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) const {
+ // XXX: HACK HACK HACK!!! This should NOT be static, but it is to fix a
+ // race between SurfaceFlinger unref'ing the buffer and the client ref'ing
+ // it.
+ static sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+ status_t err = graphicBuffer->initCheck();
+ if (err != 0) {
+ LOGE("createGraphicBuffer: init check failed: %d", err);
+ return 0;
+ } else if (graphicBuffer->handle == 0) {
+ LOGE("createGraphicBuffer: unable to create GraphicBuffer");
+ return 0;
+ }
+ return graphicBuffer;
+}
+
+// ---------------------------------------------------------------------------
+
Client::Client(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger), mNameGenerator(1)
{
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ca7d27d..48642d4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -322,6 +322,8 @@
status_t electronBeamOnAnimationImplLocked();
status_t renderScreenToTextureLocked(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) const;
friend class FreezeLock;
sp<FreezeLock> getFreezeLock() const;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 5f40854..7a95c09 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -180,12 +180,9 @@
return mCapabilities;
}
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutLibBridge#init(java.io.File, java.util.Map)
- */
@Override
- public boolean init(File fontLocation, Map<String, Map<String, Integer>> enumValueMap) {
+ public boolean init(File fontLocation, Map<String, Map<String, Integer>> enumValueMap,
+ LayoutLog log) {
sEnumValueMap = enumValueMap;
// don't use EnumSet.allOf(), because the bridge doesn't come with its specific version
@@ -242,11 +239,6 @@
// now parse com.android.internal.R (and only this one as android.R is a subset of
// the internal version), and put the content in the maps.
try {
- // WARNING: this only works because the class is already loaded, and therefore
- // the objects returned by Field.get() are the same as the ones used by
- // the code accessing the R class.
- // int[] does not implement equals/hashCode, and if the parsing used a different class
- // loader for the R class, this would NOT work.
Class<?> r = com.android.internal.R.class;
for (Class<?> inner : r.getDeclaredClasses()) {
@@ -262,7 +254,9 @@
if (Modifier.isStatic(modifiers)) {
Class<?> type = f.getType();
if (type.isArray() && type.getComponentType() == int.class) {
- // if the object is an int[] we put it in sRArrayMap
+ // if the object is an int[] we put it in sRArrayMap using an IntArray
+ // wrapper that properly implements equals and hashcode for the array
+ // objects, as required by the map contract.
sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
} else if (type == int.class) {
Integer value = (Integer) f.get(null);
@@ -274,12 +268,12 @@
}
}
}
- } catch (IllegalArgumentException e) {
- // FIXME: log/return the error (there's no logger object at this point!)
- e.printStackTrace();
- return false;
- } catch (IllegalAccessException e) {
- e.printStackTrace();
+ } catch (Throwable throwable) {
+ if (log != null) {
+ log.error(null,
+ "Failed to load com.android.internal.R from the layout library jar",
+ throwable);
+ }
return false;
}