Merge change Iaa321588 into eclair-mr2

* changes:
  Add "deleted" row to Events table.
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index e5a6ccb..e272a65 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -86,8 +86,8 @@
         x += k;
     }
 
-    buffer->meta_data()->setInt32(kKeyTimeUnits, mPhase);
-    buffer->meta_data()->setInt32(kKeyTimeScale, mSampleRate);
+    buffer->meta_data()->setInt64(
+            kKeyTime, ((int64_t)mPhase * 1000000) / mSampleRate);
 
     mPhase += numFramesPerBuffer;
 
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 5397a69..4d4d013 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -71,19 +71,22 @@
             options.clearSeekTo();
 
             bool shouldSeek = false;
-            if (err != OK) {
+            if (err == INFO_FORMAT_CHANGED) {
+                CHECK_EQ(buffer, NULL);
+
+                printf("format changed.\n");
+                continue;
+            } else if (err != OK) {
                 printf("reached EOF.\n");
 
                 shouldSeek = true;
             } else {
-                int32_t units, scale;
-                CHECK(buffer->meta_data()->findInt32(kKeyTimeUnits, &units));
-                CHECK(buffer->meta_data()->findInt32(kKeyTimeScale, &scale));
-                int64_t timestamp = ((OMX_TICKS)units * 1000000) / scale;
+                int64_t timestampUs;
+                CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
 
                 bool failed = false;
                 if (seekTimeUs >= 0) {
-                    int64_t diff = timestamp - seekTimeUs;
+                    int64_t diff = timestampUs - seekTimeUs;
 
                     if (diff > 500000) {
                         printf("ERROR: ");
@@ -92,7 +95,7 @@
                 }
 
                 printf("buffer has timestamp %lld us (%.2f secs)\n",
-                       timestamp, timestamp / 1E6);
+                       timestampUs, timestampUs / 1E6);
 
                 buffer->release();
                 buffer = NULL;
@@ -138,6 +141,12 @@
 
             if (err != OK) {
                 CHECK_EQ(buffer, NULL);
+
+                if (err == INFO_FORMAT_CHANGED) {
+                    printf("format changed.\n");
+                    continue;
+                }
+
                 break;
             }
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 3806fa8..0c1c7ec 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -229,7 +229,9 @@
     public final void setPreviewCallback(PreviewCallback cb) {
         mPreviewCallback = cb;
         mOneShot = false;
-        setHasPreviewCallback(cb != null, false);
+        // Always use one-shot mode. We fake camera preview mode by
+        // doing one-shot preview continuously.
+        setHasPreviewCallback(cb != null, true);
     }
 
     /**
@@ -280,10 +282,19 @@
 
             case CAMERA_MSG_PREVIEW_FRAME:
                 if (mPreviewCallback != null) {
-                    mPreviewCallback.onPreviewFrame((byte[])msg.obj, mCamera);
+                    PreviewCallback cb = mPreviewCallback;
                     if (mOneShot) {
+                        // Clear the callback variable before the callback
+                        // in case the app calls setPreviewCallback from
+                        // the callback function
                         mPreviewCallback = null;
+                    } else {
+                        // We're faking the camera preview mode to prevent
+                        // the app from being flooded with preview frames.
+                        // Set to oneshot mode again.
+                        setHasPreviewCallback(true, true);
                     }
+                    cb.onPreviewFrame((byte[])msg.obj, mCamera);
                 }
                 return;
 
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index d2861cb..d1db35e 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -496,15 +496,18 @@
      * @param uri A String representing the URI of the desired file.
      * @param buffer The byte array to copy the data into.
      * @param offset The offet into buffer to place the data.
+     * @param expectSize The size that the buffer has allocated for this file.
      * @return int The size of the given file, or zero if it fails.
      */
-    private int getFile(String uri, byte[] buffer, int offset) {
+    private int getFile(String uri, byte[] buffer, int offset,
+            int expectedSize) {
         int size = 0;
         try {
             InputStream stream = mContext.getContentResolver()
                             .openInputStream(Uri.parse(uri));
             size = stream.available();
-            if (buffer != null && buffer.length - offset >= size) {
+            if (size <= expectedSize && buffer != null
+                    && buffer.length - offset >= size) {
                 stream.read(buffer, offset, size);
             } else {
                 size = 0;
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 5145e03..17345bc 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -408,8 +408,7 @@
                 mStatusCode == HTTP_MOVED_PERMANENTLY ||
                 mStatusCode == HTTP_TEMPORARY_REDIRECT) && 
                 mNativeLoader != 0) {
-            if (!mFromCache && mRequestHandle != null
-                    && !mRequestHandle.getMethod().equals("POST")) {
+            if (!mFromCache && mRequestHandle != null) {
                 mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
                         headers, mMimeType, false);
             }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3fe6961..ad19b0f 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2215,6 +2215,11 @@
         return view;
     }
     
+    private void updateSurface(ViewManager.ChildView childView, int x, int y,
+            int width, int height) {
+        childView.attachView(x, y, width, height);
+    }
+
     private void destroySurface(ViewManager.ChildView childView) {
         childView.removeView();
     }
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index 0587c7c..02d95fd 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -19,10 +19,11 @@
 #define HTTP_DATASOURCE_H_
 
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/HTTPStream.h>
 
 namespace android {
 
+class HTTPStream;
+
 class HTTPDataSource : public DataSource {
 public:
     HTTPDataSource(const char *host, int port, const char *path);
@@ -40,7 +41,7 @@
         kBufferSize = 64 * 1024
     };
 
-    HTTPStream mHttp;
+    HTTPStream *mHttp;
     char *mHost;
     int mPort;
     char *mPath;
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 2bb0ed6..73d0f77 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -36,6 +36,9 @@
     ERROR_BUFFER_TOO_SMALL  = MEDIA_ERROR_BASE - 9,
     ERROR_UNSUPPORTED       = MEDIA_ERROR_BASE - 10,
     ERROR_END_OF_STREAM     = MEDIA_ERROR_BASE - 11,
+
+    // Not technically an error.
+    INFO_FORMAT_CHANGED    = MEDIA_ERROR_BASE - 12,
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index d1fa114..96d57e7 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -51,6 +51,9 @@
     // buffer is available, an error is encountered of the end of the stream
     // is reached.
     // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+    // A result of INFO_FORMAT_CHANGED indicates that the format of this
+    // MediaSource has changed mid-stream, the client can continue reading
+    // but should be prepared for buffers of the new configuration.
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index abb45a9..d48ea41 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -27,23 +27,23 @@
 
 namespace android {
 
+// The following keys map to int32_t data unless indicated otherwise.
 enum {
-    kKeyMIMEType          = 'mime',
+    kKeyMIMEType          = 'mime',  // cstring
     kKeyWidth             = 'widt',
     kKeyHeight            = 'heig',
     kKeyChannelCount      = '#chn',
     kKeySampleRate        = 'srte',
     kKeyBitRate           = 'brte',
-    kKeyESDS              = 'esds',
-    kKeyAVCC              = 'avcc',
-    kKeyTimeUnits         = '#tim',
-    kKeyTimeScale         = 'scal',
+    kKeyESDS              = 'esds',  // raw data
+    kKeyAVCC              = 'avcc',  // raw data
     kKeyWantsNALFragments = 'NALf',
     kKeyIsSyncFrame       = 'sync',
-    kKeyDuration          = 'dura',
+    kKeyTime              = 'time',  // int64_t (usecs)
+    kKeyDuration          = 'dura',  // int64_t (usecs)
     kKeyColorFormat       = 'colf',
-    kKeyPlatformPrivate   = 'priv',
-    kKeyDecoderComponent  = 'decC',
+    kKeyPlatformPrivate   = 'priv',  // pointer
+    kKeyDecoderComponent  = 'decC',  // cstring
     kKeyBufferID          = 'bfID',
     kKeyMaxInputSize      = 'inpS',
 };
@@ -62,6 +62,7 @@
         TYPE_NONE     = 'none',
         TYPE_C_STRING = 'cstr',
         TYPE_INT32    = 'in32',
+        TYPE_INT64    = 'in64',
         TYPE_FLOAT    = 'floa',
         TYPE_POINTER  = 'ptr ',
     };
@@ -71,11 +72,13 @@
 
     bool setCString(uint32_t key, const char *value);
     bool setInt32(uint32_t key, int32_t value);
+    bool setInt64(uint32_t key, int64_t value);
     bool setFloat(uint32_t key, float value);
     bool setPointer(uint32_t key, void *value);
 
     bool findCString(uint32_t key, const char **value);
     bool findInt32(uint32_t key, int32_t *value);
+    bool findInt64(uint32_t key, int64_t *value);
     bool findFloat(uint32_t key, float *value);
     bool findPointer(uint32_t key, void **value);
 
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index ff7e34a..ec043a9 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -124,6 +124,7 @@
     bool mInitialBufferSubmit;
     bool mSignalledEOS;
     bool mNoMoreOutputData;
+    bool mOutputPortSettingsHaveChanged;
     int64_t mSeekTimeUs;
 
     Mutex mLock;
diff --git a/media/java/android/media/ThumbnailUtil.java b/media/java/android/media/ThumbnailUtil.java
index 8acb744..7c6bca3 100644
--- a/media/java/android/media/ThumbnailUtil.java
+++ b/media/java/android/media/ThumbnailUtil.java
@@ -459,6 +459,7 @@
         Cursor c = cr.query(thumbUri, THUMB_PROJECTION,
               Thumbnails.IMAGE_ID + "=?",
               new String[]{String.valueOf(origId)}, null);
+        if (c == null) return null;
         try {
             if (c.moveToNext()) {
                 return ContentUris.withAppendedId(thumbUri, c.getLong(0));
@@ -487,6 +488,7 @@
         if (thumb == null) return false;
         try {
             Uri uri = getImageThumbnailUri(cr, origId, thumb.getWidth(), thumb.getHeight());
+            if (uri == null) return false;
             OutputStream thumbOut = cr.openOutputStream(uri);
             thumb.compress(Bitmap.CompressFormat.JPEG, 85, thumbOut);
             thumbOut.close();
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 64e9f2f..0e92162 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -130,7 +130,10 @@
     decoder->start();
 
     MediaBuffer *buffer;
-    status_t err = decoder->read(&buffer);
+    status_t err;
+    do {
+        err = decoder->read(&buffer);
+    } while (err == INFO_FORMAT_CHANGED);
 
     if (err != OK) {
         CHECK_EQ(buffer, NULL);
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 8d85ce2..1660351 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -201,10 +201,7 @@
     }
 
     buffer->set_range(0, frameSize);
-    buffer->meta_data()->setInt32(
-            kKeyTimeUnits, (mCurrentTimeUs + 500) / 1000);
-    buffer->meta_data()->setInt32(
-            kKeyTimeScale, 1000);
+    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
 
     mOffset += frameSize;
     mCurrentTimeUs += 20000;  // Each frame is 20ms
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 319488e..7b4d178 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -209,15 +209,9 @@
                 break;
             }
 
-            int32_t units, scale;
-            bool success =
-                mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
-            success = success &&
-                mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
-            CHECK(success);
-
             Mutex::Autolock autoLock(mLock);
-            mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+            CHECK(mInputBuffer->meta_data()->findInt64(
+                        kKeyTime, &mPositionTimeMediaUs));
 
             mPositionTimeRealUs =
                 ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 596ab67..40028a5 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -191,8 +191,7 @@
     *buffer = new CameraBuffer(frame);
 
     (*buffer)->meta_data()->clear();
-    (*buffer)->meta_data()->setInt32(kKeyTimeScale, 15);
-    (*buffer)->meta_data()->setInt32(kKeyTimeUnits, count);
+    (*buffer)->meta_data()->setInt64(kKeyTime, (count * 1000000) / 15);
 
     (*buffer)->add_ref();
     (*buffer)->setObserver(this);
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index 53b92a0..28d338c 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/ESDS.h>
+#include "include/ESDS.h"
 
 #include <string.h>
 
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 698223b..fa92024 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -14,17 +14,19 @@
  * limitations under the License.
  */
 
+#include "include/string.h"
+#include "include/HTTPStream.h"
+
 #include <stdlib.h>
 
 #include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/string.h>
 
 namespace android {
 
 HTTPDataSource::HTTPDataSource(const char *uri)
-    : mHost(NULL),
+    : mHttp(new HTTPStream),
+      mHost(NULL),
       mPort(0),
       mPath(NULL),
       mBuffer(malloc(kBufferSize)),
@@ -65,33 +67,38 @@
     mPort = port;
     mPath = strdup(path.c_str());
 
-    status_t err = mHttp.connect(mHost, mPort);
+    status_t err = mHttp->connect(mHost, mPort);
     CHECK_EQ(err, OK);
 }
 
 HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
-    : mHost(strdup(host)),
+    : mHttp(new HTTPStream),
+      mHost(strdup(host)),
       mPort(port),
       mPath(strdup(path)),
       mBuffer(malloc(kBufferSize)),
       mBufferLength(0),
       mBufferOffset(0) {
-    status_t err = mHttp.connect(mHost, mPort);
+    status_t err = mHttp->connect(mHost, mPort);
     CHECK_EQ(err, OK);
 }
 
 HTTPDataSource::~HTTPDataSource() {
-    mHttp.disconnect();
+    mHttp->disconnect();
 
     free(mBuffer);
     mBuffer = NULL;
 
     free(mPath);
     mPath = NULL;
+
+    delete mHttp;
+    mHttp = NULL;
 }
 
 ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
-    if (offset >= mBufferOffset && offset < mBufferOffset + mBufferLength) {
+    if (offset >= mBufferOffset
+            && offset < (off_t)(mBufferOffset + mBufferLength)) {
         size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
 
         size_t copy = num_bytes_available;
@@ -119,19 +126,19 @@
     status_t err;
     int attempt = 1;
     for (;;) {
-        if ((err = mHttp.send("GET ")) != OK
-            || (err = mHttp.send(mPath)) != OK
-            || (err = mHttp.send(" HTTP/1.1\r\n")) != OK
-            || (err = mHttp.send(host)) != OK
-            || (err = mHttp.send(range)) != OK
-            || (err = mHttp.send("\r\n")) != OK
-            || (err = mHttp.receive_header(&http_status)) != OK) {
+        if ((err = mHttp->send("GET ")) != OK
+            || (err = mHttp->send(mPath)) != OK
+            || (err = mHttp->send(" HTTP/1.1\r\n")) != OK
+            || (err = mHttp->send(host)) != OK
+            || (err = mHttp->send(range)) != OK
+            || (err = mHttp->send("\r\n")) != OK
+            || (err = mHttp->receive_header(&http_status)) != OK) {
 
             if (attempt == 3) {
                 return err;
             }
 
-            mHttp.connect(mHost, mPort);
+            mHttp->connect(mHost, mPort);
             ++attempt;
         } else {
             break;
@@ -143,14 +150,14 @@
     }
 
     string value;
-    if (!mHttp.find_header_value("Content-Length", &value)) {
+    if (!mHttp->find_header_value("Content-Length", &value)) {
         return UNKNOWN_ERROR;
     }
 
     char *end;
     unsigned long contentLength = strtoul(value.c_str(), &end, 10);
 
-    ssize_t num_bytes_received = mHttp.receive(mBuffer, contentLength);
+    ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
 
     if (num_bytes_received <= 0) {
         return num_bytes_received;
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 6af7df9..02f9439 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "include/HTTPStream.h"
+
 #include <sys/socket.h>
 
 #include <arpa/inet.h>
@@ -25,7 +27,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaDebug.h>
 
 namespace android {
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 7fd699f..b7dd9ba 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -147,7 +147,12 @@
             *out_bitrate = bitrate;
         }
 
-        *frame_size = 144000 * bitrate / sampling_rate + padding;
+        if (version == 3 /* V1 */) {
+            *frame_size = 144000 * bitrate / sampling_rate + padding;
+        } else {
+            // V2 or V2.5
+            *frame_size = 72000 * bitrate / sampling_rate + padding;
+        }
     }
 
     if (out_sampling_rate) {
@@ -166,6 +171,33 @@
 static bool Resync(
         const sp<DataSource> &source, uint32_t match_header,
         off_t *inout_pos, uint32_t *out_header) {
+    if (*inout_pos == 0) {
+        // Skip an optional ID3 header if syncing at the very beginning
+        // of the datasource.
+
+        uint8_t id3header[10];
+        if (source->read_at(0, id3header, sizeof(id3header))
+                < (ssize_t)sizeof(id3header)) {
+            // If we can't even read these 10 bytes, we might as well bail out,
+            // even if there _were_ 10 bytes of valid mp3 audio data...
+            return false;
+        }
+
+        if (id3header[0] == 'I' && id3header[1] == 'D' && id3header[2] == '3') {
+            // Skip the ID3v2 header.
+
+            size_t len =
+                ((id3header[6] & 0x7f) << 21)
+                | ((id3header[7] & 0x7f) << 14)
+                | ((id3header[8] & 0x7f) << 7)
+                | (id3header[9] & 0x7f);
+
+            len += 10;
+
+            *inout_pos += len;
+        }
+    }
+
     // Everything must match except for
     // protection, bitrate, padding, private bits and mode extension.
     const uint32_t kMask = 0xfffe0ccf;
@@ -338,10 +370,9 @@
 
         off_t fileSize;
         if (mDataSource->getSize(&fileSize) == OK) {
-            mMeta->setInt32(
+            mMeta->setInt64(
                     kKeyDuration,
-                    8 * (fileSize - mFirstFramePos) / bitrate);
-            mMeta->setInt32(kKeyTimeScale, 1000);
+                    8000 * (fileSize - mFirstFramePos) / bitrate);
         }
     }
 }
@@ -492,8 +523,7 @@
 
     buffer->set_range(0, frame_size);
 
-    buffer->meta_data()->setInt32(kKeyTimeUnits, mCurrentTimeUs / 1000);
-    buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
 
     mCurrentPos += frame_size;
     mCurrentTimeUs += 1152 * 1000000 / 44100;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 9174d19..da714f8 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "MPEG4Extractor"
 #include <utils/Log.h>
 
+#include "include/SampleTable.h"
+
 #include <arpa/inet.h>
 
 #include <ctype.h>
@@ -32,7 +34,6 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/SampleTable.h>
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
@@ -43,6 +44,7 @@
     // Caller retains ownership of both "dataSource" and "sampleTable".
     MPEG4Source(const sp<MetaData> &format,
                 const sp<DataSource> &dataSource,
+                int32_t timeScale,
                 const sp<SampleTable> &sampleTable);
 
     virtual status_t start(MetaData *params = NULL);
@@ -390,7 +392,6 @@
             }
 
             mLastTrack->timescale = ntohl(timescale);
-            mLastTrack->meta->setInt32(kKeyTimeScale, mLastTrack->timescale);
 
             int64_t duration;
             if (version == 1) {
@@ -409,7 +410,8 @@
                 }
                 duration = ntohl(duration32);
             }
-            mLastTrack->meta->setInt32(kKeyDuration, duration);
+            mLastTrack->meta->setInt64(
+                    kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
 
             *offset += chunk_size;
             break;
@@ -722,7 +724,7 @@
     }
 
     return new MPEG4Source(
-            track->meta, mDataSource, track->sampleTable);
+            track->meta, mDataSource, track->timescale, track->sampleTable);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -730,10 +732,11 @@
 MPEG4Source::MPEG4Source(
         const sp<MetaData> &format,
         const sp<DataSource> &dataSource,
+        int32_t timeScale,
         const sp<SampleTable> &sampleTable)
     : mFormat(format),
       mDataSource(dataSource),
-      mTimescale(0),
+      mTimescale(timeScale),
       mSampleTable(sampleTable),
       mCurrentSampleIndex(0),
       mIsAVC(false),
@@ -746,9 +749,6 @@
     bool success = mFormat->findCString(kKeyMIMEType, &mime);
     CHECK(success);
 
-    success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
-    CHECK(success);
-
     mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
 }
 
@@ -879,8 +879,8 @@
 
             mBuffer->set_range(0, size);
             mBuffer->meta_data()->clear();
-            mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
-            mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+            mBuffer->meta_data()->setInt64(
+                    kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
             ++mCurrentSampleIndex;
         }
 
@@ -959,8 +959,8 @@
 
         mBuffer->set_range(0, dstOffset);
         mBuffer->meta_data()->clear();
-        mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
-        mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+        mBuffer->meta_data()->setInt64(
+                kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
         ++mCurrentSampleIndex;
 
         *out = mBuffer;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index fa35768..9a7a873 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -399,15 +399,11 @@
         info.size = buffer->range_length();
         info.offset = offset;
 
-        int32_t units, scale;
-        bool success =
-            buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
-        CHECK(success);
-        success =
-            buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
-        CHECK(success);
+        int64_t timestampUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
 
-        info.timestamp = (int64_t)units * 1000 / scale;
+        // Our timestamp is in ms.
+        info.timestamp = (timestampUs + 500) / 1000;
 
         mSampleInfos.push_back(info);
 
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index f3c0e73..b973745b 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -108,10 +108,10 @@
 }
 
 void MediaBuffer::set_range(size_t offset, size_t length) {
-    if (offset < 0 || offset + length > mSize) {
+    if (offset + length > mSize) {
         LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
     }
-    CHECK(offset >= 0 && offset + length <= mSize);
+    CHECK(offset + length <= mSize);
 
     mRangeOffset = offset;
     mRangeLength = length;
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 2e609e3..3747a8d 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -18,6 +18,9 @@
 #define LOG_TAG "MediaPlayerImpl"
 #include "utils/Log.h"
 
+#include "include/string.h"
+#include "include/HTTPStream.h"
+
 #include <OMX_Component.h>
 
 #include <unistd.h>
@@ -26,7 +29,6 @@
 #include <media/stagefright/CachingDataSource.h>
 // #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaPlayerImpl.h>
@@ -250,6 +252,13 @@
         status_t err = mVideoDecoder->read(&buffer, &options);
         CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
 
+        if (err == INFO_FORMAT_CHANGED) {
+            LOGI("format changed.");
+            depopulateISurface();
+            populateISurface();
+            continue;
+        }
+
         if (err == ERROR_END_OF_STREAM || err != OK) {
             eof = true;
             continue;
@@ -261,15 +270,9 @@
             continue;
         }
 
-        int32_t units, scale;
-        bool success =
-            buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
-        CHECK(success);
-        success =
-            buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
-        CHECK(success);
+        int64_t pts_us;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &pts_us));
 
-        int64_t pts_us = (int64_t)units * 1000000 / scale;
         {
             Mutex::Autolock autoLock(mLock);
             mVideoPosition = pts_us;
@@ -379,12 +382,10 @@
 
             sp<MediaSource> source = mExtractor->getTrack(i);
 
-            int32_t units, scale;
-            if (meta->findInt32(kKeyDuration, &units)
-                && meta->findInt32(kKeyTimeScale, &scale)) {
-                int64_t duration_us = (int64_t)units * 1000000 / scale;
-                if (duration_us > mDuration) {
-                    mDuration = duration_us;
+            int64_t durationUs;
+            if (meta->findInt64(kKeyDuration, &durationUs)) {
+                if (durationUs > mDuration) {
+                    mDuration = durationUs;
                 }
             }
 
@@ -609,6 +610,9 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     CHECK(success);
 
+    LOGI("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d",
+         mVideoWidth, mVideoHeight, decodedWidth, decodedHeight);
+
     if (mSurface.get() != NULL) {
         mVideoRenderer =
             mClient.interface()->createRenderer(
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 6b067cb..63b476e 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -58,6 +58,10 @@
     return setData(key, TYPE_INT32, &value, sizeof(value));
 }
 
+bool MetaData::setInt64(uint32_t key, int64_t value) {
+    return setData(key, TYPE_INT64, &value, sizeof(value));
+}
+
 bool MetaData::setFloat(uint32_t key, float value) {
     return setData(key, TYPE_FLOAT, &value, sizeof(value));
 }
@@ -94,6 +98,21 @@
     return true;
 }
 
+bool MetaData::findInt64(uint32_t key, int64_t *value) {
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
+        return false;
+    }
+
+    CHECK_EQ(size, sizeof(*value));
+
+    *value = *(int64_t *)data;
+
+    return true;
+}
+
 bool MetaData::findFloat(uint32_t key, float *value) {
     uint32_t type;
     const void *data;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7586ada..5201c5a 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,11 +18,12 @@
 #define LOG_TAG "OMXCodec"
 #include <utils/Log.h>
 
+#include "include/ESDS.h"
+
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 #include <binder/ProcessState.h>
 #include <media/IMediaPlayerService.h>
-#include <media/stagefright/ESDS.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
@@ -677,6 +678,7 @@
       mInitialBufferSubmit(true),
       mSignalledEOS(false),
       mNoMoreOutputData(false),
+      mOutputPortSettingsHaveChanged(false),
       mSeekTimeUs(-1) {
     mPortStatus[kPortIndexInput] = ENABLED;
     mPortStatus[kPortIndexOutput] = ENABLED;
@@ -986,12 +988,8 @@
 
                 buffer->meta_data()->clear();
 
-                buffer->meta_data()->setInt32(
-                        kKeyTimeUnits,
-                        (msg.u.extended_buffer_data.timestamp + 500) / 1000);
-
-                buffer->meta_data()->setInt32(
-                        kKeyTimeScale, 1000);
+                buffer->meta_data()->setInt64(
+                        kKeyTime, msg.u.extended_buffer_data.timestamp);
 
                 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
                     buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
@@ -1082,6 +1080,9 @@
             if (mState == RECONFIGURING) {
                 CHECK_EQ(portIndex, kPortIndexOutput);
 
+                initOutputFormat(mSource->getFormat());
+                mOutputPortSettingsHaveChanged = true;
+
                 enablePortAsync(portIndex);
 
                 status_t err = allocateBuffersOnPort(portIndex);
@@ -1439,7 +1440,7 @@
     }
 
     OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
-    OMX_TICKS timestamp = 0;
+    OMX_TICKS timestampUs = 0;
     size_t srcLength = 0;
 
     if (err != OK) {
@@ -1459,15 +1460,11 @@
                (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
                srcLength);
 
-        int32_t units, scale;
-        if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
-            && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
-            timestamp = ((OMX_TICKS)units * 1000000) / scale;
-
+        if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
             CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
                  info->mBuffer, srcLength);
             CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
-                 timestamp, timestamp / 1E6);
+                 timestampUs, timestampUs / 1E6);
         }
     }
 
@@ -1478,7 +1475,7 @@
 
     err = mOMX->empty_buffer(
             mNode, info->mBuffer, 0, srcLength,
-            flags, timestamp);
+            flags, timestampUs);
 
     if (err != OK) {
         setState(ERROR);
@@ -1790,6 +1787,7 @@
     mInitialBufferSubmit = true;
     mSignalledEOS = false;
     mNoMoreOutputData = false;
+    mOutputPortSettingsHaveChanged = false;
     mSeekTimeUs = -1;
     mFilledBuffers.clear();
 
@@ -1860,6 +1858,8 @@
 }
 
 sp<MetaData> OMXCodec::getFormat() {
+    Mutex::Autolock autoLock(mLock);
+
     return mOutputFormat;
 }
 
@@ -1923,6 +1923,12 @@
         return ERROR_END_OF_STREAM;
     }
 
+    if (mOutputPortSettingsHaveChanged) {
+        mOutputPortSettingsHaveChanged = false;
+
+        return INFO_FORMAT_CHANGED;
+    }
+
     size_t index = *mFilledBuffers.begin();
     mFilledBuffers.erase(mFilledBuffers.begin());
 
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8efa7c7..5c5bb4d 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -17,11 +17,12 @@
 #define LOG_TAG "SampleTable"
 #include <utils/Log.h>
 
+#include "include/SampleTable.h"
+
 #include <arpa/inet.h>
 
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SampleTable.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
@@ -54,7 +55,7 @@
 }
 
 status_t SampleTable::setChunkOffsetParams(
-        uint32_t type, off_t data_offset, off_t data_size) {
+        uint32_t type, off_t data_offset, size_t data_size) {
     if (mChunkOffsetOffset >= 0) {
         return ERROR_MALFORMED;
     }
@@ -95,7 +96,7 @@
 }
 
 status_t SampleTable::setSampleToChunkParams(
-        off_t data_offset, off_t data_size) {
+        off_t data_offset, size_t data_size) {
     if (mSampleToChunkOffset >= 0) {
         return ERROR_MALFORMED;
     }
@@ -127,7 +128,7 @@
 }
 
 status_t SampleTable::setSampleSizeParams(
-        uint32_t type, off_t data_offset, off_t data_size) {
+        uint32_t type, off_t data_offset, size_t data_size) {
     if (mSampleSizeOffset >= 0) {
         return ERROR_MALFORMED;
     }
@@ -187,7 +188,7 @@
 }
 
 status_t SampleTable::setTimeToSampleParams(
-        off_t data_offset, off_t data_size) {
+        off_t data_offset, size_t data_size) {
     if (mTimeToSample != NULL || data_size < 8) {
         return ERROR_MALFORMED;
     }
@@ -219,7 +220,7 @@
     return OK;
 }
 
-status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
+status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) {
     if (mSyncSampleOffset >= 0 || data_size < 8) {
         return ERROR_MALFORMED;
     }
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
index 8e8f4fa..d420e6b 100644
--- a/media/libstagefright/ShoutcastSource.cpp
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
+#include "include/string.h"
+#include "include/HTTPStream.h"
+
 #include <stdlib.h>
 
-#include <media/stagefright/HTTPStream.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/ShoutcastSource.h>
-#include <media/stagefright/string.h>
 
 namespace android {
 
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 3d85f75..dd8005c 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -22,10 +22,11 @@
 #define LOG_TAG "TimedEventQueue"
 #include <utils/Log.h>
 
+#include "include/TimedEventQueue.h"
+
 #include <sys/time.h>
 
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/TimedEventQueue.h>
 
 namespace android {
 
diff --git a/include/media/stagefright/ESDS.h b/media/libstagefright/include/ESDS.h
similarity index 100%
rename from include/media/stagefright/ESDS.h
rename to media/libstagefright/include/ESDS.h
diff --git a/include/media/stagefright/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
similarity index 97%
rename from include/media/stagefright/HTTPStream.h
rename to media/libstagefright/include/HTTPStream.h
index 3d0d67a..e05d911 100644
--- a/include/media/stagefright/HTTPStream.h
+++ b/media/libstagefright/include/HTTPStream.h
@@ -18,10 +18,11 @@
 
 #define HTTP_STREAM_H_
 
+#include "string.h"
+
 #include <sys/types.h>
 
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/string.h>
 #include <utils/KeyedVector.h>
 
 namespace android {
diff --git a/include/media/stagefright/QComHardwareRenderer.h b/media/libstagefright/include/QComHardwareRenderer.h
similarity index 100%
rename from include/media/stagefright/QComHardwareRenderer.h
rename to media/libstagefright/include/QComHardwareRenderer.h
diff --git a/include/media/stagefright/SampleTable.h b/media/libstagefright/include/SampleTable.h
similarity index 88%
rename from include/media/stagefright/SampleTable.h
rename to media/libstagefright/include/SampleTable.h
index 808d142..34a0649 100644
--- a/include/media/stagefright/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -35,17 +35,17 @@
 
     // type can be 'stco' or 'co64'.
     status_t setChunkOffsetParams(
-            uint32_t type, off_t data_offset, off_t data_size);
+            uint32_t type, off_t data_offset, size_t data_size);
 
-    status_t setSampleToChunkParams(off_t data_offset, off_t data_size);
+    status_t setSampleToChunkParams(off_t data_offset, size_t data_size);
 
     // type can be 'stsz' or 'stz2'.
     status_t setSampleSizeParams(
-            uint32_t type, off_t data_offset, off_t data_size);
+            uint32_t type, off_t data_offset, size_t data_size);
 
-    status_t setTimeToSampleParams(off_t data_offset, off_t data_size);
+    status_t setTimeToSampleParams(off_t data_offset, size_t data_size);
 
-    status_t setSyncSampleParams(off_t data_offset, off_t data_size);
+    status_t setSyncSampleParams(off_t data_offset, size_t data_size);
 
     ////////////////////////////////////////////////////////////////////////////
 
diff --git a/include/media/stagefright/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
similarity index 100%
rename from include/media/stagefright/SoftwareRenderer.h
rename to media/libstagefright/include/SoftwareRenderer.h
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/media/libstagefright/include/TIHardwareRenderer.h
similarity index 100%
rename from include/media/stagefright/TIHardwareRenderer.h
rename to media/libstagefright/include/TIHardwareRenderer.h
diff --git a/include/media/stagefright/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
similarity index 100%
rename from include/media/stagefright/TimedEventQueue.h
rename to media/libstagefright/include/TimedEventQueue.h
diff --git a/include/media/stagefright/string.h b/media/libstagefright/include/string.h
similarity index 100%
rename from include/media/stagefright/string.h
rename to media/libstagefright/include/string.h
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index d7f355a..8d100d9 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -25,11 +25,12 @@
 
 #include "pv_omxcore.h"
 
+#include "../include/QComHardwareRenderer.h"
+#include "../include/SoftwareRenderer.h"
+#include "../include/TIHardwareRenderer.h"
+
 #include <binder/IMemory.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
-#include <media/stagefright/SoftwareRenderer.h>
-#include <media/stagefright/TIHardwareRenderer.h>
 #include <media/stagefright/VideoRenderer.h>
 
 #include <OMX_Component.h>
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
index 7dc368f..8e78c77 100644
--- a/media/libstagefright/omx/QComHardwareRenderer.cpp
+++ b/media/libstagefright/omx/QComHardwareRenderer.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#include "../include/QComHardwareRenderer.h"
+
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryHeapPmem.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
 #include <ui/ISurface.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 882c401..ef6ede0 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -17,9 +17,10 @@
 #define LOG_TAG "SoftwareRenderer"
 #include <utils/Log.h>
 
+#include "../include/SoftwareRenderer.h"
+
 #include <binder/MemoryHeapBase.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SoftwareRenderer.h>
 #include <ui/ISurface.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
index ebade4a..6dde86a 100644
--- a/media/libstagefright/omx/TIHardwareRenderer.cpp
+++ b/media/libstagefright/omx/TIHardwareRenderer.cpp
@@ -17,7 +17,8 @@
 #define LOG_TAG "TIHardwareRenderer"
 #include <utils/Log.h>
 
-#include <media/stagefright/TIHardwareRenderer.h>
+#include "../include/TIHardwareRenderer.h"
+
 #include <media/stagefright/MediaDebug.h>
 #include <ui/ISurface.h>
 #include <ui/Overlay.h>
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
index 5b16784..a4a1937 100644
--- a/media/libstagefright/string.cpp
+++ b/media/libstagefright/string.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/string.h>
+#include "include/string.h"
 
 namespace android {
 
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index e1bce73..2dc45b5 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -24,6 +24,7 @@
 
 public class InputDevice {
     static final boolean DEBUG_POINTERS = false;
+    static final boolean DEBUG_HACKS = false;
     
     /** Amount that trackball needs to move in order to generate a key event. */
     static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
@@ -76,6 +77,19 @@
         final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
                                         + MotionEvent.NUM_SAMPLE_DATA];
         
+        // Used to determine whether we dropped bad data, to avoid doing
+        // it repeatedly.
+        final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
+        
+        // Used to perform averaging of reported coordinates, to smooth
+        // the data and filter out transients during a release.
+        static final int HISTORY_SIZE = 5;
+        int[] mHistoryDataStart = new int[MAX_POINTERS];
+        int[] mHistoryDataEnd = new int[MAX_POINTERS];
+        final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
+                                        * HISTORY_SIZE];
+        final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
+        
         // Temporary data structures for doing the pointer ID mapping.
         final int[] mLast2Next = new int[MAX_POINTERS];
         final int[] mNext2Last = new int[MAX_POINTERS];
@@ -98,6 +112,183 @@
             }
         }
         
+        /**
+         * Special hack for devices that have bad screen data: if one of the
+         * points has moved more than a screen height from the last position,
+         * then drop it.
+         */
+        void dropBadPoint(InputDevice dev) {
+            // We should always have absY, but let's be paranoid.
+            if (dev.absY == null) {
+                return;
+            }
+            // Don't do anything if a finger is going down or up.  We run
+            // here before assigning pointer IDs, so there isn't a good
+            // way to do per-finger matching.
+            if (mNextNumPointers != mLastNumPointers) {
+                return;
+            }
+            
+            // We consider a single movement across more than a 7/16 of
+            // the long size of the screen to be bad.  This was a magic value
+            // determined by looking at the maximum distance it is feasible
+            // to actually move in one sample.
+            final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
+            
+            // Look through all new points and see if any are farther than
+            // acceptable from all previous points.
+            for (int i=mNextNumPointers-1; i>=0; i--) {
+                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+                //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
+                final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
+                if (DEBUG_HACKS) Log.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
+                boolean dropped = false;
+                if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
+                    dropped = true;
+                    int closestDy = -1;
+                    int closestY = -1;
+                    // We will drop this new point if it is sufficiently
+                    // far away from -all- last points.
+                    for (int j=mLastNumPointers-1; j>=0; j--) {
+                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+                        //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
+                        int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
+                        //if (dx < 0) dx = -dx;
+                        if (dy < 0) dy = -dy;
+                        if (DEBUG_HACKS) Log.v("InputDevice", "Comparing with last point #" + j
+                                + ": y=" + mLastData[joff] + " dy=" + dy);
+                        if (dy < maxDy) {
+                            dropped = false;
+                            break;
+                        } else if (closestDy < 0 || dy < closestDy) {
+                            closestDy = dy;
+                            closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
+                        }
+                    }
+                    if (dropped) {
+                        dropped = true;
+                        Log.i("InputDevice", "Dropping bad point #" + i
+                                + ": newY=" + y + " closestDy=" + closestDy
+                                + " maxDy=" + maxDy);
+                        mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
+                        break;
+                    }
+                }
+                mDroppedBadPoint[i] = dropped;
+            }
+        }
+        
+        /**
+         * Special hack for devices that have bad screen data: aggregate and
+         * compute averages of the coordinate data, to reduce the amount of
+         * jitter seen by applications.
+         */
+        int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
+                int nextNumPointers) {
+            final int numPointers = mLastNumPointers;
+            final int[] rawData = mLastData;
+            if (DEBUG_HACKS) Log.v("InputDevice", "lastNumPointers=" + lastNumPointers
+                    + " nextNumPointers=" + nextNumPointers
+                    + " numPointers=" + numPointers);
+            for (int i=0; i<numPointers; i++) {
+                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+                // We keep the average data in offsets based on the pointer
+                // ID, so we don't need to move it around as fingers are
+                // pressed and released.
+                final int p = mPointerIds[i];
+                final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
+                if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
+                    if (lastNumPointers < nextNumPointers) {
+                        // This pointer is going down.  Clear its history
+                        // and start fresh.
+                        if (DEBUG_HACKS) Log.v("InputDevice", "Pointer down @ index "
+                                + upOrDownPointer + " id " + mPointerIds[i]);
+                        mHistoryDataStart[i] = 0;
+                        mHistoryDataEnd[i] = 0;
+                        System.arraycopy(rawData, ioff, mHistoryData, poff,
+                                MotionEvent.NUM_SAMPLE_DATA);
+                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
+                                MotionEvent.NUM_SAMPLE_DATA);
+                        continue;
+                    } else {
+                        // The pointer is going up.  Just fall through to
+                        // recompute the last averaged point (and don't add
+                        // it as a new point to include in the average).
+                        if (DEBUG_HACKS) Log.v("InputDevice", "Pointer up @ index "
+                                + upOrDownPointer + " id " + mPointerIds[i]);
+                    }
+                } else {
+                    int end = mHistoryDataEnd[i];
+                    int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
+                    int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
+                    int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
+                    int newX = rawData[ioff + MotionEvent.SAMPLE_X];
+                    int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
+                    int dx = newX-oldX;
+                    int dy = newY-oldY;
+                    int delta = dx*dx + dy*dy;
+                    if (DEBUG_HACKS) Log.v("InputDevice", "Delta from last: " + delta);
+                    if (delta >= (75*75)) {
+                        // Magic number, if moving farther than this, turn
+                        // off filtering to avoid lag in response.
+                        mHistoryDataStart[i] = 0;
+                        mHistoryDataEnd[i] = 0;
+                        System.arraycopy(rawData, ioff, mHistoryData, poff,
+                                MotionEvent.NUM_SAMPLE_DATA);
+                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
+                                MotionEvent.NUM_SAMPLE_DATA);
+                        continue;
+                    } else {
+                        end++;
+                        if (end >= HISTORY_SIZE) {
+                            end -= HISTORY_SIZE;
+                        }
+                        mHistoryDataEnd[i] = end;
+                        int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
+                        mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
+                        mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
+                        mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
+                                = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
+                        int start = mHistoryDataStart[i];
+                        if (end == start) {
+                            start++;
+                            if (start >= HISTORY_SIZE) {
+                                start -= HISTORY_SIZE;
+                            }
+                            mHistoryDataStart[i] = start;
+                        }
+                    }
+                }
+                
+                // Now compute the average.
+                int start = mHistoryDataStart[i];
+                int end = mHistoryDataEnd[i];
+                int x=0, y=0;
+                int totalPressure = 0;
+                while (start != end) {
+                    int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
+                    int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
+                    x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
+                    y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
+                    totalPressure += pressure;
+                    start++;
+                    if (start >= HISTORY_SIZE) start = 0;
+                }
+                int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
+                int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
+                x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
+                y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
+                totalPressure += pressure;
+                x /= totalPressure;
+                y /= totalPressure;
+                if (DEBUG_HACKS) Log.v("InputDevice", "Averaging " + totalPressure
+                        + " weight: (" + x + "," + y + ")");
+                mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
+                mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
+            }
+            return mAveragedData;
+        }
+        
         private boolean assignPointer(int nextIndex, boolean allowOverlap) {
             final int lastNumPointers = mLastNumPointers;
             final int[] next2Last = mNext2Last;
@@ -333,7 +524,13 @@
             int upOrDownPointer = updatePointerIdentifiers();
             
             final float[] reportData = mReportData;
-            final int[] rawData = mLastData;
+            final int[] rawData;
+            if (KeyInputQueue.BAD_TOUCH_HACK) {
+                rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
+                        nextNumPointers);
+            } else {
+                rawData = mLastData;
+            }
             
             final int numPointers = mLastNumPointers;
             
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 35ed448..09591f4 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -52,6 +52,12 @@
     static final boolean DEBUG_VIRTUAL_KEYS = false;
     static final boolean DEBUG_POINTERS = false;
     
+    /**
+     * Turn on some hacks we have to improve the touch interaction with a
+     * certain device whose screen currently is not all that good.
+     */
+    static final boolean BAD_TOUCH_HACK = true;
+    
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
 
     final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
@@ -540,19 +546,17 @@
                                             keycode, 0, scancode,
                                             ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
                                              ? KeyEvent.FLAG_WOKE_HERE : 0));
+                            
                         } else if (ev.type == RawInputEvent.EV_KEY) {
+                            // Single touch protocol: touch going down or up.
                             if (ev.scancode == RawInputEvent.BTN_TOUCH &&
                                     (classes&(RawInputEvent.CLASS_TOUCHSCREEN
                                             |RawInputEvent.CLASS_TOUCHSCREEN_MT))
                                             == RawInputEvent.CLASS_TOUCHSCREEN) {
                                 di.mAbs.changed = true;
                                 di.mAbs.mDown[0] = ev.value != 0;
-                            } else if (ev.scancode == RawInputEvent.BTN_2 &&
-                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mDown[1] = ev.value != 0;
+                            
+                            // Trackball (mouse) protocol: press down or up.
                             } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
                                     (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
                                 di.mRel.changed = true;
@@ -560,6 +564,7 @@
                                 send = true;
                             }
     
+                        // Process position events from multitouch protocol.
                         } else if (ev.type == RawInputEvent.EV_ABS &&
                                 (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
                             if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
@@ -585,10 +590,10 @@
                                 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
                                     + MotionEvent.SAMPLE_SIZE] = ev.value;
                             }
-                            
+                        
+                        // Process position events from single touch protocol.
                         } else if (ev.type == RawInputEvent.EV_ABS &&
                                 (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                            // Finger 1
                             if (ev.scancode == RawInputEvent.ABS_X) {
                                 di.mAbs.changed = true;
                                 di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
@@ -605,18 +610,9 @@
                                 di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
                                 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
                                                  + MotionEvent.SAMPLE_SIZE] = ev.value;
-
-                            // Finger 2
-                            } else if (ev.scancode == RawInputEvent.ABS_HAT0X) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA 
-                                         + MotionEvent.SAMPLE_X] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                        + MotionEvent.SAMPLE_Y] = ev.value;
                             }
     
+                        // Process movement events from trackball (mouse) protocol.
                         } else if (ev.type == RawInputEvent.EV_REL &&
                                 (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
                             // Add this relative movement into our totals.
@@ -629,6 +625,9 @@
                             }
                         }
                         
+                        // Handle multitouch protocol sync: tells us that the
+                        // driver has returned all data for -one- of the pointers
+                        // that is currently down.
                         if (ev.type == RawInputEvent.EV_SYN
                                 && ev.scancode == RawInputEvent.SYN_MT_REPORT
                                 && di.mAbs != null) {
@@ -654,6 +653,9 @@
                                     if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
                                 }
                             }
+                        
+                        // Handle general event sync: all data for the current
+                        // event update has been delivered.
                         } else if (send || (ev.type == RawInputEvent.EV_SYN
                                 && ev.scancode == RawInputEvent.SYN_REPORT)) {
                             if (mDisplay != null) {
@@ -677,15 +679,10 @@
                                                     MotionEvent.NUM_SAMPLE_DATA);
                                             ms.mNextNumPointers++;
                                         }
-                                        if (ms.mDown[1]) {
-                                            System.arraycopy(di.curTouchVals,
-                                                    MotionEvent.NUM_SAMPLE_DATA,
-                                                    ms.mNextData,
-                                                    ms.mNextNumPointers
-                                                    * MotionEvent.NUM_SAMPLE_DATA,
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                            ms.mNextNumPointers++;
-                                        }
+                                    }
+                                    
+                                    if (BAD_TOUCH_HACK) {
+                                        ms.dropBadPoint(di);
                                     }
                                     
                                     boolean doMotion = !monitorVirtualKey(di,
@@ -719,6 +716,16 @@
                                                         RawInputEvent.CLASS_TOUCHSCREEN, me);
                                             }
                                         } while (ms.hasMore());
+                                    } else {
+                                        // We are consuming movement in the
+                                        // virtual key area...  but still
+                                        // propagate this to the previous
+                                        // data for comparisons.
+                                        System.arraycopy(ms.mNextData, 0,
+                                                ms.mLastData, 0,
+                                                ms.mNextNumPointers
+                                                        * MotionEvent.NUM_SAMPLE_DATA);
+                                        ms.mLastNumPointers = ms.mNextNumPointers;
                                     }
                                     
                                     ms.finish();
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index a3589c7..89d969d 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -542,7 +542,7 @@
 
         value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
         if (!TextUtils.isEmpty(value)) {
-            config.SSID = value;
+            config.SSID = removeDoubleQuotes(value);
         } else {
             config.SSID = null;
         }
@@ -675,11 +675,21 @@
             value = WifiNative.getNetworkVariableCommand(netId,
                     field.varName());
             if (!TextUtils.isEmpty(value)) {
+                if (field != config.eap) value = removeDoubleQuotes(value);
                 field.setValue(value);
             }
         }
     }
 
+    private static String removeDoubleQuotes(String string) {
+        if (string.length() <= 2) return "";
+        return string.substring(1, string.length() - 1);
+    }
+
+    private static String convertToQuotedString(String string) {
+        return "\"" + string + "\"";
+    }
+
     /**
      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
      * @return the supplicant-assigned identifier for the new or updated
@@ -731,7 +741,7 @@
                 !WifiNative.setNetworkVariableCommand(
                     netId,
                     WifiConfiguration.ssidVarName,
-                    config.SSID)) {
+                    convertToQuotedString(config.SSID))) {
                 if (DBG) {
                     Log.d(TAG, "failed to set SSID: "+config.SSID);
                 }
@@ -894,18 +904,22 @@
                     : config.enterpriseFields) {
                 String varName = field.varName();
                 String value = field.value();
-                if ((value != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    varName,
-                    value)) {
-                    if (DBG) {
-                        Log.d(TAG, config.SSID + ": failed to set " + varName +
-                              ": " + value);
+                if (value != null) {
+                    if (field != config.eap) {
+                        value = convertToQuotedString(value);
                     }
-                    break setVariables;
+                    if (!WifiNative.setNetworkVariableCommand(
+                            netId,
+                            varName,
+                            value)) {
+                        if (DBG) {
+                            Log.d(TAG, config.SSID + ": failed to set " + varName +
+                                  ": " + value);
+                        }
+                        break setVariables;
+                    }
                 }
             }
-
             return netId;
         }
 
@@ -1702,8 +1716,10 @@
     }
 
     private boolean acquireWifiLockLocked(WifiLock wifiLock) {
+        Log.d(TAG, "acquireWifiLockLocked: " + wifiLock);
+
         mLocks.addLock(wifiLock);
-        
+
         int uid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
         try {
@@ -1721,7 +1737,7 @@
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-        
+
         updateWifiState();
         return true;
     }
@@ -1735,8 +1751,11 @@
 
     private boolean releaseWifiLockLocked(IBinder lock) {
         boolean hadLock;
-        
+
         WifiLock wifiLock = mLocks.removeLock(lock);
+
+        Log.d(TAG, "releaseWifiLockLocked: " + wifiLock);
+
         hadLock = (wifiLock != null);
 
         if (hadLock) {
@@ -1758,7 +1777,7 @@
                 Binder.restoreCallingIdentity(ident);
             }
         }
-        
+        // TODO - should this only happen if you hadLock?
         updateWifiState();
         return hadLock;
     }