merge master in master_gl
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 81639ad..2f4a1c9 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -32,6 +32,7 @@
 #include <media/AudioSystem.h>
 #include "CameraService.h"
 
+#include <cutils/atomic.h>
 #include <cutils/properties.h>
 
 namespace android {
@@ -42,6 +43,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <pthread.h>
+#include <signal.h>
 }
 
 // When you enable this, as well as DEBUG_REFS=1 and
@@ -63,6 +65,10 @@
 static int debug_frame_cnt;
 #endif
 
+static int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
 // ----------------------------------------------------------------------------
 
 void CameraService::instantiate() {
@@ -76,6 +82,7 @@
     BnCameraService()
 {
     LOGI("CameraService started: pid=%d", getpid());
+    mUsers = 0;
 }
 
 CameraService::~CameraService()
@@ -87,7 +94,9 @@
 
 sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
 {
-    LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
+    int callingPid = getCallingPid();
+    LOGD("CameraService::connect E (pid %d, client %p)", callingPid,
+            cameraClient->asBinder().get());
 
     Mutex::Autolock lock(mLock);
     sp<Client> client;
@@ -96,36 +105,50 @@
         if (currentClient != 0) {
             sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
             if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
-                // this is the same client reconnecting...
-                LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get());
+                // This is the same client reconnecting...
+                LOGD("CameraService::connect X (pid %d, same client %p) is reconnecting...",
+                    callingPid, cameraClient->asBinder().get());
                 return currentClient;
             } else {
-                // it's another client... reject it
-                LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get());
+                // It's another client... reject it
+                LOGD("CameraService::connect X (pid %d, new client %p) rejected. "
+                    "(old pid %d, old client %p)",
+                    callingPid, cameraClient->asBinder().get(),
+                    currentClient->mClientPid, currentCameraClient->asBinder().get());
+                if (kill(currentClient->mClientPid, 0) == -1 && errno == ESRCH) {
+                    LOGD("The old client is dead!");
+                }
                 return client;
             }
         } else {
             // can't promote, the previous client has died...
-            LOGD("new client connecting, old reference was dangling...");
+            LOGD("New client (pid %d) connecting, old reference was dangling...",
+                    callingPid);
             mClient.clear();
+            if (mUsers > 0) {
+                LOGD("Still have client, rejected");
+                return client;
+            }
         }
     }
 
     // create a new Client object
-    client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
+    client = new Client(this, cameraClient, callingPid);
     mClient = client;
 #if DEBUG_CLIENT_REFERENCES
     // Enable tracking for this object, and track increments and decrements of
     // the refcount.
     client->trackMe(true, true);
 #endif
-    LOGD("Connect X");
+    LOGD("CameraService::connect X");
     return client;
 }
 
 void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
 {
-    // declar this outside the lock to make absolutely sure the
+    int callingPid = getCallingPid();
+
+    // Declare this outside the lock to make absolutely sure the
     // destructor won't be called with the lock held.
     sp<Client> client;
 
@@ -133,26 +156,42 @@
 
     if (mClient == 0) {
         // This happens when we have already disconnected.
-        LOGV("mClient is null.");
+        LOGD("removeClient (pid %d): already disconnected", callingPid);
         return;
     }
 
-    // Promote mClient. It should never fail because we're called from
-    // a binder call, so someone has to have a strong reference.
+    // Promote mClient. It can fail if we are called from this path:
+    // Client::~Client() -> disconnect() -> removeClient().
     client = mClient.promote();
     if (client == 0) {
-        LOGW("can't get a strong reference on mClient!");
+        LOGD("removeClient (pid %d): no more strong reference", callingPid);
         mClient.clear();
         return;
     }
 
     if (cameraClient->asBinder() != client->getCameraClient()->asBinder()) {
         // ugh! that's not our client!!
-        LOGW("removeClient() called, but mClient doesn't match!");
+        LOGW("removeClient (pid %d): mClient doesn't match!", callingPid);
     } else {
         // okay, good, forget about mClient
         mClient.clear();
     }
+
+    LOGD("removeClient (pid %d) done", callingPid);
+}
+
+// The reason we need this count is a new CameraService::connect() request may
+// come in while the previous Client's destructor has not been run or is still
+// running. If the last strong reference of the previous Client is gone but
+// destructor has not been run, we should not allow the new Client to be created
+// because we need to wait for the previous Client to tear down the hardware
+// first.
+void CameraService::incUsers() {
+    android_atomic_inc(&mUsers);
+}
+
+void CameraService::decUsers() {
+    android_atomic_dec(&mUsers);
 }
 
 static sp<MediaPlayer> newMediaPlayer(const char *file) 
@@ -177,7 +216,8 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient, pid_t clientPid)
 {
-    LOGD("Client E constructor");
+    int callingPid = getCallingPid();
+    LOGD("Client::Client E (pid %d)", callingPid);
     mCameraService = cameraService;
     mCameraClient = cameraClient;
     mClientPid = clientPid;
@@ -189,22 +229,28 @@
 
     // Callback is disabled by default
     mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-    LOGD("Client X constructor");
+    cameraService->incUsers();
+    LOGD("Client::Client X (pid %d)", callingPid);
 }
 
 status_t CameraService::Client::checkPid()
 {
-    if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
-    LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get());
+    int callingPid = getCallingPid();
+    if (mClientPid == callingPid) return NO_ERROR;
+    LOGW("Attempt to use locked camera (client %p) from different process "
+        " (old pid %d, new pid %d)",
+        getCameraClient()->asBinder().get(), mClientPid, callingPid);
     return -EBUSY;
 }
 
 status_t CameraService::Client::lock()
 {
+    int callingPid = getCallingPid();
+    LOGD("lock from pid %d (mClientPid %d)", callingPid, mClientPid);
     Mutex::Autolock _l(mLock);
     // lock camera to this client if the the camera is unlocked
     if (mClientPid == 0) {
-        mClientPid = IPCThreadState::self()->getCallingPid();
+        mClientPid = callingPid;
         return NO_ERROR;
     }
     // returns NO_ERROR if the client already owns the camera, -EBUSY otherwise
@@ -213,13 +259,14 @@
 
 status_t CameraService::Client::unlock()
 {
+    int callingPid = getCallingPid();
+    LOGD("unlock from pid %d (mClientPid %d)", callingPid, mClientPid);    
     Mutex::Autolock _l(mLock);
     // allow anyone to use camera
-    LOGD("unlock (%p)", getCameraClient()->asBinder().get());
     status_t result = checkPid();
     if (result == NO_ERROR) {
         mClientPid = 0;
-
+        LOGD("clear mCameraClient (pid %d)", callingPid);
         // we need to remove the reference so that when app goes
         // away, the reference count goes to 0.
         mCameraClient.clear();
@@ -229,15 +276,17 @@
 
 status_t CameraService::Client::connect(const sp<ICameraClient>& client)
 {
+    int callingPid = getCallingPid();
+
     // connect a new process to the camera
-    LOGD("connect (%p)", client->asBinder().get());
+    LOGD("Client::connect E (pid %d, client %p)", callingPid, client->asBinder().get());
 
     // I hate this hack, but things get really ugly when the media recorder
     // service is handing back the camera to the app. The ICameraClient
     // destructor will be called during the same IPC, making it look like
     // the remote client is trying to disconnect. This hack temporarily
     // sets the mClientPid to an invalid pid to prevent the hardware from
-    //  being torn down.
+    // being torn down.
     {
 
         // hold a reference to the old client or we will deadlock if the client is
@@ -246,24 +295,29 @@
         {
             Mutex::Autolock _l(mLock);
             if (mClientPid != 0 && checkPid() != NO_ERROR) {
-                LOGW("Tried to connect to locked camera");
+                LOGW("Tried to connect to locked camera (old pid %d, new pid %d)",
+                        mClientPid, callingPid);
                 return -EBUSY;
             }
             oldClient = mCameraClient;
 
             // did the client actually change?
-            if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+            if (client->asBinder() == mCameraClient->asBinder()) {
+                LOGD("Connect to the same client");
+                return NO_ERROR;
+            }
 
             mCameraClient = client;
             mClientPid = -1;
             mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-            LOGD("connect new process (%d) to existing camera client", mClientPid);
+            LOGD("Connect to the new client (pid %d, client %p)",
+                callingPid, mCameraClient->asBinder().get());
         }
 
     }
     // the old client destructor is called when oldClient goes out of scope
     // now we set the new PID to lock the interface again
-    mClientPid = IPCThreadState::self()->getCallingPid();
+    mClientPid = callingPid;
 
     return NO_ERROR;
 }
@@ -280,8 +334,11 @@
 
 CameraService::Client::~Client()
 {
+    int callingPid = getCallingPid();
+
     // tear down client
-    LOGD("Client (%p)  E destructor", getCameraClient()->asBinder().get());
+    LOGD("Client::~Client E (pid %d, client %p)",
+            callingPid, getCameraClient()->asBinder().get());
     if (mSurface != 0 && !mUseOverlay) {
 #if HAVE_ANDROID_OS
         pthread_t thr;
@@ -307,19 +364,21 @@
     }
 
     // make sure we tear down the hardware
-    mClientPid = IPCThreadState::self()->getCallingPid();
+    mClientPid = callingPid;
     disconnect();
-    LOGD("Client X destructor");
+    LOGD("Client::~Client X (pid %d)", mClientPid);
 }
 
 void CameraService::Client::disconnect()
 {
-    LOGD("Client (%p) E disconnect from (%d)",
-            getCameraClient()->asBinder().get(),
-            IPCThreadState::self()->getCallingPid());
+    int callingPid = getCallingPid();
+
+    LOGD("Client::disconnect() E (pid %d client %p)",
+            callingPid, getCameraClient()->asBinder().get());
+
     Mutex::Autolock lock(mLock);
     if (mClientPid <= 0) {
-        LOGD("camera is unlocked, don't tear down hardware");
+        LOGD("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
         return;
     }
     if (checkPid() != NO_ERROR) {
@@ -327,25 +386,31 @@
         return;
     }
 
+    // Make sure disconnect() is done once and once only, whether it is called
+    // from the user directly, or called by the destructor.
+    if (mHardware == 0) return;
+
     mCameraService->removeClient(mCameraClient);
-    if (mHardware != 0) {
-        LOGD("hardware teardown");
-        // Before destroying mHardware, we must make sure it's in the
-        // idle state.
-        mHardware->stopPreview();
-        // Cancel all picture callbacks.
-        mHardware->cancelPicture(true, true, true);
-        // Release the hardware resources.
-        mHardware->release();
-    }
+
+    LOGD("hardware teardown");
+    // Before destroying mHardware, we must make sure it's in the
+    // idle state.
+    mHardware->stopPreview();
+    // Cancel all picture callbacks.
+    mHardware->cancelPicture(true, true, true);
+    // Release the hardware resources.
+    mHardware->release();
     mHardware.clear();
-    LOGD("Client X disconnect");
+
+    mCameraService->decUsers();
+
+    LOGD("Client::disconnect() X (pid %d)", callingPid);
 }
 
 // pass the buffered ISurface to the camera service
 status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
 {
-    LOGD("setPreviewDisplay(%p)", surface.get());
+    LOGD("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
     if (result != NO_ERROR) return result;
@@ -365,7 +430,7 @@
 // preview are handled.
 void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
 {
-    LOGV("setPreviewCallbackFlag");
+    LOGV("setPreviewCallbackFlag (pid %d)", getCallingPid());
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
     mPreviewCallbackFlag = callback_flag;
@@ -374,7 +439,9 @@
 // start preview mode, must call setPreviewDisplay first
 status_t CameraService::Client::startCameraMode(camera_mode mode)
 {
-    LOGD("startCameraMode(%d)", mode);
+    int callingPid = getCallingPid();
+
+    LOGD("startCameraMode(%d) (pid %d)", mode, callingPid);
 
     /* we cannot call into mHardware with mLock held because
      * mHardware has callbacks onto us which acquire this lock
@@ -405,7 +472,7 @@
 
 status_t CameraService::Client::startRecordingMode()
 {
-    LOGV("startRecordingMode");
+    LOGD("startRecordingMode (pid %d)", getCallingPid());
 
     status_t ret = UNKNOWN_ERROR;
 
@@ -433,7 +500,7 @@
 
 status_t CameraService::Client::startPreviewMode()
 {
-    LOGV("startPreviewMode");
+    LOGD("startPreviewMode (pid %d)", getCallingPid());
 
     // if preview has been enabled, nothing needs to be done
     if (mHardware->previewEnabled()) {
@@ -500,11 +567,15 @@
 
 status_t CameraService::Client::startPreview()
 {
+    LOGD("startPreview (pid %d)", getCallingPid());
+    
     return startCameraMode(CAMERA_PREVIEW_MODE);
 }
 
 status_t CameraService::Client::startRecording()
 {
+    LOGD("startRecording (pid %d)", getCallingPid());
+
     if (mMediaPlayerBeep.get() != NULL) {
         mMediaPlayerBeep->seekTo(0);
         mMediaPlayerBeep->start();
@@ -515,7 +586,7 @@
 // stop preview mode
 void CameraService::Client::stopPreview()
 {
-    LOGD("stopPreview()");
+    LOGD("stopPreview (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
@@ -537,7 +608,7 @@
 // stop recording mode
 void CameraService::Client::stopRecording()
 {
-    LOGV("stopRecording()");
+    LOGD("stopRecording (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
@@ -552,15 +623,13 @@
         mMediaPlayerBeep->start();
     }
     mHardware->stopRecording();
-    LOGV("stopRecording(), hardware stopped OK");
+    LOGD("stopRecording(), hardware stopped OK");
     mPreviewBuffer.clear();
 }
 
 // release a recording frame
 void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
 {
-    LOGV("releaseRecordingFrame()");
-
     Mutex::Autolock lock(mLock);
     if (checkPid() != NO_ERROR) return;
 
@@ -704,7 +773,7 @@
 // take a picture - image is returned in callback
 status_t CameraService::Client::autoFocus()
 {
-    LOGV("autoFocus");
+    LOGD("autoFocus (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -722,7 +791,7 @@
 // take a picture - image is returned in callback
 status_t CameraService::Client::takePicture()
 {
-    LOGD("takePicture");
+    LOGD("takePicture (pid %d)", getCallingPid());
 
     Mutex::Autolock lock(mLock);
     status_t result = checkPid();
@@ -920,6 +989,7 @@
 
 void CameraService::Client::postShutter()
 {
+    LOGD("postShutter");
     mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
 }
 
@@ -1029,7 +1099,7 @@
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         snprintf(buffer, SIZE, "Permission Denial: "
                 "can't dump CameraService from pid=%d, uid=%d\n",
-                IPCThreadState::self()->getCallingPid(),
+                getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
         result.append(buffer);
         write(fd, result.string(), result.size());
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index a421fd3..729e539 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -194,6 +194,11 @@
                             CameraService();
     virtual                 ~CameraService();
 
+    // We use a count for number of clients (shoule only be 0 or 1).
+    volatile    int32_t                     mUsers;
+    virtual     void                        incUsers();
+    virtual     void                        decUsers();
+
     mutable     Mutex                       mLock;
                 wp<Client>                  mClient;
 
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 3b40677..523aed0 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -458,7 +458,7 @@
     void validate();
     matrixf_t& top() { return stack[depth]; }
     const matrixf_t& top() const { return stack[depth]; }
-    const uint32_t top_ops() const { return ops[depth]; }
+    uint32_t top_ops() const { return ops[depth]; }
     inline bool isRigidBody() const {
         return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE));
     }
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 048bdd5..bbc21c4 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -86,10 +86,13 @@
 class Mutex;
 class String8;
 
-typedef void (*shutter_callback)(void *cookie);
-typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
-typedef void (*autofocus_callback)(bool focused, void *cookie);
-typedef void (*error_callback)(status_t err, void *cookie);
+// ref-counted object for callbacks
+class CameraListener: virtual public RefBase
+{
+public:
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+    virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+};
 
 class Camera : public BnCameraClient, public IBinder::DeathRecipient
 {
@@ -144,13 +147,8 @@
             // get preview/capture parameters - key/value pairs
             String8     getParameters() const;
 
-            void        setShutterCallback(shutter_callback cb, void *cookie);
-            void        setRawCallback(frame_callback cb, void *cookie);
-            void        setJpegCallback(frame_callback cb, void *cookie);
-            void        setRecordingCallback(frame_callback cb, void *cookie);
-            void        setPreviewCallback(frame_callback cb, void *cookie, int preview_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
-            void        setErrorCallback(error_callback cb, void *cookie);
-            void        setAutoFocusCallback(autofocus_callback cb, void *cookie);
+            void        setListener(const sp<CameraListener>& listener);
+            void        setPreviewCallbackFlags(int preview_callback_flag);
 
     // ICameraClient interface
     virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
@@ -160,6 +158,8 @@
 
 private:
                         Camera();
+                        Camera(const Camera&);
+                        Camera& operator=(const Camera);
                         virtual void binderDied(const wp<IBinder>& who);
 
             class DeathNotifier: public IBinder::DeathRecipient
@@ -179,20 +179,7 @@
             sp<ICamera>         mCamera;
             status_t            mStatus;
 
-            shutter_callback    mShutterCallback;
-            void                *mShutterCallbackCookie;
-            frame_callback      mRawCallback;
-            void                *mRawCallbackCookie;
-            frame_callback      mJpegCallback;
-            void                *mJpegCallbackCookie;
-            frame_callback      mPreviewCallback;
-            void                *mPreviewCallbackCookie;
-            frame_callback      mRecordingCallback;
-            void                *mRecordingCallbackCookie;
-            error_callback      mErrorCallback;
-            void                *mErrorCallbackCookie;
-            autofocus_callback  mAutoFocusCallback;
-            void                *mAutoFocusCallbackCookie;
+            sp<CameraListener>  mListener;
 
             friend class DeathNotifier;
 
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index c78b99a..b1f5045 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -43,6 +43,7 @@
 struct FileState {
     int modTime_sec;
     int modTime_nsec;
+    int mode;
     int size;
     int crc32;
     int nameLen;
@@ -71,6 +72,8 @@
     status_t WriteEntityHeader(const String8& key, size_t dataSize);
     status_t WriteEntityData(const void* data, size_t size);
 
+    void SetKeyPrefix(const String8& keyPrefix);
+
 private:
     explicit BackupDataWriter();
     status_t write_padding_for(int n);
@@ -79,6 +82,7 @@
     status_t m_status;
     ssize_t m_pos;
     int m_entityCount;
+    String8 m_keyPrefix;
 };
 
 /**
@@ -133,6 +137,7 @@
 
 private:
     void* m_buf;
+    bool m_loggedUnknownMetadata;
     KeyedVector<String8,FileRec> m_files;
 };
 
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 68f9233..f1029b7 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -71,7 +71,7 @@
  * The relative sizes of the stretchy segments indicates the relative
  * amount of stretchiness of the regions bordered by the segments.  For
  * example, regions 3, 7 and 11 above will take up more horizontal space
- * than regions 1, 5 and 9 since the horizonal segment associated with
+ * than regions 1, 5 and 9 since the horizontal segment associated with
  * the first set of regions is larger than the other set of regions.  The
  * ratios of the amount of horizontal (or vertical) space taken by any
  * two stretchable slices is exactly the ratio of their corresponding
@@ -87,7 +87,7 @@
  * the leftmost slices always start at x=0 and the rightmost slices
  * always end at the end of the image. So, for example, the regions 0,
  * 4 and 8 (which are fixed along the X axis) start at x value 0 and
- * go to xDiv[0] amd slices 2, 6 and 10 start at xDiv[1] and end at
+ * go to xDiv[0] and slices 2, 6 and 10 start at xDiv[1] and end at
  * xDiv[2].
  *
  * The array pointed to by the colors field lists contains hints for
@@ -626,25 +626,25 @@
     event_code_t next();
 
     // These are available for all nodes:
-    const int32_t getCommentID() const;
+    int32_t getCommentID() const;
     const uint16_t* getComment(size_t* outLen) const;
-    const uint32_t getLineNumber() const;
+    uint32_t getLineNumber() const;
     
     // This is available for TEXT:
-    const int32_t getTextID() const;
+    int32_t getTextID() const;
     const uint16_t* getText(size_t* outLen) const;
     ssize_t getTextValue(Res_value* outValue) const;
     
     // These are available for START_NAMESPACE and END_NAMESPACE:
-    const int32_t getNamespacePrefixID() const;
+    int32_t getNamespacePrefixID() const;
     const uint16_t* getNamespacePrefix(size_t* outLen) const;
-    const int32_t getNamespaceUriID() const;
+    int32_t getNamespaceUriID() const;
     const uint16_t* getNamespaceUri(size_t* outLen) const;
     
     // These are available for START_TAG and END_TAG:
-    const int32_t getElementNamespaceID() const;
+    int32_t getElementNamespaceID() const;
     const uint16_t* getElementNamespace(size_t* outLen) const;
-    const int32_t getElementNameID() const;
+    int32_t getElementNameID() const;
     const uint16_t* getElementName(size_t* outLen) const;
     
     // Remaining methods are for retrieving information about attributes
@@ -653,14 +653,14 @@
     size_t getAttributeCount() const;
     
     // Returns -1 if no namespace, -2 if idx out of range.
-    const int32_t getAttributeNamespaceID(size_t idx) const;
+    int32_t getAttributeNamespaceID(size_t idx) const;
     const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
     
-    const int32_t getAttributeNameID(size_t idx) const;
+    int32_t getAttributeNameID(size_t idx) const;
     const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
-    const uint32_t getAttributeNameResID(size_t idx) const;
+    uint32_t getAttributeNameResID(size_t idx) const;
     
-    const int32_t getAttributeValueStringID(size_t idx) const;
+    int32_t getAttributeValueStringID(size_t idx) const;
     const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
     
     int32_t getAttributeDataType(size_t idx) const;
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 4228300..33b99b9 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -85,20 +85,6 @@
 void Camera::init()
 {
     mStatus = UNKNOWN_ERROR;
-    mShutterCallback = 0;
-    mShutterCallbackCookie = 0;
-    mRawCallback = 0;
-    mRawCallbackCookie = 0;
-    mJpegCallback = 0;
-    mJpegCallbackCookie = 0;
-    mPreviewCallback = 0;
-    mPreviewCallbackCookie = 0;
-    mRecordingCallback = 0;
-    mRecordingCallbackCookie = 0;
-    mErrorCallback = 0;
-    mErrorCallbackCookie = 0;
-    mAutoFocusCallback = 0;
-    mAutoFocusCallbackCookie = 0;
 }
 
 Camera::~Camera()
@@ -127,7 +113,6 @@
 {
     LOGV("disconnect");
     if (mCamera != 0) {
-        mErrorCallback = 0;
         mCamera->disconnect();
         mCamera = 0;
     }
@@ -285,125 +270,49 @@
     return params;
 }
 
-void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
+void Camera::setListener(const sp<CameraListener>& listener)
 {
-    LOGV("setAutoFocusCallback");
-    mAutoFocusCallback = cb;
-    mAutoFocusCallbackCookie = cookie;
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
 }
 
-void Camera::setShutterCallback(shutter_callback cb, void *cookie)
+void Camera::setPreviewCallbackFlags(int flag)
 {
-    LOGV("setShutterCallback");
-    mShutterCallback = cb;
-    mShutterCallbackCookie = cookie;
-}
-
-void Camera::setRawCallback(frame_callback cb, void *cookie)
-{
-    LOGV("setRawCallback");
-    mRawCallback = cb;
-    mRawCallbackCookie = cookie;
-}
-
-void Camera::setJpegCallback(frame_callback cb, void *cookie)
-{
-    LOGV("setJpegCallback");
-    mJpegCallback = cb;
-    mJpegCallbackCookie = cookie;
-}
-
-void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
-{
-    LOGV("setPreviewCallback");
-    mPreviewCallback = cb;
-    mPreviewCallbackCookie = cookie;
+    LOGV("setPreviewCallbackFlags");
     sp <ICamera> c = mCamera;
     if (c == 0) return;
     mCamera->setPreviewCallbackFlag(flag);
 }
 
-void Camera::setRecordingCallback(frame_callback cb, void *cookie)
-{
-    LOGV("setRecordingCallback");
-    mRecordingCallback = cb;
-    mRecordingCallbackCookie = cookie;
-}
-
-void Camera::setErrorCallback(error_callback cb, void *cookie)
-{
-    LOGV("setErrorCallback");
-    mErrorCallback = cb;
-    mErrorCallbackCookie = cookie;
-}
-
 // callback from camera service
 void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
 {
-    switch(msgType) {
-    case CAMERA_MSG_ERROR:
-        LOGV("errorCallback");
-        if (mErrorCallback) {
-            mErrorCallback((status_t)ext1, mErrorCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_FOCUS:
-        LOGV("autoFocusCallback");
-        if (mAutoFocusCallback) {
-            mAutoFocusCallback((bool)ext1, mAutoFocusCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_SHUTTER:
-        LOGV("shutterCallback");
-        if (mShutterCallback) {
-            mShutterCallback(mShutterCallbackCookie);
-        }
-        break;
-    default:
-        LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
-        break;
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->notify(msgType, ext1, ext2);
     }
 }
 
 // callback from camera service when frame or image is ready
 void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
 {
-    switch(msgType) {
-    case CAMERA_MSG_PREVIEW_FRAME:
-        LOGV("previewCallback");
-        if (mPreviewCallback) {
-            mPreviewCallback(dataPtr, mPreviewCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_VIDEO_FRAME:
-        LOGV("recordingCallback");
-        if (mRecordingCallback) {
-            mRecordingCallback(dataPtr, mRecordingCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_RAW_IMAGE:
-        LOGV("rawCallback");
-        if (mRawCallback) {
-            mRawCallback(dataPtr, mRawCallbackCookie);
-        }
-        break;
-    case CAMERA_MSG_COMPRESSED_IMAGE:
-        LOGV("jpegCallback");
-        if (mJpegCallback) {
-            mJpegCallback(dataPtr, mJpegCallbackCookie);
-        }
-        break;
-    default:
-        LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
-        break;
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postData(msgType, dataPtr);
     }
 }
 
 void Camera::binderDied(const wp<IBinder>& who) {
     LOGW("ICamera died");
-    if (mErrorCallback) {
-        mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
-    }
+    notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0);
 }
 
 void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 6a7f056..0868cff 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -99,10 +99,20 @@
         return amt;
     }
 
+    String8 k;
+    if (m_keyPrefix.length() > 0) {
+        k = m_keyPrefix;
+        k += ":";
+        k += key;
+    } else {
+        k = key;
+    }
+    LOGD("m_keyPrefix=%s key=%s k=%s", m_keyPrefix.string(), key.string(), k.string());
+
     entity_header_v1 header;
     ssize_t keyLen;
 
-    keyLen = key.length();
+    keyLen = k.length();
 
     header.type = tolel(BACKUP_HEADER_ENTITY_V1);
     header.keyLen = tolel(keyLen);
@@ -115,7 +125,7 @@
     }
     m_pos += amt;
 
-    amt = write(m_fd, key.string(), keyLen+1);
+    amt = write(m_fd, k.string(), keyLen+1);
     if (amt != keyLen+1) {
         m_status = errno;
         return m_status;
@@ -148,6 +158,11 @@
     return NO_ERROR;
 }
 
+void
+BackupDataWriter::SetKeyPrefix(const String8& keyPrefix)
+{
+    m_keyPrefix = keyPrefix;
+}
 
 
 BackupDataReader::BackupDataReader(int fd)
@@ -298,7 +313,7 @@
     if (remaining <= 0) {
         return 0;
     }
-    if (size > remaining) {
+    if (((int)size) > remaining) {
         size = remaining;
     }
     //LOGD("   reading %d bytes", size);
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index d65a457..99a4abc 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -41,6 +41,33 @@
 #define MAGIC0 0x70616e53 // Snap
 #define MAGIC1 0x656c6946 // File
 
+/*
+ * File entity data format (v1):
+ *
+ *   - 4-byte version number of the metadata, little endian (0x00000001 for v1)
+ *   - 12 bytes of metadata
+ *   - the file data itself
+ *
+ * i.e. a 16-byte metadata header followed by the raw file data.  If the
+ * restore code does not recognize the metadata version, it can still
+ * interpret the file data itself correctly.
+ *
+ * file_metadata_v1:
+ *
+ *   - 4 byte version number === 0x00000001 (little endian)
+ *   - 4-byte access mode (little-endian)
+ *   - undefined (8 bytes)
+ */
+
+struct file_metadata_v1 {
+    int version;
+    int mode;
+    int undefined_1;
+    int undefined_2;
+};
+
+const static int CURRENT_METADATA_VERSION = 1;
+
 #if 1 // TEST_BACKUP_HELPERS
 #define LOGP(f, x...) printf(f "\n", x)
 #else
@@ -181,29 +208,48 @@
 }
 
 static int
-write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
+write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
         char const* realFilename)
 {
-    LOGP("write_update_file %s (%s)\n", realFilename, key.string());
+    LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
 
     const int bufsize = 4*1024;
     int err;
     int amt;
     int fileSize;
     int bytesLeft;
+    file_metadata_v1 metadata;
 
     char* buf = (char*)malloc(bufsize);
     int crc = crc32(0L, Z_NULL, 0);
 
 
-    bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
+    fileSize = lseek(fd, 0, SEEK_END);
     lseek(fd, 0, SEEK_SET);
 
+    if (sizeof(metadata) != 16) {
+        LOGE("ERROR: metadata block is the wrong size!");
+    }
+
+    bytesLeft = fileSize + sizeof(metadata);
     err = dataStream->WriteEntityHeader(key, bytesLeft);
     if (err != 0) {
+        free(buf);
         return err;
     }
 
+    // store the file metadata first
+    metadata.version = tolel(CURRENT_METADATA_VERSION);
+    metadata.mode = tolel(mode);
+    metadata.undefined_1 = metadata.undefined_2 = 0;
+    err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
+    if (err != 0) {
+        free(buf);
+        return err;
+    }
+    bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
+
+    // now store the file content
     while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
         bytesLeft -= amt;
         if (bytesLeft < 0) {
@@ -211,6 +257,7 @@
         }
         err = dataStream->WriteEntityData(buf, amt);
         if (err != 0) {
+            free(buf);
             return err;
         }
     }
@@ -224,6 +271,7 @@
                 bytesLeft -= amt;
                 err = dataStream->WriteEntityData(buf, amt);
                 if (err != 0) {
+                    free(buf);
                     return err;
                 }
             }
@@ -233,7 +281,6 @@
     }
 
     free(buf);
-
     return NO_ERROR;
 }
 
@@ -241,11 +288,19 @@
 write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
 {
     int err;
+    struct stat st;
+
+    err = stat(realFilename, &st);
+    if (err < 0) {
+        return errno;
+    }
+
     int fd = open(realFilename, O_RDONLY);
     if (fd == -1) {
         return errno;
     }
-    err = write_update_file(dataStream, fd, key, realFilename);
+
+    err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
     close(fd);
     return err;
 }
@@ -266,7 +321,6 @@
     }
 
     free(buf);
-
     return crc;
 }
 
@@ -302,6 +356,7 @@
             r.s.modTime_sec = st.st_mtime;
             r.s.modTime_nsec = 0; // workaround sim breakage
             //r.s.modTime_nsec = st.st_mtime_nsec;
+            r.s.mode = st.st_mode;
             r.s.size = st.st_size;
             // we compute the crc32 later down below, when we already have the file open.
 
@@ -349,13 +404,13 @@
                 g.s.crc32 = compute_crc32(fd);
 
                 LOGP("%s", q.string());
-                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x",
-                        f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
-                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x",
-                        g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
+                LOGP("  new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
+                        f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
+                LOGP("  old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
+                        g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
                 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
-                        || f.size != g.s.size || f.crc32 != g.s.crc32) {
-                    write_update_file(dataStream, fd, p, g.file.string());
+                        || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
+                    write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
                 }
 
                 close(fd);
@@ -389,6 +444,7 @@
 RestoreHelperBase::RestoreHelperBase()
 {
     m_buf = malloc(RESTORE_BUF_SIZE);
+    m_loggedUnknownMetadata = false;
 }
 
 RestoreHelperBase::~RestoreHelperBase()
@@ -415,8 +471,25 @@
         return err;
     }
 
-    // TODO: World readable/writable for now.
-    mode = 0666;
+    // Get the metadata block off the head of the file entity and use that to
+    // set up the output file
+    file_metadata_v1 metadata;
+    amt = in->ReadEntityData(&metadata, sizeof(metadata));
+    if (amt != sizeof(metadata)) {
+        LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
+                (long)amt, strerror(errno));
+        return EIO;
+    }
+    metadata.version = fromlel(metadata.version);
+    metadata.mode = fromlel(metadata.mode);
+    if (metadata.version > CURRENT_METADATA_VERSION) {
+        if (!m_loggedUnknownMetadata) {
+            m_loggedUnknownMetadata = true;
+            LOGW("Restoring file with unsupported metadata version %d (currently %d)",
+                    metadata.version, CURRENT_METADATA_VERSION);
+        }
+    }
+    mode = metadata.mode;
 
     // Write the file and compute the crc
     crc = crc32(0L, Z_NULL, 0);
@@ -450,6 +523,7 @@
     r.s.modTime_sec = st.st_mtime;
     r.s.modTime_nsec = 0; // workaround sim breakage
     //r.s.modTime_nsec = st.st_mtime_nsec;
+    r.s.mode = st.st_mode;
     r.s.size = st.st_size;
     r.s.crc32 = crc;
 
@@ -536,6 +610,7 @@
         }
     }
 
+    free(contents);
     return contentsMatch && sizesMatch ? 0 : 1;
 }
 
@@ -623,6 +698,7 @@
 
     states[0].modTime_sec = 0xfedcba98;
     states[0].modTime_nsec = 0xdeadbeef;
+    states[0].mode = 0777; // decimal 511, hex 0x000001ff
     states[0].size = 0xababbcbc;
     states[0].crc32 = 0x12345678;
     states[0].nameLen = -12;
@@ -632,6 +708,7 @@
 
     states[1].modTime_sec = 0x93400031;
     states[1].modTime_nsec = 0xdeadbeef;
+    states[1].mode = 0666; // decimal 438, hex 0x000001b6
     states[1].size = 0x88557766;
     states[1].crc32 = 0x22334422;
     states[1].nameLen = -1;
@@ -641,6 +718,7 @@
 
     states[2].modTime_sec = 0x33221144;
     states[2].modTime_nsec = 0xdeadbeef;
+    states[2].mode = 0744; // decimal 484, hex 0x000001e4
     states[2].size = 0x11223344;
     states[2].crc32 = 0x01122334;
     states[2].nameLen = 0;
@@ -650,6 +728,7 @@
 
     states[3].modTime_sec = 0x33221144;
     states[3].modTime_nsec = 0xdeadbeef;
+    states[3].mode = 0755; // decimal 493, hex 0x000001ed
     states[3].size = 0x11223344;
     states[3].crc32 = 0x01122334;
     states[3].nameLen = 0;
@@ -669,35 +748,38 @@
     static const unsigned char correct_data[] = {
         // header
         0x53, 0x6e, 0x61, 0x70,  0x04, 0x00, 0x00, 0x00,
-        0x46, 0x69, 0x6c, 0x65,  0xac, 0x00, 0x00, 0x00,
+        0x46, 0x69, 0x6c, 0x65,  0xbc, 0x00, 0x00, 0x00,
 
         // bytes_of_padding
         0x98, 0xba, 0xdc, 0xfe,  0xef, 0xbe, 0xad, 0xde,
-        0xbc, 0xbc, 0xab, 0xab,  0x78, 0x56, 0x34, 0x12,
-        0x10, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,
+        0xff, 0x01, 0x00, 0x00,  0xbc, 0xbc, 0xab, 0xab,
+        0x78, 0x56, 0x34, 0x12,  0x10, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
 
         // bytes_of_padding3
         0x31, 0x00, 0x40, 0x93,  0xef, 0xbe, 0xad, 0xde,
-        0x66, 0x77, 0x55, 0x88,  0x22, 0x44, 0x33, 0x22,
-        0x11, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,  0x33, 0xab, 0xab, 0xab,
+        0xb6, 0x01, 0x00, 0x00,  0x66, 0x77, 0x55, 0x88,
+        0x22, 0x44, 0x33, 0x22,  0x11, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
+        0x33, 0xab, 0xab, 0xab,
 
         // bytes of padding2
         0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
-        0x44, 0x33, 0x22, 0x11,  0x34, 0x23, 0x12, 0x01,
-        0x12, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,  0x5f, 0x32, 0xab, 0xab,
+        0xe4, 0x01, 0x00, 0x00,  0x44, 0x33, 0x22, 0x11,
+        0x34, 0x23, 0x12, 0x01,  0x12, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
+        0x5f, 0x32, 0xab, 0xab,
 
         // bytes of padding3
         0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
-        0x44, 0x33, 0x22, 0x11,  0x34, 0x23, 0x12, 0x01,
-        0x13, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
-        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
-        0x64, 0x69, 0x6e, 0x67,  0x5f, 0x5f, 0x31, 0xab
+        0xed, 0x01, 0x00, 0x00,  0x44, 0x33, 0x22, 0x11,
+        0x34, 0x23, 0x12, 0x01,  0x13, 0x00, 0x00, 0x00,
+        0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
+        0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
+        0x5f, 0x5f, 0x31, 0xab
     };
 
     err = compare_file(filename, correct_data, sizeof(correct_data));
@@ -731,14 +813,14 @@
         const FileState state = readSnapshot.valueAt(i);
 
         if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
-                || states[i].modTime_nsec != state.modTime_nsec
+                || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
                 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
-            fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
-                            "          actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
-                    states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
-                    name.length(), filenames[i].string(),
-                    state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
-                    name.string());
+            fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
+                            "          actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
+                    states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
+                    states[i].crc32, name.length(), filenames[i].string(),
+                    state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
+                    state.nameLen, name.string());
             matched = false;
         }
     }
@@ -839,6 +921,7 @@
     size_t actualSize;
     bool done;
     int type;
+    ssize_t nRead;
 
     // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
 
@@ -873,8 +956,9 @@
         goto finished;
     }
 
-    err = reader.ReadEntityData(buf, bufSize);
-    if (err != NO_ERROR) {
+    nRead = reader.ReadEntityData(buf, bufSize);
+    if (nRead < 0) {
+        err = reader.Status();
         fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
         goto finished;
     }
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 69d47f0..e4f9f0f 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -544,7 +544,7 @@
     return mEventCode;
 }
 
-const int32_t ResXMLParser::getCommentID() const
+int32_t ResXMLParser::getCommentID() const
 {
     return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
 }
@@ -555,12 +555,12 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const uint32_t ResXMLParser::getLineNumber() const
+uint32_t ResXMLParser::getLineNumber() const
 {
     return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
 }
 
-const int32_t ResXMLParser::getTextID() const
+int32_t ResXMLParser::getTextID() const
 {
     if (mEventCode == TEXT) {
         return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
@@ -583,7 +583,7 @@
     return BAD_TYPE;
 }
 
-const int32_t ResXMLParser::getNamespacePrefixID() const
+int32_t ResXMLParser::getNamespacePrefixID() const
 {
     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
@@ -598,7 +598,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getNamespaceUriID() const
+int32_t ResXMLParser::getNamespaceUriID() const
 {
     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
@@ -613,7 +613,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getElementNamespaceID() const
+int32_t ResXMLParser::getElementNamespaceID() const
 {
     if (mEventCode == START_TAG) {
         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
@@ -630,7 +630,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getElementNameID() const
+int32_t ResXMLParser::getElementNameID() const
 {
     if (mEventCode == START_TAG) {
         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
@@ -655,7 +655,7 @@
     return 0;
 }
 
-const int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
+int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -678,7 +678,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const int32_t ResXMLParser::getAttributeNameID(size_t idx) const
+int32_t ResXMLParser::getAttributeNameID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
@@ -701,7 +701,7 @@
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
-const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
+uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
 {
     int32_t id = getAttributeNameID(idx);
     if (id >= 0 && (size_t)id < mTree.mNumResIds) {
@@ -710,7 +710,7 @@
     return 0;
 }
 
-const int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
+int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
 {
     if (mEventCode == START_TAG) {
         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 05fd46e..d767c31 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -997,7 +997,7 @@
         memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
         break;
     default:
-        ogles_error(c, GL_INVALID_ENUM);
+        texParameterx(target, pname, GLfixed(params[0]), c);
         return;
     }
 }
@@ -1016,6 +1016,13 @@
     texParameterx(target, pname, param, c);
 }
 
+void glTexParameteri(
+        GLenum target, GLenum pname, GLint param)
+{
+    ogles_context_t* c = ogles_context_t::get();
+    texParameterx(target, pname, GLfixed(param), c);
+}
+
 // ----------------------------------------------------------------------------
 #if 0
 #pragma mark -
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index 46958d3..e193483 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_SRC_FILES:= app-linux.c demo.c.arm
 LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
 LOCAL_MODULE:= angeles
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 include $(BUILD_EXECUTABLE)
 
 
@@ -13,5 +13,5 @@
 LOCAL_SRC_FILES:= gpustate.c
 LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM
 LOCAL_MODULE:= gpustate
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index a448f0d..31b7d9a 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -12,6 +12,6 @@
 
 LOCAL_MODULE:= test-opengl-filter
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 26836c1..8b46cd7 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -12,6 +12,6 @@
 
 LOCAL_MODULE:= test-opengl-finish
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index a8c6220..8d5f56d 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -12,6 +12,6 @@
 
 LOCAL_MODULE:= test-opengl-textures
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 5cd1f04..76fd8dd 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -12,6 +12,6 @@
 
 LOCAL_MODULE:= test-opengl-tritex
 
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)