Merge commit 'remotes/korg/cupcake' into merge

Conflicts:
	core/java/android/view/animation/TranslateAnimation.java
	core/jni/Android.mk
	core/res/res/values-en-rGB/strings.xml
	libs/audioflinger/AudioFlinger.cpp
	libs/surfaceflinger/LayerScreenshot.cpp
	packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index c8c8431..2974e32 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -48,7 +48,6 @@
         int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
-    Mutex::Autolock lock(mLock);
     status_t err = 0;
 
     // only one output stream allowed
@@ -72,7 +71,8 @@
 }
 
 AudioStreamIn* A2dpAudioInterface::openInputStream(
-        int format, int channelCount, uint32_t sampleRate, status_t *status)
+        int format, int channelCount, uint32_t sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustics)
 {
     if (status)
         *status = -1;
@@ -99,6 +99,10 @@
     if (strcmp(key, "a2dp_sink_address") == 0) {        
         return mOutput->setAddress(value);
     }
+    if (strcmp(key, "bluetooth_enabled") == 0 &&
+        strcmp(value, "false") == 0) {
+        return mOutput->close();
+    }
 
     return 0;
 }
@@ -126,11 +130,11 @@
 // ----------------------------------------------------------------------------
 
 A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
-    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
-    mInitialized(false)
+    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL)
 {
     // use any address by default
-    strncpy(mA2dpAddress, "00:00:00:00:00:00", sizeof(mA2dpAddress));
+    strcpy(mA2dpAddress, "00:00:00:00:00:00");
+    init();
 }
 
 status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
@@ -154,23 +158,17 @@
 
 A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
 {
-    if (mData)
-        a2dp_cleanup(mData);
+    close();
 }
 
 ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
 {    
-    status_t status = NO_INIT;
-    size_t remaining = bytes;
+    Mutex::Autolock lock(mLock);
 
-    if (!mInitialized) {
-        status = a2dp_init(mA2dpAddress, 44100, 2, &mData);
-        if (status < 0) {
-            LOGE("a2dp_init failed err: %d\n", status);
-            goto Error;
-        }
-        mInitialized = true;
-    }
+    size_t remaining = bytes;
+    status_t status = init();
+    if (status < 0)
+        goto Error;
     
     while (remaining > 0) {
         status = a2dp_write(mData, buffer, remaining);
@@ -186,17 +184,34 @@
     
     return bytes;
 
-Error:   
+Error:
     // Simulate audio output timing in case of error
     usleep(bytes * 1000000 / frameSize() / sampleRate());
 
     return status;
 }
 
+status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
+{
+    if (!mData) {
+        status_t status = a2dp_init(44100, 2, &mData);
+        if (status < 0) {
+            LOGE("a2dp_init failed err: %d\n", status);
+            mData = NULL;
+            return status;
+        }
+        a2dp_set_sink(mData, mA2dpAddress);
+    }
+
+    return 0;
+}
+
 status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
 {
     int result = 0;
 
+    Mutex::Autolock lock(mLock);
+
     if (!mStandby) {
         result = a2dp_stop(mData);
         if (result == 0)
@@ -208,19 +223,24 @@
 
 status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
 {
-    if (strlen(address) < sizeof(mA2dpAddress))
+    Mutex::Autolock lock(mLock);
+
+    if (strlen(address) != strlen("00:00:00:00:00:00"))
         return -EINVAL;
 
-    if (strcmp(address, mA2dpAddress)) {
-        strcpy(mA2dpAddress, address);
-        
-        if (mInitialized) {
-            a2dp_cleanup(mData);
-            mData = NULL;
-            mInitialized = false;
-        }
+    strcpy(mA2dpAddress, address);
+    if (mData)
+        a2dp_set_sink(mData, mA2dpAddress);
+
+    return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+    if (mData) {
+        a2dp_cleanup(mData);
+        mData = NULL;
     }
-    
     return NO_ERROR;
 }
 
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 2197d0e..99614dc 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -58,7 +58,8 @@
                                 int format,
                                 int channelCount,
                                 uint32_t sampleRate,
-                                status_t *status);
+                                status_t *status,
+                                AudioSystem::audio_in_acoustics acoustics);
 
 protected:
     virtual status_t    doRouting();
@@ -77,7 +78,7 @@
         virtual size_t      bufferSize() const { return 512 * 20; }
         virtual int         channelCount() const { return 2; }
         virtual int         format() const { return AudioSystem::PCM_16_BIT; }
-        virtual uint32_t    latency() const { return ((1000*channelCount()*bufferSize())/frameSize())/sampleRate() + 200; }
+        virtual uint32_t    latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
         virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
         virtual ssize_t     write(const void* buffer, size_t bytes);
                 status_t    standby();
@@ -85,6 +86,8 @@
 
     private:
         friend class A2dpAudioInterface;
+                status_t    init();
+                status_t    close();
         status_t            setAddress(const char* address);
 
     private:
@@ -94,10 +97,9 @@
                 int         mRetryCount;
                 char        mA2dpAddress[20];
                 void*       mData;
-                bool        mInitialized;
+                Mutex       mLock;
     };
 
-    Mutex                   mLock;
     A2dpAudioStreamOut*     mOutput;
 };
 
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 42204d6..9a94102 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -78,8 +78,9 @@
     virtual status_t    setParameter(const char* key, const char* value)
                             {return mFinalInterface->setParameter(key, value);}
 
-    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status)
-                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);}
+    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status,
+                                            AudioSystem::audio_in_acoustics acoustics)
+                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status, acoustics);}
 
     virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
 
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 918b01f..3c81a47 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -47,6 +47,15 @@
 #include "A2dpAudioInterface.h"
 #endif
 
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
 namespace android {
 
 //static const nsecs_t kStandbyTimeInNsecs = seconds(3);
@@ -59,6 +68,16 @@
 static const int8_t kMaxTrackRetries = 50;
 static const int8_t kMaxTrackStartupRetries = 50;
 
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
 #define AUDIOFLINGER_SECURITY_ENABLED 1
 
 // ----------------------------------------------------------------------------
@@ -98,13 +117,10 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AudioFlinger()
-    : BnAudioFlinger(), Thread(false),
-        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
-        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0),
-        mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0),
-        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
-        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
-        mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false)
+    : BnAudioFlinger(),
+        mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
+        mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
+        mRouteRestoreTime(0), mMusicMuteSaved(false)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
     mAudioHardware = AudioHardwareInterface::create();
@@ -113,57 +129,51 @@
         // open 16-bit output stream for s/w mixer
         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
         status_t status;
-        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
         mHardwareStatus = AUDIO_HW_IDLE;
-        if (mHardwareOutput) {
-            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate());
-            mRequestedOutput = mHardwareOutput;
-            doSetOutput(mHardwareOutput);
-
-            // FIXME - this should come from settings
-            setMasterVolume(1.0f);
-            setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
-            setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
-            setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
-            setMode(AudioSystem::MODE_NORMAL);
-            mMasterMute = false;
+        if (hwOutput) {
+            mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
         } else {
-            LOGE("Failed to initialize output stream, status: %d", status);
+            LOGE("Failed to initialize hardware output stream, status: %d", status);
         }
         
 #ifdef WITH_A2DP
         // Create A2DP interface
         mA2dpAudioInterface = new A2dpAudioInterface();
-        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);       
-        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
-
-        // create a buffer big enough for both hardware and A2DP audio output.
-        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
-        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
-        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
-#else
-        size_t frameCount = getOutputFrameCount(mHardwareOutput);
+        AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        if (a2dpOutput) {
+            mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+            if (hwOutput) {  
+                uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+                MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+                                                            hwOutput->sampleRate(),
+                                                            AudioSystem::PCM_16_BIT,
+                                                            hwOutput->channelCount(),
+                                                            frameCount);
+                mHardwareMixerThread->setOuputTrack(a2dpOutTrack);                
+            }
+        } else {
+            LOGE("Failed to initialize A2DP output stream, status: %d", status);
+        }
 #endif
-        // FIXME - Current mixer implementation only supports stereo output: Always
-        // Allocate a stereo buffer even if HW output is mono.
-        mMixBuffer = new int16_t[frameCount * 2];
-        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
-        
+ 
+        // FIXME - this should come from settings
+        setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+        setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+        setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+        setMode(AudioSystem::MODE_NORMAL);
+
+        setMasterVolume(1.0f);
+        setMasterMute(false);
+
         // Start record thread
-        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
         if (mAudioRecordThread != 0) {
             mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
         }
      } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
-
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.audio.silent", value, "0");
-    if (atoi(value)) {
-        LOGD("Silence is golden");
-        mMasterMute = true;
-    }
 }
 
 AudioFlinger::~AudioFlinger()
@@ -172,60 +182,73 @@
         mAudioRecordThread->exit();
         mAudioRecordThread.clear();        
     }
+    mHardwareMixerThread.clear();
     delete mAudioHardware;
     // deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+    mA2dpMixerThread.clear();
     delete mA2dpAudioInterface;
-    delete [] mMixBuffer;
-    delete mHardwareAudioMixer;
-    delete mA2dpAudioMixer;
-}
- 
-void AudioFlinger::setOutput(AudioStreamOut* output)
-{
-    mRequestedOutput = output;
+#endif
 }
 
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
-{
-    mSampleRate = output->sampleRate();
-    mChannelCount = output->channelCount();
-
-    // FIXME - Current mixer implementation only supports stereo output
-    if (mChannelCount == 1) {
-        LOGE("Invalid audio hardware channel count");
-    }
-    mFormat = output->format();
-    mFrameCount = getOutputFrameCount(output);
-    mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
-    mOutput = output;
-}
-
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
-{
-    return output->bufferSize() / output->channelCount() / sizeof(int16_t);
-}
 
 #ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
+// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::setA2dpEnabled_l(bool enable)
 {
-    return (streamType == AudioTrack::SYSTEM ||
-            streamType == AudioTrack::RING ||
-            streamType == AudioTrack::ALARM ||
-            streamType == AudioTrack::NOTIFICATION);
+    SortedVector < sp<MixerThread::Track> > tracks;
+    SortedVector < wp<MixerThread::Track> > activeTracks;
+    
+    LOGV_IF(enable, "set output to A2DP\n");
+    LOGV_IF(!enable, "set output to hardware audio\n");
+
+    // Transfer tracks playing on MUSIC stream from one mixer to the other
+    if (enable) {
+        mHardwareMixerThread->getTracks_l(tracks, activeTracks);
+        mA2dpMixerThread->putTracks_l(tracks, activeTracks);
+    } else {
+        mA2dpMixerThread->getTracks_l(tracks, activeTracks);
+        mHardwareMixerThread->putTracks_l(tracks, activeTracks);
+    }
+    mA2dpEnabled = enable;
+    mNotifyA2dpChange = true;
+    mWaitWorkCV.broadcast();
 }
 
-void AudioFlinger::setA2dpEnabled(bool enable)
+// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::checkA2dpEnabledChange_l()
 {
-    if (enable) {
-        LOGD("set output to A2DP\n");
-        setOutput(mA2dpOutput);
-    } else {
-        LOGD("set output to hardware audio\n");
-        setOutput(mHardwareOutput);
+    if (mNotifyA2dpChange) {
+        // Notify AudioSystem of the A2DP activation/deactivation
+        size_t size = mNotificationClients.size();
+        for (size_t i = 0; i < size; i++) {
+            sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
+            if (binder != NULL) {
+                LOGV("Notifying output change to client %p", binder.get());
+                sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+                client->a2dpEnabledChanged(mA2dpEnabled);
+            }
+        }
+        mNotifyA2dpChange = false;
     }
 }
 #endif // WITH_A2DP
 
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+    // NOTE that streams listed here must not be routed to A2DP by default:
+    // AudioSystem::routedToA2dpOutput(streamType) == false
+    return (streamType == AudioSystem::RING ||
+            streamType == AudioSystem::ALARM ||
+            streamType == AudioSystem::NOTIFICATION);
+}
+
+bool AudioFlinger::streamDisablesA2dp(int streamType)
+{
+    return (streamType == AudioSystem::VOICE_CALL ||
+            streamType == AudioSystem::BLUETOOTH_SCO);
+}
+
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -247,60 +270,18 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    result.append("Tracks:\n");
-    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        wp<Track> wTrack = mTracks[i];
-        if (wTrack != 0) {
-            sp<Track> track = wTrack.promote();
-            if (track != 0) {
-                track->dump(buffer, SIZE);
-                result.append(buffer);
-            }
-        }
-    }
-
-    result.append("Active Tracks:\n");
-    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
-    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
-        wp<Track> wTrack = mTracks[i];
-        if (wTrack != 0) {
-            sp<Track> track = wTrack.promote();
-            if (track != 0) {
-                track->dump(buffer, SIZE);
-                result.append(buffer);
-            }
-        }
-    }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
 
 status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-
-    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
-    result.append(buffer);
-    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
+    int hardwareStatus = mHardwareStatus;
+    
+    if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
+        hardwareStatus = AUDIO_HW_STANDBY;
+    }
+    snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
     result.append(buffer);
     write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -325,225 +306,36 @@
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         dumpPermissionDenial(fd, args);
     } else {
-        AutoMutex lock(&mLock);
+        bool locked = false;
+        for (int i = 0; i < kDumpLockRetries; ++i) {
+            if (mLock.tryLock() == NO_ERROR) {
+                locked = true;
+                break;
+            }
+            usleep(kDumpLockSleep);
+        }
 
         dumpClients(fd, args);
-        dumpTracks(fd, args);
         dumpInternals(fd, args);
+        mHardwareMixerThread->dump(fd, args);
+#ifdef WITH_A2DP
+        mA2dpMixerThread->dump(fd, args);
+#endif
+
+        // dump record client
+        if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+
         if (mAudioHardware) {
             mAudioHardware->dumpState(fd, args);
         }
+        if (locked) mLock.unlock();
     }
     return NO_ERROR;
 }
 
-// Thread virtuals
-bool AudioFlinger::threadLoop()
-{
-    unsigned long sleepTime = kBufferRecoveryInUsecs;
-    int16_t* curBuf = mMixBuffer;
-    Vector< sp<Track> > tracksToRemove;
-    size_t enabledTracks = 0;
-    nsecs_t standbyTime = systemTime();
-
-    do {
-        enabledTracks = 0;
-        { // scope for the mLock
-        
-            Mutex::Autolock _l(mLock);
-            const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-
-            // put audio hardware into standby after short delay
-            if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
-                // wait until we have something to do...
-                LOGV("Audio hardware entering standby\n");
-                mHardwareStatus = AUDIO_HW_STANDBY;
-                if (!mStandby) {
-                    mOutput->standby();
-                    mStandby = true;
-                }
-                mHardwareStatus = AUDIO_HW_IDLE;
-                // we're about to wait, flush the binder command buffer
-                IPCThreadState::self()->flushCommands();
-                mWaitWorkCV.wait(mLock);
-                LOGV("Audio hardware exiting standby\n");
-                standbyTime = systemTime() + kStandbyTimeInNsecs;
-                continue;
-            }
-
-            // check for change in output
-            if (mRequestedOutput != mOutput) {
-
-                // put current output into standby mode
-                if (mOutput) mOutput->standby();
-
-                // change output
-                doSetOutput(mRequestedOutput);
-            }
-
-            // find out which tracks need to be processed
-            size_t count = activeTracks.size();
-            for (size_t i=0 ; i<count ; i++) {
-                sp<Track> t = activeTracks[i].promote();
-                if (t == 0) continue;
-
-                Track* const track = t.get();
-                audio_track_cblk_t* cblk = track->cblk();
-
-                // The first time a track is added we wait
-                // for all its buffers to be filled before processing it
-                mAudioMixer->setActiveTrack(track->name());
-                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
-                        !track->isPaused())
-                {
-                    //LOGD("u=%08x, s=%08x [OK]", u, s);
-
-                    // compute volume for this track
-                    int16_t left, right;
-                    if (track->isMuted() || mMasterMute || track->isPausing()) {
-                        left = right = 0;
-                        if (track->isPausing()) {
-                            LOGV("paused(%d)", track->name());
-                            track->setPaused();
-                        }
-                    } else {
-                        float typeVolume = mStreamTypes[track->type()].volume;
-                        float v = mMasterVolume * typeVolume;
-                        float v_clamped = v * cblk->volume[0];
-                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                        left = int16_t(v_clamped);
-                        v_clamped = v * cblk->volume[1];
-                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-                        right = int16_t(v_clamped);
-                    }
-
-                    // XXX: these things DON'T need to be done each time
-                    mAudioMixer->setBufferProvider(track);
-                    mAudioMixer->enable(AudioMixer::MIXING);
-
-                    int param;
-                    if ( track->mFillingUpStatus == Track::FS_FILLED) {
-                        // no ramp for the first volume setting
-                        track->mFillingUpStatus = Track::FS_ACTIVE;
-                        if (track->mState == TrackBase::RESUMING) {
-                            track->mState = TrackBase::ACTIVE;
-                            param = AudioMixer::RAMP_VOLUME;
-                        } else {
-                            param = AudioMixer::VOLUME;
-                        }
-                    } else {
-                        param = AudioMixer::RAMP_VOLUME;
-                    }
-                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
-                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
-                    mAudioMixer->setParameter(
-                        AudioMixer::TRACK,
-                        AudioMixer::FORMAT, track->format());
-                    mAudioMixer->setParameter(
-                        AudioMixer::TRACK,
-                        AudioMixer::CHANNEL_COUNT, track->channelCount());
-                    mAudioMixer->setParameter(
-                        AudioMixer::RESAMPLE,
-                        AudioMixer::SAMPLE_RATE,
-                        int(cblk->sampleRate));
-
-                    // reset retry count
-                    track->mRetryCount = kMaxTrackRetries;
-                    enabledTracks++;
-                } else {
-                    //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
-                    if (track->isStopped()) {
-                        track->reset();
-                    }
-                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
-                        // We have consumed all the buffers of this track.
-                        // Remove it from the list of active tracks.
-                        LOGV("remove(%d) from active list", track->name());
-                        tracksToRemove.add(track);
-                    } else {
-                        // No buffers for this track. Give it a few chances to
-                        // fill a buffer, then remove it from active list.
-                        if (--(track->mRetryCount) <= 0) {
-                            LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
-                            tracksToRemove.add(track);
-                        }
-                    }
-                    // LOGV("disable(%d)", track->name());
-                    mAudioMixer->disable(AudioMixer::MIXING);
-                }
-            }
-
-            // remove all the tracks that need to be...
-            count = tracksToRemove.size();
-            if (UNLIKELY(count)) {
-                for (size_t i=0 ; i<count ; i++) {
-                    const sp<Track>& track = tracksToRemove[i];
-                    removeActiveTrack(track);
-                    if (track->isTerminated()) {
-                        mTracks.remove(track);
-                        mAudioMixer->deleteTrackName(track->mName);
-                    }
-                }
-            }  
-       }
-        if (LIKELY(enabledTracks)) {
-            // mix buffers...
-            mAudioMixer->process(curBuf);
-
-            // output audio to hardware
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
-            mOutput->write(curBuf, mixBufferSize);
-            mNumWrites++;
-            mInWrite = false;
-            mStandby = false;
-            nsecs_t temp = systemTime();
-            standbyTime = temp + kStandbyTimeInNsecs;
-            nsecs_t delta = temp - mLastWriteTime;
-            nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-            if (delta > maxPeriod) {
-                LOGW("write blocked for %llu msecs", ns2ms(delta));
-                mNumDelayedWrites++;
-            }
-            sleepTime = kBufferRecoveryInUsecs;
-        } else {
-            // There was nothing to mix this round, which means all
-            // active tracks were late. Sleep a little bit to give
-            // them another chance. If we're too late, the audio
-            // hardware will zero-fill for us.
-            LOGV("no buffers - usleep(%lu)", sleepTime);
-            usleep(sleepTime);
-            if (sleepTime < kMaxBufferRecoveryInUsecs) {
-                sleepTime += kBufferRecoveryInUsecs;
-            }
-        }
-
-        // finally let go of all our tracks, without the lock held
-        // since we can't guarantee the destructors won't acquire that
-        // same lock.
-        tracksToRemove.clear();
-    } while (true);
-
-    return false;
-}
-
-status_t AudioFlinger::readyToRun()
-{
-    if (mSampleRate == 0) {
-        LOGE("No working audio driver found.");
-        return NO_INIT;
-    }
-    LOGI("AudioFlinger's main thread ready to run.");
-    return NO_ERROR;
-}
-
-void AudioFlinger::onFirstRef()
-{
-    run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
-}
-
 // IAudioFlinger interface
+
+
 sp<IAudioTrack> AudioFlinger::createTrack(
         pid_t pid,
         int streamType,
@@ -555,34 +347,21 @@
         const sp<IMemory>& sharedBuffer,
         status_t *status)
 {
-    sp<Track> track;
+    sp<MixerThread::Track> track;
     sp<TrackHandle> trackHandle;
     sp<Client> client;
     wp<Client> wclient;
     status_t lStatus;
 
-    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+    if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
-    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
-        LOGE("Sample rate out of range: %d", sampleRate);
-        lStatus = BAD_VALUE;
-        goto Exit;
-    }
-
     {
         Mutex::Autolock _l(mLock);
 
-        if (mSampleRate == 0) {
-            LOGE("Audio driver not initialized.");
-            lStatus = NO_INIT;
-            goto Exit;
-        }
-
         wclient = mClients.valueFor(pid);
 
         if (wclient != NULL) {
@@ -591,13 +370,21 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
-
-        track = new Track(this, client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer);
-        mTracks.add(track);
+#ifdef WITH_A2DP
+        if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
+            track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        } else 
+#endif
+        {
+            track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        }
+    }
+    if (lStatus == NO_ERROR) {
         trackHandle = new TrackHandle(track);
-
-        lStatus = NO_ERROR;
+    } else {
+        track.clear();
     }
 
 Exit:
@@ -607,34 +394,54 @@
     return trackHandle;
 }
 
-uint32_t AudioFlinger::sampleRate() const
+uint32_t AudioFlinger::sampleRate(int output) const
 {
-    return mSampleRate;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->sampleRate();
+     }
+#endif
+     return mHardwareMixerThread->sampleRate();
 }
 
-int AudioFlinger::channelCount() const
+int AudioFlinger::channelCount(int output) const
 {
-    return mChannelCount;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->channelCount();
+     }
+#endif
+     return mHardwareMixerThread->channelCount();
 }
 
-int AudioFlinger::format() const
+int AudioFlinger::format(int output) const
 {
-    return mFormat;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->format();
+     }
+#endif
+     return mHardwareMixerThread->format();
 }
 
-size_t AudioFlinger::frameCount() const
+size_t AudioFlinger::frameCount(int output) const
 {
-    return mFrameCount;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->frameCount();
+     }
+#endif
+     return mHardwareMixerThread->frameCount();
 }
 
-uint32_t AudioFlinger::latency() const
+uint32_t AudioFlinger::latency(int output) const
 {
-    if (mOutput) {
-        return mOutput->latency();
-    }
-    else {
-        return 0;
-    }
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->latency();
+     }
+#endif
+     return mHardwareMixerThread->latency();
 }
 
 status_t AudioFlinger::setMasterVolume(float value)
@@ -648,12 +455,14 @@
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
     if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
-        mMasterVolume = 1.0f;
-    }
-    else {
-        mMasterVolume = value;
+        value = 1.0f;
     }
     mHardwareStatus = AUDIO_HW_IDLE;
+    mHardwareMixerThread->setMasterVolume(value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterVolume(value);
+#endif
+
     return NO_ERROR;
 }
 
@@ -671,20 +480,21 @@
     }
 
 #ifdef WITH_A2DP
-    LOGD("setRouting %d %d %d\n", mode, routes, mask);
+    LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
     if (mode == AudioSystem::MODE_NORMAL && 
             (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
         AutoMutex lock(&mLock);
 
         bool enableA2dp = false;
         if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
-            if (mA2dpDisableCount > 0)
-                mA2dpSuppressed = true;
-            else
-                enableA2dp = true;
+            enableA2dp = true;
         }
-        setA2dpEnabled(enableA2dp);
-        LOGD("setOutput done\n");
+        if (mA2dpDisableCount > 0) {
+            mA2dpSuppressed = enableA2dp;
+        } else {
+            setA2dpEnabled_l(enableA2dp);
+        }
+        LOGV("setOutput done\n");
     }
 #endif
 
@@ -697,6 +507,12 @@
         err = mAudioHardware->getRouting(mode, &r);
         if (err == NO_ERROR) {
             r = (r & ~mask) | (routes & mask);
+            if (mode == AudioSystem::MODE_NORMAL || 
+                (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+                mSavedRoute = r;
+                r |= mForcedRoute;
+                LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
+            }
             mHardwareStatus = AUDIO_HW_SET_ROUTING;
             err = mAudioHardware->setRouting(mode, r);
         }
@@ -709,9 +525,14 @@
 {
     uint32_t routes = 0;
     if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
-        mHardwareStatus = AUDIO_HW_GET_ROUTING;
-        mAudioHardware->getRouting(mode, &routes);
-        mHardwareStatus = AUDIO_HW_IDLE;
+        if (mode == AudioSystem::MODE_NORMAL || 
+            (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+            routes = mSavedRoute;                
+        } else {
+            mHardwareStatus = AUDIO_HW_GET_ROUTING;
+            mAudioHardware->getRouting(mode, &routes);
+            mHardwareStatus = AUDIO_HW_IDLE;
+        }
     } else {
         LOGW("Illegal value: getRouting(%d)", mode);
     }
@@ -774,19 +595,21 @@
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
-
-    mMasterMute = muted;
+    mHardwareMixerThread->setMasterMute(muted);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterMute(muted);
+#endif
     return NO_ERROR;
 }
 
 float AudioFlinger::masterVolume() const
 {
-    return mMasterVolume;
+    return mHardwareMixerThread->masterVolume();
 }
 
 bool AudioFlinger::masterMute() const
 {
-    return mMasterMute;
+    return mHardwareMixerThread->masterMute();
 }
 
 status_t AudioFlinger::setStreamVolume(int stream, float value)
@@ -796,26 +619,40 @@
         return PERMISSION_DENIED;
     }
 
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
 
     status_t ret = NO_ERROR;
-    if (stream == AudioTrack::VOICE_CALL) {
+    
+    if (stream == AudioSystem::VOICE_CALL ||
+        stream == AudioSystem::BLUETOOTH_SCO) {
+        float hwValue = value;
+        if (stream == AudioSystem::VOICE_CALL) {
+            hwValue = (float)AudioSystem::logToLinear(value)/100.0f;
+            // FIXME: This is a temporary fix to re-base the internally
+            // generated in-call audio so that it is never muted, which is
+            // already the case for the hardware routed in-call audio.
+            // When audio stream handling is reworked, this should be
+            // addressed more cleanly.  Fixes #1324; see discussion at
+            // http://review.source.android.com/8224
+            value = value * 0.99 + 0.01;        
+        } else { // (type == AudioSystem::BLUETOOTH_SCO)
+            hwValue = 1.0f;
+        }
+
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
-        ret = mAudioHardware->setVoiceVolume(value);
+        ret = mAudioHardware->setVoiceVolume(hwValue);
         mHardwareStatus = AUDIO_HW_IDLE;
-        // FIXME: This is a temporary fix to re-base the internally
-        // generated in-call audio so that it is never muted, which is
-        // already the case for the hardware routed in-call audio.
-        // When audio stream handling is reworked, this should be
-        // addressed more cleanly.  Fixes #1324; see discussion at
-        // http://review.source.android.com/8224
-        mStreamTypes[stream].volume = value * (1.0 - 1.0 / 6.0) + (1.0 / 6.0);
-    } else {
-        mStreamTypes[stream].volume = value;
+        
     }
+    
+    mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
+
     return ret;
 }
 
@@ -826,45 +663,66 @@
         return PERMISSION_DENIED;
     }
 
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
-    mStreamTypes[stream].mute = muted;
+    
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamMute(stream, muted);
+#endif
+    if (stream == AudioSystem::MUSIC) 
+    {
+        AutoMutex lock(&mHardwareLock);
+        if (mForcedRoute != 0)
+            mMusicMuteSaved = muted;
+        else
+            mHardwareMixerThread->setStreamMute(stream, muted);
+    } else {
+        mHardwareMixerThread->setStreamMute(stream, muted);
+    }
+
+    
+
     return NO_ERROR;
 }
 
 float AudioFlinger::streamVolume(int stream) const
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return 0.0f;
     }
-    if (stream == AudioTrack::VOICE_CALL) {
+    float value = mHardwareMixerThread->streamVolume(stream);
+    
+    if (stream == AudioSystem::VOICE_CALL) {
         // FIXME: Re-base internally generated in-call audio,
         // reverse of above in setStreamVolume.
-        return (mStreamTypes[stream].volume - (1.0 / 6.0)) / (1.0 - 1.0 / 6.0);
+        value = (value - 0.01) / 0.99;
     }
-    return mStreamTypes[stream].volume;
+    
+    return value;
 }
 
 bool AudioFlinger::streamMute(int stream) const
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return true;
     }
-    return mStreamTypes[stream].mute;
+    
+    if (stream == AudioSystem::MUSIC && mForcedRoute != 0) 
+    {
+        return mMusicMuteSaved;
+    }
+    return mHardwareMixerThread->streamMute(stream);
 }
 
 bool AudioFlinger::isMusicActive() const
 {
-    size_t count = mActiveTracks.size();
-    for (size_t i = 0 ; i < count ; ++i) {
-        sp<Track> t = mActiveTracks[i].promote();
-        if (t == 0) continue;
-        Track* const track = t.get();
-        if (t->mStreamType == AudioTrack::MUSIC)
-            return true;
-    }
-    return false;
+ #ifdef WITH_A2DP
+     if (isA2dpEnabled()) {
+         return mA2dpMixerThread->isMusicActive();
+     }
+ #endif
+    return mHardwareMixerThread->isMusicActive();
 }
 
 status_t AudioFlinger::setParameter(const char* key, const char* value)
@@ -872,6 +730,8 @@
     status_t result, result2;
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_SET_PARAMETER;
+    
+    LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
     result = mAudioHardware->setParameter(key, value);
     if (mA2dpAudioInterface) {
         result2 = mA2dpAudioInterface->setParameter(key, value);
@@ -882,15 +742,716 @@
     return result;
 }
 
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+{
+    
+    LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+
+    sp<IBinder> binder = client->asBinder();
+    if (mNotificationClients.indexOf(binder) < 0) {
+        LOGV("Adding notification client %p", binder.get());
+        binder->linkToDeath(this);
+        mNotificationClients.add(binder);
+        client->a2dpEnabledChanged(isA2dpEnabled());
+    }
+}
+
+void AudioFlinger::binderDied(const wp<IBinder>& who) {
+    
+    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+
+    IBinder *binder = who.unsafe_get();
+
+    if (binder != NULL) {
+        int index = mNotificationClients.indexOf(binder);
+        if (index >= 0) {
+            LOGV("Removing notification client %p", binder);
+            mNotificationClients.removeAt(index);
+        }
+    }
+}
+
 void AudioFlinger::removeClient(pid_t pid)
 {
+    LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mLock);
     mClients.removeItem(pid);
 }
 
-status_t AudioFlinger::addTrack(const sp<Track>& track)
+bool AudioFlinger::isA2dpEnabled() const
 {
-    Mutex::Autolock _l(mLock);
+    return mA2dpEnabled;
+}
+
+void AudioFlinger::handleForcedSpeakerRoute(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount++ == 0) {
+                mRouteRestoreTime = 0;
+                mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+                if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(0);
+                    usleep(mHardwareMixerThread->latency()*1000);
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    // delay track start so that audio hardware has time to siwtch routes
+                    usleep(kStartSleepTime);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                }
+                mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+            }
+            LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount > 0){
+                if (--mForcedSpeakerCount == 0) {
+                    mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
+                }
+                LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
+            } else {
+                LOGE("mForcedSpeakerCount is already zero");
+            }
+        }
+        break;
+    case CHECK_ROUTE_RESTORE_TIME:
+    case FORCE_ROUTE_RESTORE:
+        if (mRouteRestoreTime) {
+            AutoMutex lock(mHardwareLock);
+            if (mRouteRestoreTime && 
+               (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
+                mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
+                mForcedRoute = 0;
+                if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
+                }
+                mRouteRestoreTime = 0;
+            }
+        }
+        break;
+    }
+}
+
+#ifdef WITH_A2DP
+// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::handleStreamDisablesA2dp_l(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            if (mA2dpDisableCount++ == 0) {
+                if (mA2dpEnabled) {
+                    setA2dpEnabled_l(false);
+                    mA2dpSuppressed = true;
+                }
+            }
+            LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            if (mA2dpDisableCount > 0) {
+                if (--mA2dpDisableCount == 0) {
+                    if (mA2dpSuppressed) {
+                        setA2dpEnabled_l(true);
+                        mA2dpSuppressed = false;
+                    }
+                }
+                LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
+            } else {
+                LOGE("mA2dpDisableCount is already zero");
+            }
+        }
+        break;
+    }
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
+    :   Thread(false),
+        mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType), 
+        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
+        mInWrite(false)
+{
+    mSampleRate = output->sampleRate();
+    mChannelCount = output->channelCount();
+
+    // FIXME - Current mixer implementation only supports stereo output
+    if (mChannelCount == 1) {
+        LOGE("Invalid audio hardware channel count");
+    }
+
+    mFormat = output->format();
+    mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
+    mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
+
+    // FIXME - Current mixer implementation only supports stereo output: Always
+    // Allocate a stereo buffer even if HW output is mono.
+    mMixBuffer = new int16_t[mFrameCount * 2];
+    memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+    delete [] mMixBuffer;
+    delete mAudioMixer;
+}
+
+status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+    result.append(buffer);
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+
+    snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+    result.append(buffer);
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+    result.append(buffer);
+    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// Thread virtuals
+bool AudioFlinger::MixerThread::threadLoop()
+{
+    unsigned long sleepTime = kBufferRecoveryInUsecs;
+    int16_t* curBuf = mMixBuffer;
+    Vector< sp<Track> > tracksToRemove;
+    size_t enabledTracks = 0;
+    nsecs_t standbyTime = systemTime();   
+    size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+
+#ifdef WITH_A2DP
+    bool outputTrackActive = false;
+#endif
+
+    do {
+        enabledTracks = 0;
+        { // scope for the AudioFlinger::mLock
+        
+            Mutex::Autolock _l(mAudioFlinger->mLock);
+
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mAudioFlinger->mLock.unlock();
+                    mOutputTrack->stop();
+                    mAudioFlinger->mLock.lock();
+                    outputTrackActive = false;
+                }
+            }
+            mAudioFlinger->checkA2dpEnabledChange_l();
+#endif
+
+            const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+            // put audio hardware into standby after short delay
+            if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+                // wait until we have something to do...
+                LOGV("Audio hardware entering standby, output %d\n", mOutputType);
+                if (!mStandby) {
+                    mOutput->standby();
+                    mStandby = true;
+                }
+                
+#ifdef WITH_A2DP
+                if (outputTrackActive) {
+                    mAudioFlinger->mLock.unlock();
+                    mOutputTrack->stop();
+                    mAudioFlinger->mLock.lock();
+                    outputTrackActive = false;
+                }
+#endif
+                if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                    mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
+                }                
+                // we're about to wait, flush the binder command buffer
+                IPCThreadState::self()->flushCommands();
+                mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
+                LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
+                
+                if (mMasterMute == false) {
+                    char value[PROPERTY_VALUE_MAX];
+                    property_get("ro.audio.silent", value, "0");
+                    if (atoi(value)) {
+                        LOGD("Silence is golden");
+                        setMasterMute(true);
+                    }                    
+                }
+                
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
+                continue;
+            }
+
+            // Forced route to speaker is handled by hardware mixer thread
+            if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
+            }
+
+            // find out which tracks need to be processed
+            size_t count = activeTracks.size();
+            for (size_t i=0 ; i<count ; i++) {
+                sp<Track> t = activeTracks[i].promote();
+                if (t == 0) continue;
+
+                Track* const track = t.get();
+                audio_track_cblk_t* cblk = track->cblk();
+
+                // The first time a track is added we wait
+                // for all its buffers to be filled before processing it
+                mAudioMixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+                        !track->isPaused())
+                {
+                    //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+                    // compute volume for this track
+                    int16_t left, right;
+                    if (track->isMuted() || mMasterMute || track->isPausing()) {
+                        left = right = 0;
+                        if (track->isPausing()) {
+                            LOGV("paused(%d)", track->name());
+                            track->setPaused();
+                        }
+                    } else {
+                        float typeVolume = mStreamTypes[track->type()].volume;
+                        float v = mMasterVolume * typeVolume;
+                        float v_clamped = v * cblk->volume[0];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        left = int16_t(v_clamped);
+                        v_clamped = v * cblk->volume[1];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        right = int16_t(v_clamped);
+                    }
+
+                    // XXX: these things DON'T need to be done each time
+                    mAudioMixer->setBufferProvider(track);
+                    mAudioMixer->enable(AudioMixer::MIXING);
+
+                    int param;
+                    if ( track->mFillingUpStatus == Track::FS_FILLED) {
+                        // no ramp for the first volume setting
+                        track->mFillingUpStatus = Track::FS_ACTIVE;
+                        if (track->mState == TrackBase::RESUMING) {
+                            track->mState = TrackBase::ACTIVE;
+                            param = AudioMixer::RAMP_VOLUME;
+                        } else {
+                            param = AudioMixer::VOLUME;
+                        }
+                    } else {
+                        param = AudioMixer::RAMP_VOLUME;
+                    }
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::FORMAT, track->format());
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::CHANNEL_COUNT, track->channelCount());
+                    mAudioMixer->setParameter(
+                        AudioMixer::RESAMPLE,
+                        AudioMixer::SAMPLE_RATE,
+                        int(cblk->sampleRate));
+
+                    // reset retry count
+                    track->mRetryCount = kMaxTrackRetries;
+                    enabledTracks++;
+                } else {
+                    //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+                    if (track->isStopped()) {
+                        track->reset();
+                    }
+                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+                        // We have consumed all the buffers of this track.
+                        // Remove it from the list of active tracks.
+                        LOGV("remove(%d) from active list", track->name());
+                        tracksToRemove.add(track);
+                    } else {
+                        // No buffers for this track. Give it a few chances to
+                        // fill a buffer, then remove it from active list.
+                        if (--(track->mRetryCount) <= 0) {
+                            LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                            tracksToRemove.add(track);
+                        }
+                    }
+                    // LOGV("disable(%d)", track->name());
+                    mAudioMixer->disable(AudioMixer::MIXING);
+                }
+            }
+
+            // remove all the tracks that need to be...
+            count = tracksToRemove.size();
+            if (UNLIKELY(count)) {
+                for (size_t i=0 ; i<count ; i++) {
+                    const sp<Track>& track = tracksToRemove[i];
+                    removeActiveTrack_l(track);
+                    if (track->isTerminated()) {
+                        mTracks.remove(track);
+                        deleteTrackName_l(track->mName);
+                    }
+                }
+            }
+       }
+        
+        if (LIKELY(enabledTracks)) {
+            // mix buffers...
+            mAudioMixer->process(curBuf);
+
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (!outputTrackActive) {
+                    LOGV("starting output track in mixer for output %d", mOutputType);
+                    mOutputTrack->start();
+                    outputTrackActive = true;
+                }
+                mOutputTrack->write(curBuf, mFrameCount);
+            }
+#endif
+
+            // output audio to hardware
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            mOutput->write(curBuf, mixBufferSize);
+            mNumWrites++;
+            mInWrite = false;
+            mStandby = false;
+            nsecs_t temp = systemTime();
+            standbyTime = temp + kStandbyTimeInNsecs;
+            nsecs_t delta = temp - mLastWriteTime;
+            if (delta > maxPeriod) {
+                LOGW("write blocked for %llu msecs", ns2ms(delta));
+                mNumDelayedWrites++;
+            }
+            sleepTime = kBufferRecoveryInUsecs;
+        } else {         
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mOutputTrack->write(curBuf, 0);
+                    if (mOutputTrack->bufferQueueEmpty()) {
+                        mOutputTrack->stop();
+                        outputTrackActive = false;
+                    } else {
+                        standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    }
+                }
+            }
+#endif
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, the audio
+            // hardware will zero-fill for us.
+            //LOGV("no buffers - usleep(%lu)", sleepTime);
+            usleep(sleepTime);
+            if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                sleepTime += kBufferRecoveryInUsecs;
+            }
+        }
+
+        // finally let go of all our tracks, without the lock held
+        // since we can't guarantee the destructors won't acquire that
+        // same lock.
+        tracksToRemove.clear();
+    } while (true);
+
+    return false;
+}
+
+status_t AudioFlinger::MixerThread::readyToRun()
+{
+    if (mSampleRate == 0) {
+        LOGE("No working audio driver found.");
+        return NO_INIT;
+    }
+    LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
+    return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onFirstRef()
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+
+    run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::MixerThread::Track>  AudioFlinger::MixerThread::createTrack_l(
+        const sp<AudioFlinger::Client>& client,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
+{
+    sp<Track> track;
+    status_t lStatus;
+    
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+
+    if (mSampleRate == 0) {
+        LOGE("Audio driver not initialized.");
+        lStatus = NO_INIT;
+        goto Exit;
+    }
+
+    track = new Track(this, client, streamType, sampleRate, format,
+            channelCount, frameCount, sharedBuffer);
+    if (track->getCblk() == NULL) {
+        lStatus = NO_MEMORY;
+        goto Exit;
+    }
+    mTracks.add(track);
+    lStatus = NO_ERROR;
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return track;
+}
+
+// getTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::getTracks_l(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+    size_t size = mTracks.size();
+    LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType,  mTracks.size(), mActiveTracks.size());
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = mTracks[i];
+        if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+            tracks.add(t);
+            int j = mActiveTracks.indexOf(t);
+            if (j >= 0) {
+                t = mActiveTracks[j].promote();
+                if (t != NULL) {
+                    activeTracks.add(t);                                    
+                }                            
+            }
+        }
+    }
+
+    size = activeTracks.size();
+    for (size_t i = 0; i < size; i++) {
+        removeActiveTrack_l(activeTracks[i]);
+    }
+    
+    size = tracks.size();
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = tracks[i];
+        mTracks.remove(t);
+        deleteTrackName_l(t->name());
+    }
+}
+
+// putTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::putTracks_l(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+
+    LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType,  tracks.size(), activeTracks.size());
+
+    size_t size = tracks.size();
+    for (size_t i = 0; i < size ; i++) {
+        sp<Track> t = tracks[i];
+        int name = getTrackName_l();
+
+        if (name < 0) return;
+        
+        t->mName = name;
+        t->mMixerThread = this;
+        mTracks.add(t);
+
+        int j = activeTracks.indexOf(t);
+        if (j >= 0) {
+            addActiveTrack_l(t);
+        }            
+    }
+}
+
+uint32_t AudioFlinger::MixerThread::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioFlinger::MixerThread::channelCount() const
+{
+    return mChannelCount;
+}
+
+int AudioFlinger::MixerThread::format() const
+{
+    return mFormat;
+}
+
+size_t AudioFlinger::MixerThread::frameCount() const
+{
+    return mFrameCount;
+}
+
+uint32_t AudioFlinger::MixerThread::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
+status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+{
+    mMasterVolume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+{
+    mMasterMute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::masterVolume() const
+{
+    return mMasterVolume;
+}
+
+bool AudioFlinger::MixerThread::masterMute() const
+{
+    return mMasterMute;
+}
+
+status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+{
+    mStreamTypes[stream].volume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+{
+    mStreamTypes[stream].mute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::streamVolume(int stream) const
+{
+    return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::MixerThread::streamMute(int stream) const
+{
+    return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::MixerThread::isMusicActive() const
+{
+    size_t count = mActiveTracks.size();
+    for (size_t i = 0 ; i < count ; ++i) {
+        sp<Track> t = mActiveTracks[i].promote();
+        if (t == 0) continue;
+        Track* const track = t.get();
+        if (t->mStreamType == AudioSystem::MUSIC)
+            return true;
+    }
+    return false;
+}
+
+// addTrack_l() must be called with AudioFlinger::mLock held
+status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+{
+    status_t status = ALREADY_EXISTS;
 
     // here the track could be either new, or restarted
     // in both cases "unstop" the track
@@ -903,139 +1464,135 @@
     }
     // set retry count for buffer fill
     track->mRetryCount = kMaxTrackStartupRetries;
-    LOGV("mWaitWorkCV.broadcast");
-    mWaitWorkCV.broadcast();
-
     if (mActiveTracks.indexOf(track) < 0) {
         // the track is newly added, make sure it fills up all its
         // buffers before playing. This is to ensure the client will
         // effectively get the latency it requested.
         track->mFillingUpStatus = Track::FS_FILLING;
         track->mResetDone = false;
-        addActiveTrack(track);
-        return NO_ERROR;
+        addActiveTrack_l(track);
+        status = NO_ERROR;
     }
-    return ALREADY_EXISTS;
+    
+    LOGV("mWaitWorkCV.broadcast");
+    mAudioFlinger->mWaitWorkCV.broadcast();
+
+    return status;
 }
 
-void AudioFlinger::removeTrack(wp<Track> track, int name)
+// removeTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeTrack_l(wp<Track> track, int name)
 {
-    Mutex::Autolock _l(mLock);
     sp<Track> t = track.promote();
     if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
-        remove_track_l(track, name);
-    }
-}
-
-void AudioFlinger::remove_track_l(wp<Track> track, int name)
-{
-    sp<Track> t = track.promote();
-    if (t!=NULL) {
         t->reset();
+        deleteTrackName_l(name);
+        removeActiveTrack_l(track);
+        mAudioFlinger->mWaitWorkCV.broadcast();
     }
-    audioMixer()->deleteTrackName(name);
-    removeActiveTrack(track);
-    mWaitWorkCV.broadcast();
 }
 
-void AudioFlinger::destroyTrack(const sp<Track>& track)
+// destroyTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
 {
-    // NOTE: We're acquiring a strong reference on the track before
-    // acquiring the lock, this is to make sure removing it from
-    // mTracks won't cause the destructor to be called while the lock is
-    // held (note that technically, 'track' could be a reference to an item
-    // in mTracks, which is why we need to do this).
-    sp<Track> keep(track);
-    Mutex::Autolock _l(mLock);
     track->mState = TrackBase::TERMINATED;
     if (mActiveTracks.indexOf(track) < 0) {
         LOGV("remove track (%d) and delete from mixer", track->name());
         mTracks.remove(track);
-        audioMixer()->deleteTrackName(keep->name());
+        deleteTrackName_l(track->name());
     }
 }
 
-void AudioFlinger::addActiveTrack(const wp<Track>& t)
+// addActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
 {
     mActiveTracks.add(t);
 
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+   
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
+        }        
 #ifdef WITH_A2DP
-    // disable A2DP for certain stream types
-    sp<Track> track = t.promote();
-    if (streamDisablesA2dp(track->type())) {
-        if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) {
-            setA2dpEnabled(false);
-            mA2dpSuppressed = true;
-            LOGD("mA2dpSuppressed = true\n");
+        // AudioFlinger::mLock must be locked before calling
+        // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+        if (streamDisablesA2dp(track->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
         }
-        LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount);
-    }
 #endif
+    }
 }
 
-void AudioFlinger::removeActiveTrack(const wp<Track>& t)
+// removeActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
 {
     mActiveTracks.remove(t);
+
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+        }
 #ifdef WITH_A2DP
-    // disable A2DP for certain stream types
-    sp<Track> track = t.promote();
-    if (streamDisablesA2dp(track->type())) {
-        if (mA2dpDisableCount > 0) {
-            mA2dpDisableCount--;
-            if (mA2dpDisableCount == 0 && mA2dpSuppressed) {
-                setA2dpEnabled(true);
-                mA2dpSuppressed = false;
-            }
-            LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount);
-        } else
-            LOGE("mA2dpDisableCount is already zero");
-    }
+        // AudioFlinger::mLock must be locked before calling
+        // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+        if (streamDisablesA2dp(track->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
+        }
 #endif
+    }
+}
+
+// getTrackName_l() must be called with AudioFlinger::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
+{
+    return mAudioMixer->getTrackName();
+}
+
+// deleteTrackName_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
+{
+    mAudioMixer->deleteTrackName(name);
+}
+
+size_t AudioFlinger::MixerThread::getOutputFrameCount() 
+{
+    return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
 }
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
-    :   RefBase(),
-        mAudioFlinger(audioFlinger),
-        mMemoryDealer(new MemoryDealer(1024*1024)),
-        mPid(pid)
-{
-    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
-}
-
-AudioFlinger::Client::~Client()
-{
-    mAudioFlinger->removeClient(mPid);
-}
-
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
-{
-    return mMemoryDealer;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::TrackBase::TrackBase(
-            const sp<AudioFlinger>& audioFlinger,
+// TrackBase constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+            const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
             int streamType,
             uint32_t sampleRate,
             int format,
             int channelCount,
             int frameCount,
+            uint32_t flags,
             const sp<IMemory>& sharedBuffer)
     :   RefBase(),
-        mAudioFlinger(audioFlinger),
+        mMixerThread(mixerThread),
         mClient(client),
         mStreamType(streamType),
         mFrameCount(0),
         mState(IDLE),
         mClientTid(-1),
         mFormat(format),
-        mFlags(0)
+        mFlags(flags & ~SYSTEM_FLAGS_MASK)
 {
-    mName = audioFlinger->audioMixer()->getTrackName();
+    mName = mixerThread->getTrackName_l();
+    LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     if (mName < 0) {
         LOGE("no more track names availlable");
         return;
@@ -1043,7 +1600,6 @@
 
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
-
     // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
    size_t size = sizeof(audio_track_cblk_t);
    size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
@@ -1051,41 +1607,60 @@
        size += bufferSize;
    }
 
-    mCblkMemory = client->heap()->allocate(size);
-    if (mCblkMemory != 0) {
-        mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
-        if (mCblk) { // construct the shared structure in-place.
-            new(mCblk) audio_track_cblk_t();
-            // clear all buffers
-            mCblk->frameCount = frameCount;
-            mCblk->sampleRate = sampleRate;
-            mCblk->channels = channelCount;
-            if (sharedBuffer == 0) {
-                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
-                memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
-                // Force underrun condition to avoid false underrun callback until first data is
-                // written to buffer
-                mCblk->flowControlFlag = 1;
-            } else {
-                mBuffer = sharedBuffer->pointer();
+   if (client != NULL) {
+        mCblkMemory = client->heap()->allocate(size);
+        if (mCblkMemory != 0) {
+            mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
+            if (mCblk) { // construct the shared structure in-place.
+                new(mCblk) audio_track_cblk_t();
+                // clear all buffers
+                mCblk->frameCount = frameCount;
+                mCblk->sampleRate = sampleRate;
+                mCblk->channels = channelCount;
+                if (sharedBuffer == 0) {
+                    mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                    memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+                    // Force underrun condition to avoid false underrun callback until first data is
+                    // written to buffer
+                    mCblk->flowControlFlag = 1;
+                } else {
+                    mBuffer = sharedBuffer->pointer();
+                }
+                mBufferEnd = (uint8_t *)mBuffer + bufferSize;
             }
-            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+        } else {
+            LOGE("not enough memory for AudioTrack size=%u", size);
+            client->heap()->dump("AudioTrack");
+            return;
         }
-    } else {
-        LOGE("not enough memory for AudioTrack size=%u", size);
-        client->heap()->dump("AudioTrack");
-        return;
-    }
+   } else {
+       mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+       if (mCblk) { // construct the shared structure in-place.
+           new(mCblk) audio_track_cblk_t();
+           // clear all buffers
+           mCblk->frameCount = frameCount;
+           mCblk->sampleRate = sampleRate;
+           mCblk->channels = channelCount;
+           mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+           memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+           // Force underrun condition to avoid false underrun callback until first data is
+           // written to buffer
+           mCblk->flowControlFlag = 1;
+           mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+       }
+   }
 }
 
-AudioFlinger::TrackBase::~TrackBase()
+AudioFlinger::MixerThread::TrackBase::~TrackBase()
 {
-    mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
+    if (mCblk) {
+        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.        
+    }
     mCblkMemory.clear();            // and free the shared memory
     mClient.clear();
 }
 
-void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
     mFrameCount = buffer->frameCount;
@@ -1093,7 +1668,7 @@
     buffer->frameCount = 0;
 }
 
-bool AudioFlinger::TrackBase::step() {
+bool AudioFlinger::MixerThread::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
 
@@ -1105,31 +1680,31 @@
     return result;
 }
 
-void AudioFlinger::TrackBase::reset() {
+void AudioFlinger::MixerThread::TrackBase::reset() {
     audio_track_cblk_t* cblk = this->cblk();
 
     cblk->user = 0;
     cblk->server = 0;
     cblk->userBase = 0;
     cblk->serverBase = 0;
-    mFlags = 0;
+    mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
     LOGV("TrackBase::reset");
 }
 
-sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
 {
     return mCblkMemory;
 }
 
-int AudioFlinger::TrackBase::sampleRate() const {
+int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
     return mCblk->sampleRate;
 }
 
-int AudioFlinger::TrackBase::channelCount() const {
+int AudioFlinger::MixerThread::TrackBase::channelCount() const {
     return mCblk->channels;
 }
 
-void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
     audio_track_cblk_t* cblk = this->cblk();
     int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
     int16_t *bufferEnd = bufferStart + frames * cblk->channels;
@@ -1148,8 +1723,9 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::Track::Track(
-            const sp<AudioFlinger>& audioFlinger,
+// Track constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::Track::Track(
+            const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
             int streamType,
             uint32_t sampleRate,
@@ -1157,7 +1733,7 @@
             int channelCount,
             int frameCount,
             const sp<IMemory>& sharedBuffer)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
@@ -1165,23 +1741,36 @@
     mSharedBuffer = sharedBuffer;
 }
 
-AudioFlinger::Track::~Track()
+AudioFlinger::MixerThread::Track::~Track()
 {
     wp<Track> weak(this); // never create a strong ref from the dtor
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     mState = TERMINATED;
-    mAudioFlinger->removeTrack(weak, mName);
+    mMixerThread->removeTrack_l(weak, mName);
 }
 
-void AudioFlinger::Track::destroy()
+void AudioFlinger::MixerThread::Track::destroy()
 {
-    mAudioFlinger->destroyTrack(this);
+    // NOTE: destroyTrack_l() can remove a strong reference to this Track 
+    // by removing it from mTracks vector, so there is a risk that this Tracks's
+    // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
+    // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
+    // here so that the destructor is called only when exiting this function.
+    // On the other hand, as long as Track::destroy() is only called by 
+    // TrackHandle destructor, the TrackHandle still holds a strong ref on 
+    // this Track with its member mTrack.
+    sp<Track> keep(this);
+    { // scope for AudioFlinger::mLock
+        Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+        mMixerThread->destroyTrack_l(this);
+    }
 }
 
-void AudioFlinger::Track::dump(char* buffer, size_t size)
+void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
 {
     snprintf(buffer, size, "  %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
             mName - AudioMixer::TRACK0,
-            mClient->pid(),
+            (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
             mCblk->channels,
@@ -1196,7 +1785,7 @@
             mCblk->user);
 }
 
-status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
      audio_track_cblk_t* cblk = this->cblk();
      uint32_t framesReady;
@@ -1236,53 +1825,55 @@
      return NOT_ENOUGH_DATA;
 }
 
-bool AudioFlinger::Track::isReady() const {
+bool AudioFlinger::MixerThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING) return true;
 
     if (mCblk->framesReady() >= mCblk->frameCount ||
         mCblk->forceReady) {
         mFillingUpStatus = FS_FILLED;
         mCblk->forceReady = 0;
+        LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
         return true;
     }
     return false;
 }
 
-status_t AudioFlinger::Track::start()
+status_t AudioFlinger::MixerThread::Track::start()
 {
-    LOGV("start(%d)", mName);
-    mAudioFlinger->addTrack(this);
+    LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+    mMixerThread->addTrack_l(this);
     return NO_ERROR;
 }
 
-void AudioFlinger::Track::stop()
+void AudioFlinger::MixerThread::Track::stop()
 {
-    LOGV("stop(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     if (mState > STOPPED) {
         mState = STOPPED;
         // If the track is not active (PAUSED and buffers full), flush buffers
-        if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+        if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
             reset();
         }
         LOGV("(> STOPPED) => STOPPED (%d)", mName);
     }
 }
 
-void AudioFlinger::Track::pause()
+void AudioFlinger::MixerThread::Track::pause()
 {
-    LOGV("pause(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     if (mState == ACTIVE || mState == RESUMING) {
         mState = PAUSING;
         LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
     }
 }
 
-void AudioFlinger::Track::flush()
+void AudioFlinger::MixerThread::Track::flush()
 {
     LOGV("flush(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
         return;
     }
@@ -1298,7 +1889,7 @@
     reset();
 }
 
-void AudioFlinger::Track::reset()
+void AudioFlinger::MixerThread::Track::reset()
 {
     // Do not reset twice to avoid discarding data written just after a flush and before
     // the audioflinger thread detects the track is stopped.
@@ -1313,12 +1904,12 @@
     }
 }
 
-void AudioFlinger::Track::mute(bool muted)
+void AudioFlinger::MixerThread::Track::mute(bool muted)
 {
     mMute = muted;
 }
 
-void AudioFlinger::Track::setVolume(float left, float right)
+void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
 {
     mVolume[0] = left;
     mVolume[1] = right;
@@ -1326,7 +1917,292 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+// RecordTrack constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::RecordTrack::RecordTrack(
+            const sp<MixerThread>& mixerThread,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount,
+            uint32_t flags)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format,
+                  channelCount, frameCount, flags, 0),
+        mOverflow(false)
+{
+}
+
+AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+{
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+    mMixerThread->deleteTrackName_l(mName);
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
+
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::start()
+{
+    return mMixerThread->mAudioFlinger->startRecord(this);
+}
+
+void AudioFlinger::MixerThread::RecordTrack::stop()
+{
+    mMixerThread->mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::OutputTrack::OutputTrack(
+            const sp<MixerThread>& mixerThread,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount)
+    :   Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
+    mOutputMixerThread(mixerThread)
+{
+                
+    mCblk->out = 1;
+    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+    mOutBuffer.frameCount = 0;
+    mCblk->bufferTimeoutMs = 10;
+    
+    LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", 
+            mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+    
+}
+
+AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+{
+    stop();
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::start()
+{
+    status_t status = Track::start();
+    
+    mRetryCount = 127;
+    return status;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::stop()
+{
+    Track::stop();
+    clearBufferQueue();
+    mOutBuffer.frameCount = 0;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+{
+    Buffer *pInBuffer;
+    Buffer inBuffer;
+    uint32_t channels = mCblk->channels;
+        
+    inBuffer.frameCount = frames;
+    inBuffer.i16 = data;
+    
+    if (mCblk->user == 0) {
+        if (mOutputMixerThread->isMusicActive()) {
+            mCblk->forceReady = 1;
+            LOGV("OutputTrack::start() force ready");
+        } else if (mCblk->frameCount > frames){
+            if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+                uint32_t startFrames = (mCblk->frameCount - frames);
+                LOGV("OutputTrack::start() write %d frames", startFrames);
+                pInBuffer = new Buffer;
+                pInBuffer->mBuffer = new int16_t[startFrames * channels];
+                pInBuffer->frameCount = startFrames;
+                pInBuffer->i16 = pInBuffer->mBuffer;
+                memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+                mBufferQueue.add(pInBuffer);                
+            } else {
+                LOGW ("OutputTrack::write() no more buffers");
+            }
+        }        
+    }
+
+    while (1) { 
+        // First write pending buffers, then new data
+        if (mBufferQueue.size()) {
+            pInBuffer = mBufferQueue.itemAt(0);
+        } else {
+            pInBuffer = &inBuffer;
+        }
+ 
+        if (pInBuffer->frameCount == 0) {
+            break;
+        }
+        
+        if (mOutBuffer.frameCount == 0) {
+            mOutBuffer.frameCount = pInBuffer->frameCount;
+            if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+                break;
+            }
+        }
+            
+        uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
+        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+        mCblk->stepUser(outFrames);
+        pInBuffer->frameCount -= outFrames;
+        pInBuffer->i16 += outFrames * channels;
+        mOutBuffer.frameCount -= outFrames;
+        mOutBuffer.i16 += outFrames * channels;            
+        
+        if (pInBuffer->frameCount == 0) {
+            if (mBufferQueue.size()) {
+                mBufferQueue.removeAt(0);
+                delete [] pInBuffer->mBuffer;
+                delete pInBuffer;
+            } else {
+                break;
+            }
+        }
+    }
+ 
+    // If we could not write all frames, allocate a buffer and queue it for next time.
+    if (inBuffer.frameCount) {
+        if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+            pInBuffer = new Buffer;
+            pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+            pInBuffer->frameCount = inBuffer.frameCount;
+            pInBuffer->i16 = pInBuffer->mBuffer;
+            memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+            mBufferQueue.add(pInBuffer);
+        } else {
+            LOGW("OutputTrack::write() no more buffers");
+        }
+    }
+    
+    // Calling write() with a 0 length buffer, means that no more data will be written:
+    // If no more buffers are pending, fill output track buffer to make sure it is started 
+    // by output mixer.
+    if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
+        frames = mCblk->frameCount - mCblk->user;
+        pInBuffer = new Buffer;
+        pInBuffer->mBuffer = new int16_t[frames * channels];
+        pInBuffer->frameCount = frames;
+        pInBuffer->i16 = pInBuffer->mBuffer;
+        memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+        mBufferQueue.add(pInBuffer);
+    }
+
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    int active;
+    int timeout = 0;
+    status_t result;
+    audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = buffer->frameCount;
+
+    LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+    buffer->frameCount  = 0;
+    
+    uint32_t framesAvail = cblk->framesAvailable();
+
+    if (framesAvail == 0) {
+        return AudioTrack::NO_MORE_BUFFERS;
+    }
+
+    if (framesReq > framesAvail) {
+        framesReq = framesAvail;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
+    buffer->frameCount  = framesReq;
+    buffer->raw         = (void *)cblk->buffer(u);
+    return NO_ERROR;
+}
+
+
+void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+{
+    size_t size = mBufferQueue.size();
+    Buffer *pBuffer;
+    
+    for (size_t i = 0; i < size; i++) {
+        pBuffer = mBufferQueue.itemAt(i);
+        delete [] pBuffer->mBuffer;
+        delete pBuffer;
+    }
+    mBufferQueue.clear();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+    :   RefBase(),
+        mAudioFlinger(audioFlinger),
+        mMemoryDealer(new MemoryDealer(1024*1024)),
+        mPid(pid)
+{
+    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+    mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+    return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
     : BnAudioTrack(),
       mTrack(track)
 {
@@ -1386,8 +2262,7 @@
         uint32_t flags,
         status_t *status)
 {
-    sp<AudioRecordThread> thread;
-    sp<RecordTrack> recordTrack;
+    sp<MixerThread::RecordTrack> recordTrack;
     sp<RecordHandle> recordHandle;
     sp<Client> client;
     wp<Client> wclient;
@@ -1414,12 +2289,6 @@
         goto Exit;
     }
 
-    if (mSampleRate == 0) {
-        LOGE("Audio driver not initialized");
-        lStatus = NO_INIT;
-        goto Exit;
-    }
-
     if (mAudioRecordThread == 0) {
         LOGE("Audio record thread not started");
         lStatus = NO_INIT;
@@ -1436,7 +2305,7 @@
     }
 
     // add client to list
-    {
+    { // scope for mLock
         Mutex::Autolock _l(mLock);
         wclient = mClients.valueFor(pid);
         if (wclient != NULL) {
@@ -1445,15 +2314,20 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
+
+        // frameCount must be a multiple of input buffer size
+        inFrameCount = inputBufferSize/channelCount/sizeof(short);
+        frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+    
+        // create new record track. The record track uses one track in mHardwareMixerThread by convention.
+        recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+                                                   format, channelCount, frameCount, flags);
     }
-
-    // frameCount must be a multiple of input buffer size
-    inFrameCount = inputBufferSize/channelCount/sizeof(short);
-    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
-    // create new record track and pass to record thread
-    recordTrack = new RecordTrack(this, client, streamType, sampleRate,
-            format, channelCount, frameCount);
+    if (recordTrack->getCblk() == NULL) {
+        recordTrack.clear();
+        lStatus = NO_MEMORY;
+        goto Exit;
+    }
 
     // return to handle to client
     recordHandle = new RecordHandle(recordTrack);
@@ -1466,97 +2340,22 @@
     return recordHandle;
 }
 
-status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
     if (mAudioRecordThread != 0) {
         return mAudioRecordThread->start(recordTrack);        
     }
     return NO_INIT;
 }
 
-void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
     if (mAudioRecordThread != 0) {
         mAudioRecordThread->stop(recordTrack);
     }
 }
 
-
 // ----------------------------------------------------------------------------
 
-AudioFlinger::RecordTrack::RecordTrack(
-            const sp<AudioFlinger>& audioFlinger,
-            const sp<Client>& client,
-            int streamType,
-            uint32_t sampleRate,
-            int format,
-            int channelCount,
-            int frameCount)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
-            channelCount, frameCount, 0),
-            mOverflow(false)
-{
-}
-
-AudioFlinger::RecordTrack::~RecordTrack()
-{
-    mAudioFlinger->audioMixer()->deleteTrackName(mName);
-}
-
-status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
-{
-    audio_track_cblk_t* cblk = this->cblk();
-    uint32_t framesAvail;
-    uint32_t framesReq = buffer->frameCount;
-
-     // Check if last stepServer failed, try to step now
-    if (mFlags & TrackBase::STEPSERVER_FAILED) {
-        if (!step()) goto getNextBuffer_exit;
-        LOGV("stepServer recovered");
-        mFlags &= ~TrackBase::STEPSERVER_FAILED;
-    }
-
-    framesAvail = cblk->framesAvailable_l();
-
-    if (LIKELY(framesAvail)) {
-        uint32_t s = cblk->server;
-        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
-
-        if (framesReq > framesAvail) {
-            framesReq = framesAvail;
-        }
-        if (s + framesReq > bufferEnd) {
-            framesReq = bufferEnd - s;
-        }
-
-        buffer->raw = getBuffer(s, framesReq);
-        if (buffer->raw == 0) goto getNextBuffer_exit;
-
-        buffer->frameCount = framesReq;
-        return NO_ERROR;
-    }
-
-getNextBuffer_exit:
-    buffer->raw = 0;
-    buffer->frameCount = 0;
-    return NOT_ENOUGH_DATA;
-}
-
-status_t AudioFlinger::RecordTrack::start()
-{
-    return mAudioFlinger->startRecord(this);
-}
-
-void AudioFlinger::RecordTrack::stop()
-{
-    mAudioFlinger->stopRecord(this);
-    TrackBase::reset();
-    // Force overerrun condition to avoid false overrun callback until first data is
-    // read from buffer
-    mCblk->flowControlFlag = 1;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
     : BnAudioRecord(),
     mRecordTrack(recordTrack)
 {
@@ -1588,8 +2387,10 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
+            const sp<AudioFlinger>& audioFlinger) :
     mAudioHardware(audioHardware),
+    mAudioFlinger(audioFlinger),
     mActive(false)
 {
 }
@@ -1619,15 +2420,17 @@
                     input = 0;
                 }
                 mRecordTrack.clear();
+                mStopped.signal();
 
                 mWaitWorkCV.wait(mLock);
                
                 LOGV("AudioRecordThread: loop starting");
                 if (mRecordTrack != 0) {
                     input = mAudioHardware->openInputStream(mRecordTrack->format(), 
-                                            mRecordTrack->channelCount(), 
-                                            mRecordTrack->sampleRate(), 
-                                            &mStartStatus);
+                                    mRecordTrack->channelCount(), 
+                                    mRecordTrack->sampleRate(), 
+                                    &mStartStatus,
+                                    (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
                     if (input != 0) {
                         inBufferSize = input->bufferSize();
                         inFrameCount = inBufferSize/input->frameSize();                        
@@ -1643,12 +2446,14 @@
                 mWaitWorkCV.signal();
             }
             mLock.unlock();
-        } else if (mRecordTrack != 0){
+        } else if (mRecordTrack != 0) {
 
             buffer.frameCount = inFrameCount;
-            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
+                       (int)buffer.frameCount == inFrameCount)) {
                 LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
-                if (input->read(buffer.raw, inBufferSize) < 0) {
+                ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
+                if (bytesRead < 0) {
                     LOGE("Error reading audio input");
                     sleep(1);
                 }
@@ -1677,7 +2482,7 @@
     return false;
 }
 
-status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
+status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
 {
     LOGV("AudioRecordThread::start");
     AutoMutex lock(&mLock);
@@ -1690,6 +2495,19 @@
 
     mRecordTrack = recordTrack;
 
+#ifdef WITH_A2DP
+    { // scope for lock2
+
+        // AudioFlinger::mLock must be locked before calling
+        // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+        AutoMutex lock2(&mAudioFlinger->mLock);
+
+        // Currently there is no way to detect if we are recording over SCO,
+        // so we disable A2DP during any recording.
+        mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
+    }
+#endif
+
     // signal thread to start
     LOGV("Signal record thread");
     mWaitWorkCV.signal();
@@ -1698,11 +2516,24 @@
     return mStartStatus;
 }
 
-void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
+void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
     if (mActive && (recordTrack == mRecordTrack.get())) {
+#ifdef WITH_A2DP
+        { // scope for lock2
+    
+            // AudioFlinger::mLock must be locked before calling
+            // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+            AutoMutex lock2(&mAudioFlinger->mLock);
+
+            // Currently there is no way to detect if we are recording over SCO,
+            // so we disable A2DP during any recording.
+            mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
+        }
+#endif
         mActive = false;
+        mStopped.wait(mLock);
     }
 }
 
@@ -1717,6 +2548,22 @@
     requestExitAndWait();
 }
 
+status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    pid_t pid = 0;
+
+    if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
+        snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+        result.append(buffer);
+    } else {
+        result.append("No record client\n");
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
 
 status_t AudioFlinger::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 9ab362a..ab15947 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 
 #include <media/IAudioFlinger.h>
+#include <media/IAudioFlingerClient.h>
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/AudioTrack.h>
@@ -32,6 +33,7 @@
 #include <utils/MemoryDealer.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
+#include <utils/Vector.h>
 
 #include <hardware_legacy/AudioHardwareInterface.h>
 
@@ -54,18 +56,13 @@
 
 static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 
-class AudioFlinger : public BnAudioFlinger, protected Thread
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient 
 {
 public:
     static void instantiate();
 
     virtual     status_t    dump(int fd, const Vector<String16>& args);
 
-    // Thread virtuals
-    virtual     bool        threadLoop();
-    virtual     status_t    readyToRun();
-    virtual     void        onFirstRef();
-
     // IAudioFlinger interface
     virtual sp<IAudioTrack> createTrack(
                                 pid_t pid,
@@ -78,11 +75,11 @@
                                 const sp<IMemory>& sharedBuffer,
                                 status_t *status);
 
-    virtual     uint32_t    sampleRate() const;
-    virtual     int         channelCount() const;
-    virtual     int         format() const;
-    virtual     size_t      frameCount() const;
-    virtual     size_t      latency() const;
+    virtual     uint32_t    sampleRate(int output) const;
+    virtual     int         channelCount(int output) const;
+    virtual     int         format(int output) const;
+    virtual     size_t      frameCount(int output) const;
+    virtual     uint32_t    latency(int output) const;
 
     virtual     status_t    setMasterVolume(float value);
     virtual     status_t    setMasterMute(bool muted);
@@ -107,8 +104,19 @@
 
     virtual     bool        isMusicActive() const;
 
+    virtual     bool        isA2dpEnabled() const;
+
     virtual     status_t    setParameter(const char* key, const char* value);
 
+    virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
+    
+    virtual     size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+    
+    virtual     void        wakeUp()    { mWaitWorkCV.broadcast(); }
+    
+    // IBinder::DeathRecipient
+    virtual     void        binderDied(const wp<IBinder>& who);
+
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
         AUDIO_HW_INIT,
@@ -149,23 +157,31 @@
                             AudioFlinger();
     virtual                 ~AudioFlinger();
     
-    void                    setOutput(AudioStreamOut* output);
-    void                    doSetOutput(AudioStreamOut* output);
-    size_t                  getOutputFrameCount(AudioStreamOut* output);
+    void                    setOutput(int outputType);
+    void                    doSetOutput(int outputType);
 
 #ifdef WITH_A2DP
+    void                    setA2dpEnabled_l(bool enable);
+    void                    checkA2dpEnabledChange_l();
+#endif
+    static bool             streamForcedToSpeaker(int streamType);
     static bool             streamDisablesA2dp(int streamType);
-    inline bool             isA2dpEnabled() const {
-                                return (mRequestedOutput == mA2dpOutput ||
-                                        (mOutput && mOutput == mA2dpOutput));
-                            }
-    void                    setA2dpEnabled(bool enable);
+    
+    // Management of forced route to speaker for certain track types.
+    enum force_speaker_command {
+        ACTIVE_TRACK_ADDED = 0,
+        ACTIVE_TRACK_REMOVED,
+        CHECK_ROUTE_RESTORE_TIME,
+        FORCE_ROUTE_RESTORE
+    };
+    void                    handleForcedSpeakerRoute(int command);
+#ifdef WITH_A2DP
+    void                    handleStreamDisablesA2dp_l(int command);
 #endif
 
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
     status_t dumpClients(int fd, const Vector<String16>& args);
-    status_t dumpTracks(int fd, const Vector<String16>& args);
     status_t dumpInternals(int fd, const Vector<String16>& args);
 
     // --- Client ---
@@ -184,168 +200,347 @@
     };
 
 
-    // --- Track ---
     class TrackHandle;
     class RecordHandle;
     class AudioRecordThread;
 
-    // base for record and playback
-    class TrackBase : public AudioBufferProvider, public RefBase {
-
+    
+    // --- MixerThread ---
+    class MixerThread : public Thread {
     public:
-        enum track_state {
-            IDLE,
-            TERMINATED,
-            STOPPED,
-            RESUMING,
-            ACTIVE,
-            PAUSING,
-            PAUSED
+        
+        // --- Track ---
+
+        // base for record and playback
+        class TrackBase : public AudioBufferProvider, public RefBase {
+
+        public:
+            enum track_state {
+                IDLE,
+                TERMINATED,
+                STOPPED,
+                RESUMING,
+                ACTIVE,
+                PAUSING,
+                PAUSED
+            };
+
+            enum track_flags {
+                STEPSERVER_FAILED = 0x01, //  StepServer could not acquire cblk->lock mutex
+                SYSTEM_FLAGS_MASK = 0x0000ffffUL,
+                // The upper 16 bits are used for track-specific flags.
+            };
+
+                                TrackBase(const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        uint32_t flags,
+                                        const sp<IMemory>& sharedBuffer);
+                                ~TrackBase();
+
+            virtual status_t    start() = 0;
+            virtual void        stop() = 0;
+                    sp<IMemory> getCblk() const;
+
+        protected:
+            friend class MixerThread;
+            friend class RecordHandle;
+            friend class AudioRecordThread;
+
+                                TrackBase(const TrackBase&);
+                                TrackBase& operator = (const TrackBase&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+            virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+            audio_track_cblk_t* cblk() const {
+                return mCblk;
+            }
+
+            int type() const {
+                return mStreamType;
+            }
+
+            int format() const {
+                return mFormat;
+            }
+
+            int channelCount() const ;
+
+            int sampleRate() const;
+
+            void* getBuffer(uint32_t offset, uint32_t frames) const;
+
+            int name() const {
+                return mName;
+            }
+
+            bool isStopped() const {
+                return mState == STOPPED;
+            }
+
+            bool isTerminated() const {
+                return mState == TERMINATED;
+            }
+
+            bool step();
+            void reset();
+
+            sp<MixerThread>     mMixerThread;
+            sp<Client>          mClient;
+            sp<IMemory>         mCblkMemory;
+            audio_track_cblk_t* mCblk;
+            int                 mStreamType;
+            void*               mBuffer;
+            void*               mBufferEnd;
+            uint32_t            mFrameCount;
+            int                 mName;
+            // we don't really need a lock for these
+            int                 mState;
+            int                 mClientTid;
+            uint8_t             mFormat;
+            uint32_t            mFlags;
         };
 
-        enum track_flags {
-            STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex
+        // playback track
+        class Track : public TrackBase {
+        public:
+                                Track(  const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        const sp<IMemory>& sharedBuffer);
+                                ~Track();
+
+                    void        dump(char* buffer, size_t size);
+            virtual status_t    start();
+            virtual void        stop();
+                    void        pause();
+
+                    void        flush();
+                    void        destroy();
+                    void        mute(bool);
+                    void        setVolume(float left, float right);
+
+        protected:
+            friend class MixerThread;
+            friend class AudioFlinger;
+            friend class AudioFlinger::TrackHandle;
+
+                                Track(const Track&);
+                                Track& operator = (const Track&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+            bool isMuted() const {
+                return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
+            }
+
+            bool isPausing() const {
+                return mState == PAUSING;
+            }
+
+            bool isPaused() const {
+                return mState == PAUSED;
+            }
+
+            bool isReady() const;
+
+            void setPaused() { mState = PAUSED; }
+            void reset();
+
+            // we don't really need a lock for these
+            float               mVolume[2];
+            volatile bool       mMute;
+            // FILLED state is used for suppressing volume ramp at begin of playing
+            enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+            mutable uint8_t     mFillingUpStatus;
+            int8_t              mRetryCount;
+            sp<IMemory>         mSharedBuffer;
+            bool                mResetDone;
+        };  // end of Track
+
+        // record track
+        class RecordTrack : public TrackBase {
+        public:
+                                RecordTrack(const sp<MixerThread>& mixerThread,
+                                        const sp<Client>& client,
+                                        int streamType,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount,
+                                        uint32_t flags);
+                                ~RecordTrack();
+
+            virtual status_t    start();
+            virtual void        stop();
+
+                    bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+                    bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+        private:
+            friend class AudioFlinger;
+            friend class AudioFlinger::RecordHandle;
+            friend class AudioFlinger::AudioRecordThread;
+            friend class MixerThread;
+
+                                RecordTrack(const Track&);
+                                RecordTrack& operator = (const Track&);
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+            bool                mOverflow;
         };
 
-                            TrackBase(  const sp<AudioFlinger>& audioFlinger,
-                                    const sp<Client>& client,
+        // playback track
+        class OutputTrack : public Track {
+        public:
+            
+            class Buffer: public AudioBufferProvider::Buffer {
+            public:
+                int16_t *mBuffer;
+            };
+            
+                                OutputTrack(  const sp<MixerThread>& mixerThread,
+                                        uint32_t sampleRate,
+                                        int format,
+                                        int channelCount,
+                                        int frameCount);
+                                ~OutputTrack();
+
+            virtual status_t    start();
+            virtual void        stop();
+                    void        write(int16_t* data, uint32_t frames);
+                    bool        bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+
+        private:
+
+            status_t            obtainBuffer(AudioBufferProvider::Buffer* buffer);
+            void                clearBufferQueue();
+            
+            sp<MixerThread>             mOutputMixerThread;
+            Vector < Buffer* >          mBufferQueue;
+            AudioBufferProvider::Buffer mOutBuffer;
+            uint32_t                    mFramesWritten;
+            
+         };  // end of OutputTrack
+
+        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
+        virtual             ~MixerThread();
+
+        virtual     status_t    dump(int fd, const Vector<String16>& args);
+
+        // Thread virtuals
+        virtual     bool        threadLoop();
+        virtual     status_t    readyToRun();
+        virtual     void        onFirstRef();
+
+        virtual     uint32_t    sampleRate() const;
+        virtual     int         channelCount() const;
+        virtual     int         format() const;
+        virtual     size_t      frameCount() const;
+        virtual     uint32_t    latency() const;
+
+        virtual     status_t    setMasterVolume(float value);
+        virtual     status_t    setMasterMute(bool muted);
+
+        virtual     float       masterVolume() const;
+        virtual     bool        masterMute() const;
+
+        virtual     status_t    setStreamVolume(int stream, float value);
+        virtual     status_t    setStreamMute(int stream, bool muted);
+
+        virtual     float       streamVolume(int stream) const;
+        virtual     bool        streamMute(int stream) const;
+
+                    bool        isMusicActive() const;
+        
+                    
+                    sp<Track>   createTrack_l(
+                                    const sp<AudioFlinger::Client>& client,
                                     int streamType,
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
                                     int frameCount,
-                                    const sp<IMemory>& sharedBuffer);
-                            ~TrackBase();
-
-        virtual status_t    start() = 0;
-        virtual void        stop() = 0;
-                sp<IMemory> getCblk() const;
-
-    protected:
-        friend class AudioFlinger;
-        friend class RecordHandle;
-        friend class AudioRecordThread;
-
-                            TrackBase(const TrackBase&);
-                            TrackBase& operator = (const TrackBase&);
-
-        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
-        virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
-        audio_track_cblk_t* cblk() const {
-            return mCblk;
-        }
-
-        int type() const {
-            return mStreamType;
-        }
-
-        int format() const {
-            return mFormat;
-        }
-
-        int channelCount() const ;
-
-        int sampleRate() const;
-
-        void* getBuffer(uint32_t offset, uint32_t frames) const;
-
-        int name() const {
-            return mName;
-        }
-
-        bool isStopped() const {
-            return mState == STOPPED;
-        }
-
-        bool isTerminated() const {
-            return mState == TERMINATED;
-        }
-
-        bool step();
-        void reset();
-
-        sp<AudioFlinger>    mAudioFlinger;
-        sp<Client>          mClient;
-        sp<IMemory>         mCblkMemory;
-        audio_track_cblk_t* mCblk;
-        int                 mStreamType;
-        void*               mBuffer;
-        void*               mBufferEnd;
-        uint32_t            mFrameCount;
-        int                 mName;
-        // we don't really need a lock for these
-        int                 mState;
-        int                 mClientTid;
-        uint8_t             mFormat;
-        uint8_t             mFlags;
-    };
-
-    // playback track
-    class Track : public TrackBase {
-    public:
-                            Track(  const sp<AudioFlinger>& audioFlinger,
-                                    const sp<Client>& client,
-                                    int streamType,
-                                    uint32_t sampleRate,
-                                    int format,
-                                    int channelCount,
-                                    int frameCount,
-                                    const sp<IMemory>& sharedBuffer);
-                            ~Track();
-
-                void        dump(char* buffer, size_t size);
-        virtual status_t    start();
-        virtual void        stop();
-                void        pause();
-
-                void        flush();
-                void        destroy();
-                void        mute(bool);
-                void        setVolume(float left, float right);
+                                    const sp<IMemory>& sharedBuffer,
+                                    status_t *status);
+                    
+                    void        getTracks_l(SortedVector < sp<Track> >& tracks,
+                                          SortedVector < wp<Track> >& activeTracks);
+                    void        putTracks_l(SortedVector < sp<Track> >& tracks,
+                                          SortedVector < wp<Track> >& activeTracks);
+                    void        setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
+                    
+        struct  stream_type_t {
+            stream_type_t()
+                :   volume(1.0f),
+                    mute(false)
+            {
+            }
+            float       volume;
+            bool        mute;
+        };
 
     private:
+
+
         friend class AudioFlinger;
-        friend class TrackHandle;
+        friend class Track;
+        friend class TrackBase;
+        friend class RecordTrack;
+        
+        MixerThread(const Client&);
+        MixerThread& operator = (const MixerThread&);
+  
+        status_t    addTrack_l(const sp<Track>& track);
+        void        removeTrack_l(wp<Track> track, int name);
+        void        destroyTrack_l(const sp<Track>& track);
+        int         getTrackName_l();
+        void        deleteTrackName_l(int name);
+        void        addActiveTrack_l(const wp<Track>& t);
+        void        removeActiveTrack_l(const wp<Track>& t);
+        size_t      getOutputFrameCount();
 
-                            Track(const Track&);
-                            Track& operator = (const Track&);
+        status_t    dumpInternals(int fd, const Vector<String16>& args);
+        status_t    dumpTracks(int fd, const Vector<String16>& args);
+        
+        sp<AudioFlinger>                mAudioFlinger;       
+        SortedVector< wp<Track> >       mActiveTracks;
+        SortedVector< sp<Track> >       mTracks;
+        stream_type_t                   mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+        AudioMixer*                     mAudioMixer;
+        AudioStreamOut*                 mOutput;
+        int                             mOutputType;
+        uint32_t                        mSampleRate;
+        size_t                          mFrameCount;
+        int                             mChannelCount;
+        int                             mFormat;
+        int16_t*                        mMixBuffer;
+        float                           mMasterVolume;
+        bool                            mMasterMute;
+        nsecs_t                         mLastWriteTime;
+        int                             mNumWrites;
+        int                             mNumDelayedWrites;
+        bool                            mStandby;
+        bool                            mInWrite;
+        sp <OutputTrack>                mOutputTrack;
+    };
 
-        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
-        bool isMuted() const {
-            return mMute;
-        }
-
-        bool isPausing() const {
-            return mState == PAUSING;
-        }
-
-        bool isPaused() const {
-            return mState == PAUSED;
-        }
-
-        bool isReady() const;
-
-        void setPaused() { mState = PAUSED; }
-        void reset();
-
-        // we don't really need a lock for these
-        float               mVolume[2];
-        volatile bool       mMute;
-        // FILLED state is used for suppressing volume ramp at begin of playing
-        enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
-        mutable uint8_t     mFillingUpStatus;
-        int8_t              mRetryCount;
-        sp<IMemory>         mSharedBuffer;
-        bool                mResetDone;
-    };  // end of Track
-
+    
     friend class AudioBuffer;
 
     class TrackHandle : public android::BnAudioTrack {
     public:
-                            TrackHandle(const sp<Track>& track);
+                            TrackHandle(const sp<MixerThread::Track>& track);
         virtual             ~TrackHandle();
         virtual status_t    start();
         virtual void        stop();
@@ -357,70 +552,20 @@
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<Track> mTrack;
-    };
-
-    struct  stream_type_t {
-        stream_type_t()
-            :   volume(1.0f),
-                mute(false)
-        {
-        }
-        float       volume;
-        bool        mute;
+        sp<MixerThread::Track> mTrack;
     };
 
     friend class Client;
-    friend class Track;
+    friend class MixerThread::Track;
 
 
                 void        removeClient(pid_t pid);
 
-                status_t    addTrack(const sp<Track>& track);
-                void        removeTrack(wp<Track> track, int name);
-                void        remove_track_l(wp<Track> track, int name);
-                void        destroyTrack(const sp<Track>& track);
-                void        addActiveTrack(const wp<Track>& track);
-                void        removeActiveTrack(const wp<Track>& track);
 
-                AudioMixer* audioMixer() {
-                    return mAudioMixer;
-                }
-
-    // record track
-    class RecordTrack : public TrackBase {
-    public:
-                            RecordTrack(  const sp<AudioFlinger>& audioFlinger,
-                                    const sp<Client>& client,
-                                    int streamType,
-                                    uint32_t sampleRate,
-                                    int format,
-                                    int channelCount,
-                                    int frameCount);
-                            ~RecordTrack();
-
-        virtual status_t    start();
-        virtual void        stop();
-
-                bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
-                bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
-    private:
-        friend class AudioFlinger;
-        friend class RecordHandle;
-        friend class AudioRecordThread;
-
-                            RecordTrack(const Track&);
-                            RecordTrack& operator = (const Track&);
-
-        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
-        bool                mOverflow;
-    };
 
     class RecordHandle : public android::BnAudioRecord {
     public:
-        RecordHandle(const sp<RecordTrack>& recordTrack);
+        RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
         virtual status_t    start();
         virtual void        stop();
@@ -428,72 +573,66 @@
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<RecordTrack> mRecordTrack;
+        sp<MixerThread::RecordTrack> mRecordTrack;
     };
 
     // record thread
     class AudioRecordThread : public Thread
     {
     public:
-        AudioRecordThread(AudioHardwareInterface* audioHardware);
+        AudioRecordThread(AudioHardwareInterface* audioHardware, const sp<AudioFlinger>& audioFlinger);
         virtual             ~AudioRecordThread();
         virtual bool        threadLoop();
         virtual status_t    readyToRun() { return NO_ERROR; }
         virtual void        onFirstRef() {}
 
-                status_t    start(RecordTrack* recordTrack);
-                void        stop(RecordTrack* recordTrack);
+                status_t    start(MixerThread::RecordTrack* recordTrack);
+                void        stop(MixerThread::RecordTrack* recordTrack);
                 void        exit();
+                status_t    dump(int fd, const Vector<String16>& args);
 
     private:
                 AudioRecordThread();
                 AudioHardwareInterface              *mAudioHardware;
-                sp<RecordTrack>                     mRecordTrack;
+                sp<AudioFlinger>                    mAudioFlinger;
+                sp<MixerThread::RecordTrack>        mRecordTrack;
                 Mutex                               mLock;
                 Condition                           mWaitWorkCV;
+                Condition                           mStopped;
                 volatile bool                       mActive;
                 status_t                            mStartStatus;
     };
 
     friend class AudioRecordThread;
+    friend class MixerThread;
 
-                status_t    startRecord(RecordTrack* recordTrack);
-                void        stopRecord(RecordTrack* recordTrack);
+                status_t    startRecord(MixerThread::RecordTrack* recordTrack);
+                void        stopRecord(MixerThread::RecordTrack* recordTrack);
 
-    mutable     Mutex                                       mHardwareLock;
-    mutable     Mutex                                       mLock;
-    mutable     Condition                                   mWaitWorkCV;
+    mutable     Mutex                               mHardwareLock;
+    mutable     Mutex                               mLock;
+    mutable     Condition                           mWaitWorkCV;
+
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;
-                SortedVector< wp<Track> >                   mActiveTracks;
-                SortedVector< sp<Track> >                   mTracks;
-                float                               mMasterVolume;
-                uint32_t                            mMasterRouting;
-                bool                                mMasterMute;
-                stream_type_t                       mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
 
-                AudioMixer*                         mHardwareAudioMixer;
-                AudioMixer*                         mA2dpAudioMixer;
-                AudioMixer*                         mAudioMixer;
+                sp<MixerThread>                     mA2dpMixerThread;
+                sp<MixerThread>                     mHardwareMixerThread;
                 AudioHardwareInterface*             mAudioHardware;
                 AudioHardwareInterface*             mA2dpAudioInterface;
-                AudioStreamOut*                     mHardwareOutput;
-                AudioStreamOut*                     mA2dpOutput;
-                AudioStreamOut*                     mOutput;
-                AudioStreamOut*                     mRequestedOutput;
                 sp<AudioRecordThread>               mAudioRecordThread;
-                uint32_t                            mSampleRate;
-                size_t                              mFrameCount;
-                int                                 mChannelCount;
-                int                                 mFormat;
-                int16_t*                            mMixBuffer;
+                bool                                mA2dpEnabled;
+                bool                                mNotifyA2dpChange;
     mutable     int                                 mHardwareStatus;
-                nsecs_t                             mLastWriteTime;
-                int                                 mNumWrites;
-                int                                 mNumDelayedWrites;
-                bool                                mStandby;
-                bool                                mInWrite;
+                SortedVector< wp<IBinder> >         mNotificationClients;
+                int                                 mForcedSpeakerCount;
                 int                                 mA2dpDisableCount;
+
+                // true if A2DP should resume when mA2dpDisableCount returns to zero
                 bool                                mA2dpSuppressed;
+                uint32_t                            mSavedRoute;
+                uint32_t                            mForcedRoute;
+                nsecs_t                             mRouteRestoreTime;
+                bool                                mMusicMuteSaved;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index e455186..62beada 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -93,7 +93,8 @@
 }
 
 AudioStreamIn* AudioHardwareGeneric::openInputStream(
-        int format, int channelCount, uint32_t sampleRate, status_t *status)
+        int format, int channelCount, uint32_t sampleRate, status_t *status,
+        AudioSystem::audio_in_acoustics acoustics)
 {
     AutoMutex lock(mLock);
 
@@ -107,7 +108,7 @@
 
     // create new output stream
     AudioStreamInGeneric* in = new AudioStreamInGeneric();
-    status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate);
+    status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
     if (status) {
         *status = lStatus;
     }
@@ -246,7 +247,8 @@
         int fd,
         int format,
         int channels,
-        uint32_t rate)
+        uint32_t rate,
+        AudioSystem::audio_in_acoustics acoustics)
 {
     // FIXME: remove logging
     LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index a7822e1..c949aa1 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -47,7 +47,7 @@
     virtual size_t      bufferSize() const { return 4096; }
     virtual int         channelCount() const { return 2; }
     virtual int         format() const { return AudioSystem::PCM_16_BIT; }
-    virtual uint32_t    latency() const { return 0; }
+    virtual uint32_t    latency() const { return 20; }
     virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
     virtual ssize_t     write(const void* buffer, size_t bytes);
     virtual status_t    standby();
@@ -69,7 +69,8 @@
             int mFd,
             int format,
             int channelCount,
-            uint32_t sampleRate);
+            uint32_t sampleRate,
+            AudioSystem::audio_in_acoustics acoustics);
 
     uint32_t    sampleRate() const { return 8000; }
     virtual size_t      bufferSize() const { return 320; }
@@ -114,7 +115,8 @@
             int format,
             int channelCount,
             uint32_t sampleRate,
-            status_t *status);
+            status_t *status,
+            AudioSystem::audio_in_acoustics acoustics);
 
             void            closeOutputStream(AudioStreamOutGeneric* out);
             void            closeInputStream(AudioStreamInGeneric* in);
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index e9f3d69..b13cb1c 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -56,10 +56,11 @@
 }
 
 AudioStreamIn* AudioHardwareStub::openInputStream(
-        int format, int channelCount, uint32_t sampleRate, status_t *status)
+        int format, int channelCount, uint32_t sampleRate,
+        status_t *status, AudioSystem::audio_in_acoustics acoustics)
 {
     AudioStreamInStub* in = new AudioStreamInStub();
-    status_t lStatus = in->set(format, channelCount, sampleRate);
+    status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
     if (status) {
         *status = lStatus;
     }
@@ -142,7 +143,8 @@
 
 // ----------------------------------------------------------------------------
 
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+				AudioSystem::audio_in_acoustics acoustics)
 {
     if ((format == AudioSystem::PCM_16_BIT) &&
             (channels == channelCount()) &&
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 24736ed..d406424 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -43,7 +43,7 @@
 
 class AudioStreamInStub : public AudioStreamIn {
 public:
-    virtual status_t    set(int format, int channelCount, uint32_t sampleRate);
+    virtual status_t    set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
     virtual uint32_t    sampleRate() const { return 8000; }
     virtual size_t      bufferSize() const { return 320; }
     virtual int         channelCount() const { return 1; }
@@ -81,7 +81,8 @@
                                 int format,
                                 int channelCount,
                                 uint32_t sampleRate,
-                                status_t *status);
+                                status_t *status,
+				AudioSystem::audio_in_acoustics acoustics);
 
 protected:
     virtual status_t    doRouting() { return NO_ERROR; }
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index d14cebf..496e271 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -15,8 +15,8 @@
     LayerBlur.cpp \
     LayerBitmap.cpp \
     LayerDim.cpp \
-    LayerScreenshot.cpp \
-    RFBServer.cpp \
+    LayerOrientationAnim.cpp \
+    OrientationAnimation.cpp \
     SurfaceFlinger.cpp \
     Tokenizer.cpp \
     Transform.cpp \
@@ -38,7 +38,8 @@
 	libcorecg \
 	libsgl \
 	libpixelflinger \
-	libGLES_CM
+	libEGL \
+	libGLESv1_CM
 
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, corecg graphics)
diff --git a/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
index d18f59a..2b30336 100644
--- a/libs/surfaceflinger/BootAnimation.cpp
+++ b/libs/surfaceflinger/BootAnimation.cpp
@@ -39,7 +39,9 @@
 #include <core/SkBitmap.h>
 #include <images/SkImageDecoder.h>
 
-#include <GLES/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/eglext.h>
 
 #include "BootAnimation.h"
 
@@ -47,32 +49,28 @@
 
 // ---------------------------------------------------------------------------
 
-BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer)
-:   Thread(false)
-{
+BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
+    Thread(false) {
     mSession = SurfaceComposerClient::clientForConnection(
             composer->createConnection()->asBinder());
 }
 
-BootAnimation::~BootAnimation()
-{
+BootAnimation::~BootAnimation() {
 }
 
-void BootAnimation::onFirstRef()
-{
+void BootAnimation::onFirstRef() {
     run("BootAnimation", PRIORITY_DISPLAY);
 }
 
-const sp<SurfaceComposerClient>& BootAnimation::session() const 
-{
+const sp<SurfaceComposerClient>& BootAnimation::session() const {
     return mSession;
 }
 
-status_t BootAnimation::initTexture(
-        Texture* texture, AssetManager& assets, const char* name)
-{
+status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
+        const char* name) {
     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
-    if (!asset) return NO_INIT;
+    if (!asset)
+        return NO_INIT;
     SkBitmap bitmap;
     SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
             &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
@@ -84,32 +82,32 @@
     bitmap.lockPixels();
 
     const int w = bitmap.width();
-    const int h = bitmap.height();    
+    const int h = bitmap.height();
     const void* p = bitmap.getPixels();
-    
+
     GLint crop[4] = { 0, h, w, -h };
     texture->w = w;
     texture->h = h;
 
     glGenTextures(1, &texture->name);
     glBindTexture(GL_TEXTURE_2D, texture->name);
-    
-    switch(bitmap.getConfig()) {
+
+    switch (bitmap.getConfig()) {
         case SkBitmap::kA8_Config:
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0,
-                    GL_ALPHA, GL_UNSIGNED_BYTE, p);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
+                    GL_UNSIGNED_BYTE, p);
             break;
         case SkBitmap::kARGB_4444_Config:
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
-                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+                    GL_UNSIGNED_SHORT_4_4_4_4, p);
             break;
         case SkBitmap::kARGB_8888_Config:
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
-                    GL_RGBA, GL_UNSIGNED_BYTE, p);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+                    GL_UNSIGNED_BYTE, p);
             break;
         case SkBitmap::kRGB_565_Config:
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
-                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
+                    GL_UNSIGNED_SHORT_5_6_5, p);
             break;
         default:
             break;
@@ -123,8 +121,7 @@
     return NO_ERROR;
 }
 
-status_t BootAnimation::readyToRun()
-{
+status_t BootAnimation::readyToRun() {
     mAssets.addDefaultAssets();
 
     DisplayInfo dinfo;
@@ -133,32 +130,27 @@
         return -1;
 
     // create the native surface
-    sp<Surface> s = session()->createSurface(getpid(), 0, 
-            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
+    sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
+            PIXEL_FORMAT_RGB_565);
     session()->openTransaction();
     s->setLayer(0x40000000);
     session()->closeTransaction();
 
     // initialize opengl and egl
-    const EGLint attribs[] = {
-            EGL_RED_SIZE,       5,
-            EGL_GREEN_SIZE,     6,
-            EGL_BLUE_SIZE,      5,
-            EGL_DEPTH_SIZE,     0,
-            EGL_NONE
-    };
+    const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
+            EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
     EGLint w, h, dummy;
     EGLint numConfigs;
     EGLConfig config;
     EGLSurface surface;
     EGLContext context;
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(display, NULL, NULL);
     eglChooseConfig(display, attribs, &config, 1, &numConfigs);
 
-    surface = eglCreateWindowSurface(
-            display, config, new EGLNativeWindowSurface(s), NULL);
-    
+    mNativeWindowSurface = new EGLNativeWindowSurface(s);
+    surface = eglCreateWindowSurface(display, config, 
+            mNativeWindowSurface.get(), NULL);
+
     context = eglCreateContext(display, config, NULL, NULL);
     eglQuerySurface(display, surface, EGL_WIDTH, &w);
     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@@ -167,7 +159,7 @@
     mContext = context;
     mSurface = surface;
     mWidth = w;
-    mHeight= h;
+    mHeight = h;
     mFlingerSurface = s;
 
     // initialize GL
@@ -180,25 +172,21 @@
     return NO_ERROR;
 }
 
-void BootAnimation::requestExit()
-{
+void BootAnimation::requestExit() {
     mBarrier.open();
     Thread::requestExit();
 }
 
-bool BootAnimation::threadLoop()
-{
+bool BootAnimation::threadLoop() {
     bool r = android();
-    eglMakeCurrent(mDisplay, 0, 0, 0);
-    eglDestroyContext(mDisplay, mContext);    
+    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroyContext(mDisplay, mContext);
     eglDestroySurface(mDisplay, mSurface);
-    eglTerminate(mDisplay);
+    mNativeWindowSurface.clear();
     return r;
 }
 
-
-bool BootAnimation::android()
-{
+bool BootAnimation::android() {
     initTexture(&mAndroid[0], mAssets, "images/android_320x480.png");
     initTexture(&mAndroid[1], mAssets, "images/boot_robot.png");
     initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png");
@@ -219,9 +207,9 @@
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     const int steps = 8;
-    for (int i=1 ; i<steps ; i++) {
+    for (int i = 1; i < steps; i++) {
         float fade = i / float(steps);
-        glColor4f(1, 1, 1, fade*fade);
+        glColor4f(1, 1, 1, fade * fade);
         glClear(GL_COLOR_BUFFER_BIT);
         glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
         eglSwapBuffers(mDisplay, mSurface);
@@ -232,79 +220,73 @@
     glDisable(GL_BLEND);
     glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
     eglSwapBuffers(mDisplay, mSurface);
-    
-    
+
     // update rect for the robot
     const int x = mWidth - mAndroid[1].w - 33;
-    const int y = (mHeight - mAndroid[1].h)/2 - 1;
-    const Rect updateRect(x, y, x+mAndroid[1].w, y+mAndroid[1].h);
+    const int y = (mHeight - mAndroid[1].h) / 2 - 1;
+    const Rect updateRect(x, y, x + mAndroid[1].w, y + mAndroid[1].h);
 
     // draw and update only what we need
-    eglSwapRectangleANDROID(mDisplay, mSurface,
-            updateRect.left, updateRect.top, 
-            updateRect.width(), updateRect.height());
+    mNativeWindowSurface->setSwapRectangle(updateRect.left,
+            updateRect.top, updateRect.width(), updateRect.height());
 
     glEnable(GL_SCISSOR_TEST);
-    glScissor(updateRect.left, mHeight-updateRect.bottom,
-            updateRect.width(), updateRect.height()); 
+    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
+            updateRect.height());
 
     const nsecs_t startTime = systemTime();
-    do
-    {
+    do {
         // glow speed and shape
         nsecs_t time = systemTime() - startTime;
-        float t = ((4.0f/(360.0f*us2ns(16667))) * time);
+        float t = ((4.0f / (360.0f * us2ns(16667))) * time);
         t = t - floorf(t);
-        const float fade = 0.5f + 0.5f*sinf(t * 2*M_PI);
+        const float fade = 0.5f + 0.5f * sinf(t * 2 * M_PI);
 
         // fade the glow in and out
         glDisable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[2].name);
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
         glColor4f(fade, fade, fade, fade);
-        glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+        glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
                 updateRect.width(), updateRect.height());
 
         // draw the robot
         glEnable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+        glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
                 updateRect.width(), updateRect.height());
 
         // make sure sleep a lot to not take too much CPU away from 
         // the boot process. With this "glow" animation there is no
         // visible difference. 
-        usleep(16667*4);
+        usleep(16667 * 4);
 
         eglSwapBuffers(mDisplay, mSurface);
     } while (!exitPending());
-    
-    
+
     glDeleteTextures(1, &mAndroid[0].name);
     glDeleteTextures(1, &mAndroid[1].name);
     glDeleteTextures(1, &mAndroid[2].name);
     return false;
 }
 
-
-bool BootAnimation::cylon()
-{
+bool BootAnimation::cylon() {
     // initialize the textures...
-    initTexture(&mLeftTrail,  mAssets, "images/cylon_left.png");
+    initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
     initTexture(&mRightTrail, mAssets, "images/cylon_right.png");
     initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png");
 
     int w = mWidth;
     int h = mHeight;
 
-    const Point c(w/2 , h/2);
+    const Point c(w / 2, h / 2);
     const GLint amplitude = 60;
-    const int scx = c.x - amplitude - mBrightSpot.w/2;
-    const int scy = c.y - mBrightSpot.h/2;
-    const int scw = amplitude*2 + mBrightSpot.w;
+    const int scx = c.x - amplitude - mBrightSpot.w / 2;
+    const int scy = c.y - mBrightSpot.h / 2;
+    const int scw = amplitude * 2 + mBrightSpot.w;
     const int sch = mBrightSpot.h;
-    const Rect updateRect(scx, h-scy-sch, scx+scw, h-scy);
+    const Rect updateRect(scx, h - scy - sch, scx + scw, h - scy);
 
     // erase screen
     glDisable(GL_SCISSOR_TEST);
@@ -314,33 +296,29 @@
 
     glClear(GL_COLOR_BUFFER_BIT);
 
-    eglSwapRectangleANDROID(mDisplay, mSurface,
-            updateRect.left, updateRect.top, 
-            updateRect.width(), updateRect.height());
+    mNativeWindowSurface->setSwapRectangle(updateRect.left,
+            updateRect.top, updateRect.width(), updateRect.height());
 
     glEnable(GL_SCISSOR_TEST);
     glEnable(GL_BLEND);
     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 
-
     // clear the screen to white
     Point p;
     float t = 0;
     float alpha = 1.0f;
     const nsecs_t startTime = systemTime();
     nsecs_t fadeTime = 0;
-    
-    do
-    {
+
+    do {
         // Set scissor in interesting area
-        glScissor(scx, scy, scw, sch); 
+        glScissor(scx, scy, scw, sch);
 
         // erase screen
         glClear(GL_COLOR_BUFFER_BIT);
 
-
         // compute wave
-        const float a = (t * 2*M_PI) - M_PI/2;
+        const float a = (t * 2 * M_PI) - M_PI / 2;
         const float sn = sinf(a);
         const float cs = cosf(a);
         GLint x = GLint(amplitude * sn);
@@ -350,50 +328,50 @@
 
         if (derivative > 0) {
             // vanishing trail...
-            p.x = (-amplitude + c.x) - mBrightSpot.w/2;
-            p.y = c.y-mLeftTrail.h/2;
-            float fade = 2.0f*(0.5f-t);
+            p.x = (-amplitude + c.x) - mBrightSpot.w / 2;
+            p.y = c.y - mLeftTrail.h / 2;
+            float fade = 2.0f * (0.5f - t);
             //fade *= fade;
             glColor4f(fade, fade, fade, fade);
             glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
             glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
 
             // trail...
-            p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
-            p.y = c.y-mRightTrail.h/2;
-            fade = t<0.25f ? t*4.0f : 1.0f;
+            p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+            p.y = c.y - mRightTrail.h / 2;
+            fade = t < 0.25f ? t * 4.0f : 1.0f;
             fade *= fade;
             glColor4f(fade, fade, fade, fade);
             glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
             glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
-        } else { 
+        } else {
             // vanishing trail..
-            p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
-            p.y = c.y-mRightTrail.h/2;
-            float fade = 2.0f*(0.5f-(t-0.5f));
+            p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+            p.y = c.y - mRightTrail.h / 2;
+            float fade = 2.0f * (0.5f - (t - 0.5f));
             //fade *= fade;
             glColor4f(fade, fade, fade, fade);
             glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
             glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
 
             // trail...
-            p.x = (x + c.x) - mBrightSpot.w/2;
-            p.y = c.y-mLeftTrail.h/2;
-            fade = t<0.5f+0.25f ? (t-0.5f)*4.0f : 1.0f;
+            p.x = (x + c.x) - mBrightSpot.w / 2;
+            p.y = c.y - mLeftTrail.h / 2;
+            fade = t < 0.5f + 0.25f ? (t - 0.5f) * 4.0f : 1.0f;
             fade *= fade;
             glColor4f(fade, fade, fade, fade);
             glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
             glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
         }
 
-        const Point p( x + c.x-mBrightSpot.w/2, c.y-mBrightSpot.h/2 );
+        const Point p(x + c.x - mBrightSpot.w / 2, c.y - mBrightSpot.h / 2);
         glBindTexture(GL_TEXTURE_2D, mBrightSpot.name);
-        glColor4f(1,0.5,0.5,1);
+        glColor4f(1, 0.5, 0.5, 1);
         glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h);
 
         // update animation
         nsecs_t time = systemTime() - startTime;
-        t = ((4.0f/(360.0f*us2ns(16667))) * time);
+        t = ((4.0f / (360.0f * us2ns(16667))) * time);
         t = t - floorf(t);
 
         eglSwapBuffers(mDisplay, mSurface);
@@ -406,7 +384,7 @@
             alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1)));
 
             session()->openTransaction();
-            mFlingerSurface->setAlpha(alpha*alpha);
+            mFlingerSurface->setAlpha(alpha * alpha);
             session()->closeTransaction();
         }
     } while (alpha > 0);
@@ -421,4 +399,5 @@
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+}
+; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
index a4a6d49..b20cea0 100644
--- a/libs/surfaceflinger/BootAnimation.h
+++ b/libs/surfaceflinger/BootAnimation.h
@@ -26,7 +26,8 @@
 #include <ui/ISurfaceComposer.h>
 #include <ui/SurfaceComposerClient.h>
 
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
 
 #include "Barrier.h"
 
@@ -35,6 +36,7 @@
 namespace android {
 
 class AssetManager;
+class EGLNativeWindowSurface;
 
 // ---------------------------------------------------------------------------
 
@@ -74,6 +76,7 @@
     EGLDisplay  mContext;
     EGLDisplay  mSurface;
     sp<Surface> mFlingerSurface;
+    sp<EGLNativeWindowSurface> mNativeWindowSurface;
     Barrier mBarrier;
 };
 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 92588fa..f14d7e9 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -21,14 +21,16 @@
 #include <string.h>
 #include <math.h>
 
-#include <GLES/egl.h>
-
 #include <cutils/properties.h>
 
 #include <utils/Log.h>
 
 #include <ui/EGLDisplaySurface.h>
 
+#include <GLES/gl.h>
+#include <EGL/eglext.h>
+
+
 #include "DisplayHardware/DisplayHardware.h"
 
 #include <hardware/copybit.h>
@@ -136,26 +138,19 @@
     const char* const egl_extensions = eglQueryString(
             display, EGL_EXTENSIONS);
     
-    const char* egl_extensions_config = egl_extensions;
-    
-    if (strstr(egl_extensions, "EGL_ANDROID_query_string_config")) {
-        egl_extensions_config = eglQueryStringConfigANDROID(
-                display, config, EGL_EXTENSIONS);
-    }
-
     LOGI("EGL informations:");
     LOGI("# of configs : %d", numConfigs);
     LOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
     LOGI("version   : %s", eglQueryString(display, EGL_VERSION));
     LOGI("extensions: %s", egl_extensions);
-    LOGI("ext/config: %s", egl_extensions_config);
     LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
 
-    if (strstr(egl_extensions_config, "EGL_ANDROID_swap_rectangle")) {
-        mFlags |= SWAP_RECTANGLE_EXTENSION;
-        // TODO: get the real "update_on_demand" behavior
-        mFlags |= UPDATE_ON_DEMAND;
-    }
+    // TODO: get this from the devfb driver (probably should be HAL module)
+    mFlags |= SWAP_RECTANGLE_EXTENSION;
+    
+    // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
+    mFlags |= UPDATE_ON_DEMAND;
+
     if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
         if (dummy == EGL_SLOW_CONFIG)
             mFlags |= SLOW_CONFIG;
@@ -173,9 +168,6 @@
     if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
         if (dummy == EGL_BUFFER_PRESERVED) {
             mFlags |= BUFFER_PRESERVED;
-            if (strstr(egl_extensions_config, "EGL_ANDROID_copy_front_to_back")) {
-                mFlags |= COPY_BACK_EXTENSION;
-            }
         }
     }
     
@@ -330,8 +322,7 @@
 
     if (mFlags & SWAP_RECTANGLE_EXTENSION) {
         const Rect& b(newDirty.bounds());
-        eglSwapRectangleANDROID(
-                dpy, surface,
+        mDisplaySurface->setSwapRectangle(
                 b.left, b.top, b.width(), b.height());
     }
 
@@ -352,3 +343,11 @@
 {
     eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
 }
+
+void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
+    mDisplaySurface->copyFrontToImage(front);
+}
+
+void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
+    mDisplaySurface->copyBackToImage(front);
+}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index df97b60..550a4d1 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,7 +22,7 @@
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
 
-#include <GLES/egl.h>
+#include <EGL/egl.h>
 
 #include "DisplayHardware/DisplayHardwareBase.h"
 
@@ -39,7 +39,6 @@
 {
 public:
     enum {
-        COPY_BACK_EXTENSION     = 0x00000001,
         DIRECT_TEXTURE          = 0x00000002,
         SWAP_RECTANGLE_EXTENSION= 0x00000004,
         COPY_BITS_EXTENSION     = 0x00000008,
@@ -80,6 +79,9 @@
     copybit_device_t* getBlitEngine() const { return mBlitEngine; }
     overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
     
+    void copyFrontToImage(const copybit_image_t& front) const;
+    void copyBackToImage(const copybit_image_t& front) const;
+       
     Rect bounds() const {
         return Rect(mWidth, mHeight);
     }
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index bdefba3..0cf53f7 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -23,6 +23,11 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
 #include "clz.h"
 #include "LayerBase.h"
 #include "LayerBlur.h"
@@ -111,6 +116,12 @@
         mDrawingState.h = h;
     }
 }
+void LayerBase::forceVisibilityTransaction() {
+    // this can be called without SurfaceFlinger.mStateLock, but if we
+    // can atomically increment the sequence number, it doesn't matter.
+    android_atomic_inc(&mCurrentState.sequence);
+    requestTransaction();
+}
 bool LayerBase::requestTransaction() {
     int32_t old = setTransactionFlags(eTransactionNeeded);
     return ((old & eTransactionNeeded) == 0);
@@ -350,6 +361,10 @@
             return;
         }        
     }
+
+    // reset GL state
+    glEnable(GL_SCISSOR_TEST);
+
     onDraw(clip);
 
     /*
@@ -391,6 +406,7 @@
     Rect r;
     Region::iterator iterator(clip);
     if (iterator) {
+        glEnable(GL_SCISSOR_TEST);
         glVertexPointer(2, GL_FIXED, 0, mVertices);
         while (iterator.iterate(&r)) {
             const GLint sy = fbHeight - (r.top + r.height());
@@ -401,7 +417,7 @@
 }
 
 void LayerBase::drawWithOpenGL(const Region& clip,
-        GLint textureName, const GGLSurface& t) const
+        GLint textureName, const GGLSurface& t, int transform) const
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t fbHeight = hw.getHeight();
@@ -473,6 +489,12 @@
 
             glMatrixMode(GL_TEXTURE);
             glLoadIdentity();
+            
+            if (transform == HAL_TRANSFORM_ROT_90) {
+                glTranslatef(0, 1, 0);
+                glRotatef(-90, 0, 0, 1);
+            }
+
             if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
                 // find the smallest power-of-two that will accommodate our surface
                 GLuint tw = 1 << (31 - clz(t.width));
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 5e14dc8..a020f44 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -86,8 +86,8 @@
                 uint32_t        z;
                 uint8_t         alpha;
                 uint8_t         flags;
-                uint8_t         sequence;   // changes when visible regions can change
-                uint8_t         reserved;
+                uint8_t         reserved[2];
+                int32_t         sequence;   // changes when visible regions can change
                 uint32_t        tint;
                 Transform       transform;
                 Region          transparentRegion;
@@ -104,11 +104,11 @@
             
             void commitTransaction(bool skipSize);
             bool requestTransaction();
-
+            void forceVisibilityTransaction();
+            
             uint32_t getTransactionFlags(uint32_t flags);
             uint32_t setTransactionFlags(uint32_t flags);
             
-            void validateVisibility(const Transform& globalTransform);
             Rect visibleBounds() const;
             void drawRegion(const Region& reg) const;
 
@@ -162,7 +162,12 @@
      * the bitmap (as opposed to the size of the drawing state).
      */
     virtual Point getPhysicalSize() const;
-    
+
+    /**
+     * validateVisibility - cache a bunch of things
+     */
+    virtual void validateVisibility(const Transform& globalTransform);
+
     /**
      * lockPageFlip - called each time the screen is redrawn and returns whether
      * the visible regions need to be recomputed (this is a fairly heavy
@@ -188,10 +193,15 @@
      * needsBlending - true if this surface needs blending
      */
     virtual bool needsBlending() const  { return false; }
-    
+
     /**
-     * isSecure - true if this surface is secure, that is if it prevents a
-     * screenshot to be taken,
+     * transformed -- true is this surface needs a to be transformed
+     */
+    virtual bool transformed() const    { return mTransformed; }
+
+    /**
+     * isSecure - true if this surface is secure, that is if it prevents
+     * screenshots or vns servers.
      */
     virtual bool isSecure() const       { return false; }
 
@@ -210,7 +220,6 @@
     }
 
     int32_t  getOrientation() const { return mOrientation; }
-    bool transformed() const    { return mTransformed; }
     int  tx() const             { return mLeft; }
     int  ty() const             { return mTop; }
     
@@ -221,7 +230,9 @@
           GLuint createTexture() const;
     
           void drawWithOpenGL(const Region& clip,
-                  GLint textureName, const GGLSurface& surface) const;
+                  GLint textureName,
+                  const GGLSurface& surface,
+                  int transform = 0) const;
 
           void clearWithOpenGL(const Region& clip) const;
 
@@ -320,8 +331,7 @@
             *params = mParams;
         }
 
-        virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
-                PixelFormat format, const sp<IMemoryHeap>& heap) 
+        virtual status_t registerBuffers(const ISurface::BufferHeap& buffers) 
                 { return INVALID_OPERATION; }
         virtual void postBuffer(ssize_t offset) { }
         virtual void unregisterBuffers() { };
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 7c98857..e844350 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -69,18 +69,15 @@
         return NO_ERROR;
     }
 
+    PixelFormatInfo info;
+    getPixelFormatInfo(format, &info);
+
     uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
     const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
-    const uint32_t Bpp = bytesPerPixel(format);
+    const uint32_t Bpp = info.bytesPerPixel;
     uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
     stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
-    size_t size = stride * h * Bpp;
-    if (format == PIXEL_FORMAT_YCbCr_422_SP ||
-        format == PIXEL_FORMAT_YCbCr_420_SP) {
-        // in YUV planar, bitsPerPixel is for the Y plane
-        size = (size * bitsPerPixel(format)) / 8;
-    }
-
+    size_t size = info.getScanlineSize(stride) * h;
     if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
         size_t pagesize = getpagesize();
         size = (size + (pagesize-1)) & ~(pagesize-1);
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 4c2eb50..9ad64c4 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -70,9 +70,6 @@
     void getBitmapSurface(copybit_image_t* img) const;
 
 private:
-    LayerBitmap(const LayerBitmap& rhs);
-    LayerBitmap& operator = (const LayerBitmap& rhs);
-
     sp<MemoryDealer>        mAllocator;
     sp<IMemory>             mBitsMemory;
     uint32_t                mAllocFlags;
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index efadbcf..d3e456f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -23,6 +23,9 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
 #include "BlurFilter.h"
 #include "LayerBlur.h"
 #include "SurfaceFlinger.h"
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index c9cebf4..00fab70 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -25,6 +25,9 @@
 #include <utils/Log.h>
 #include <utils/StopWatch.h>
 
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
 #include <ui/PixelFormat.h>
 #include <ui/EGLDisplaySurface.h>
 
@@ -129,18 +132,24 @@
     }
 }
 
+bool LayerBuffer::transformed() const
+{
+    sp<Source> source(getSource());
+    if (LIKELY(source != 0))
+        return source->transformed();
+    return false;
+}
+
 /**
  * This creates a "buffer" source for this surface
  */
-status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
-        PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
+status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
 {
     Mutex::Autolock _l(mLock);
     if (mSource != 0)
         return INVALID_OPERATION;
 
-    sp<BufferSource> source = new BufferSource(*this, w, h,
-            hstride, vstride, format, memoryHeap);
+    sp<BufferSource> source = new BufferSource(*this, buffers);
 
     status_t result = source->getStatus();
     if (result == NO_ERROR) {
@@ -194,13 +203,39 @@
     mOwner = 0;
 }
 
-status_t LayerBuffer::SurfaceBuffer::registerBuffers(
-        int w, int h, int hs, int vs,
-        PixelFormat format, const sp<IMemoryHeap>& heap)
+status_t LayerBuffer::SurfaceBuffer::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case REGISTER_BUFFERS:
+        case UNREGISTER_BUFFERS:
+        case CREATE_OVERLAY:
+        {
+            // codes that require permission check
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int self_pid = getpid();
+            if (LIKELY(pid != self_pid)) {
+                // we're called from a different process, do the real check
+                if (!checkCallingPermission(
+                        String16("android.permission.ACCESS_SURFACE_FLINGER")))
+                {
+                    const int uid = ipc->getCallingUid();
+                    LOGE("Permission Denial: "
+                            "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+                    return PERMISSION_DENIED;
+                }
+            }
+        }
+    }
+    return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
 {
     LayerBuffer* owner(getOwner());
     if (owner)
-        return owner->registerBuffers(w, h, hs, vs, format, heap);
+        return owner->registerBuffers(buffers);
     return NO_INIT;
 }
 
@@ -237,23 +272,20 @@
 // LayerBuffer::Buffer
 // ============================================================================
 
-LayerBuffer::Buffer::Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
-        int w, int h, int hs, int vs, int f)
-: mHeap(heap)
+LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
+    : mBufferHeap(buffers)
 {
     NativeBuffer& src(mNativeBuffer);
     src.crop.l = 0;
     src.crop.t = 0;
-    src.crop.r = w;
-    src.crop.b = h;
-    src.img.w = hs ?: w;
-    src.img.h = vs ?: h;
-    src.img.format = f;
+    src.crop.r = buffers.w;
+    src.crop.b = buffers.h;
+    src.img.w = buffers.hor_stride ?: buffers.w;
+    src.img.h = buffers.ver_stride ?: buffers.h;
+    src.img.format = buffers.format;
     src.img.offset = offset;
-    src.img.base   = heap->base();
-    src.img.fd     = heap->heapID();
-    // FIXME: make sure this buffer lies within the heap, in which case, set
-    // mHeap to null
+    src.img.base   = buffers.heap->base();
+    src.img.fd     = buffers.heap->heapID();
 }
 
 LayerBuffer::Buffer::~Buffer()
@@ -283,41 +315,55 @@
 }
 void LayerBuffer::Source::unregisterBuffers() {
 }
+bool LayerBuffer::Source::transformed() const {
+    return mLayer.mTransformed; 
+}
 
 // ---------------------------------------------------------------------------
 
 LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
-        int w, int h, int hstride, int vstride,
-        PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
-    : Source(layer), mStatus(NO_ERROR), mTextureName(-1U)
+        const ISurface::BufferHeap& buffers)
+    : Source(layer), mStatus(NO_ERROR), 
+      mBufferSize(0), mTextureName(-1U)
 {
-    if (memoryHeap == NULL) {
+    if (buffers.heap == NULL) {
         // this is allowed, but in this case, it is illegal to receive
         // postBuffer(). The surface just erases the framebuffer with
         // fully transparent pixels.
-        mHeap.clear();
-        mWidth = w;
-        mHeight = h;
+        mBufferHeap = buffers;
         mLayer.setNeedsBlending(false);
         return;
     }
 
-    status_t err = (memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+    status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
     if (err != NO_ERROR) {
+        LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
+        mStatus = err;
+        return;
+    }
+    
+    PixelFormatInfo info;
+    err = getPixelFormatInfo(buffers.format, &info);
+    if (err != NO_ERROR) {
+        LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
+                buffers.format, strerror(err));
         mStatus = err;
         return;
     }
 
-    // TODO: validate format/parameters
-    mHeap = memoryHeap;
-    mWidth = w;
-    mHeight = h;
-    mHStride = hstride;
-    mVStride = vstride;
-    mFormat = format;
-    PixelFormatInfo info;
-    getPixelFormatInfo(format, &info);
-    mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
+    if (buffers.hor_stride<0 || buffers.ver_stride<0) {
+        LOGE("LayerBuffer::BufferSource: invalid parameters "
+             "(w=%d, h=%d, xs=%d, ys=%d)", 
+             buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
+        mStatus = BAD_VALUE;
+        return;
+    }
+
+    mBufferHeap = buffers;
+    mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
+    mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
+    mLayer.forceVisibilityTransaction();
+    
 }
 
 LayerBuffer::BufferSource::~BufferSource()
@@ -329,21 +375,24 @@
 
 void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
 {    
-    sp<IMemoryHeap> heap;
-    int w, h, hs, vs, f;
+    ISurface::BufferHeap buffers;
     { // scope for the lock
         Mutex::Autolock _l(mLock);
-        w = mWidth;
-        h = mHeight;
-        hs= mHStride;
-        vs= mVStride;
-        f = mFormat;
-        heap = mHeap;
+        buffers = mBufferHeap;
+        if (buffers.heap != 0) {
+            const size_t memorySize = buffers.heap->getSize();
+            if ((size_t(offset) + mBufferSize) > memorySize) {
+                LOGE("LayerBuffer::BufferSource::postBuffer() "
+                     "invalid buffer (offset=%d, size=%d, heap-size=%d",
+                     int(offset), int(mBufferSize), int(memorySize));
+                return;
+            }
+        }
     }
 
     sp<Buffer> buffer;
-    if (heap != 0) {
-        buffer = new LayerBuffer::Buffer(heap, offset, w, h, hs, vs, f);
+    if (buffers.heap != 0) {
+        buffer = new LayerBuffer::Buffer(buffers, offset);
         if (buffer->getStatus() != NO_ERROR)
             buffer.clear();
         setBuffer(buffer);
@@ -354,7 +403,7 @@
 void LayerBuffer::BufferSource::unregisterBuffers()
 {
     Mutex::Autolock _l(mLock);
-    mHeap.clear();
+    mBufferHeap.heap.clear();
     mBuffer.clear();
     mLayer.invalidate();
 }
@@ -371,6 +420,11 @@
     mBuffer = buffer;
 }
 
+bool LayerBuffer::BufferSource::transformed() const
+{
+    return mBufferHeap.transform ? true : Source::transformed(); 
+}
+
 void LayerBuffer::BufferSource::onDraw(const Region& clip) const 
 {
     sp<Buffer> buffer(getBuffer());
@@ -417,7 +471,7 @@
             if (UNLIKELY(mTemporaryDealer == 0)) {
                 // allocate a memory-dealer for this the first time
                 mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
-                ->createHeap(ISurfaceComposer::eHardware);
+                    ->createHeap(ISurfaceComposer::eHardware);
                 mTempBitmap.init(mTemporaryDealer);
             }
 
@@ -447,16 +501,31 @@
         copybit_image_t dst;
         hw.getDisplaySurface(&dst);
         const copybit_rect_t& drect
-        = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+            = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
         const State& s(mLayer.drawingState());
         region_iterator it(clip);
-        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, mLayer.getOrientation());
+        
+        // pick the right orientation for this buffer
+        int orientation = mLayer.getOrientation();
+        if (UNLIKELY(mBufferHeap.transform)) {
+            Transform rot90;
+            GraphicPlane::orientationToTransfrom(
+                    ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+            const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+            const Layer::State& s(mLayer.drawingState());
+            Transform tr(planeTransform * s.transform * rot90);
+            orientation = tr.getOrientation();
+        }
+        
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
         copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
-        copybit->set_parameter(copybit, COPYBIT_DITHER,
-                s.flags & ISurfaceComposer::eLayerDither ?
-                        COPYBIT_ENABLE : COPYBIT_DISABLE);
+        copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
         err = copybit->stretch(copybit,
                 &dst, &src.img, &drect, &src.crop, &it);
+        if (err != NO_ERROR) {
+            LOGE("copybit failed (%s)", strerror(err));
+        }
     }
 
     if (!can_use_copybit || err) {
@@ -475,10 +544,11 @@
         t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
         const Region dirty(Rect(t.width, t.height));
         mLayer.loadTexture(dirty, mTextureName, t, w, h);
-        mLayer.drawWithOpenGL(clip, mTextureName, t);
+        mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
     }
 }
 
+
 // ---------------------------------------------------------------------------
 
 LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 6e3d49f..2dc77f1 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -22,7 +22,7 @@
 
 #include <utils/IMemory.h>
 #include <private/ui/LayerState.h>
-#include <GLES/eglnatives.h>
+#include <EGL/eglnatives.h>
 
 #include "LayerBase.h"
 #include "LayerBitmap.h"
@@ -46,6 +46,7 @@
         virtual void onVisibilityResolved(const Transform& planeTransform);
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
+        virtual bool transformed() const;
     protected:
         LayerBuffer& mLayer;
     };
@@ -67,9 +68,9 @@
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t flags);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+    virtual bool transformed() const;
 
-    status_t registerBuffers(int w, int h, int hstride, int vstride,
-            PixelFormat format, const sp<IMemoryHeap>& heap);
+    status_t registerBuffers(const ISurface::BufferHeap& buffers);
     void postBuffer(ssize_t offset);
     void unregisterBuffers();
     sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format);
@@ -89,10 +90,9 @@
 
     class Buffer : public LightRefBase<Buffer> {
     public:
-        Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
-                int w, int h, int hs, int vs, int f);
+        Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
         inline status_t getStatus() const {
-            return mHeap!=0 ? NO_ERROR : NO_INIT;
+            return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
         }
         inline const NativeBuffer& getBuffer() const {
             return mNativeBuffer;
@@ -103,15 +103,13 @@
         Buffer(const Buffer& rhs);
         ~Buffer();
     private:
-        sp<IMemoryHeap>    mHeap;
-        NativeBuffer       mNativeBuffer;
+        ISurface::BufferHeap    mBufferHeap;
+        NativeBuffer            mNativeBuffer;
     };
 
     class BufferSource : public Source {
     public:
-        BufferSource(LayerBuffer& layer,
-                int w, int h, int hstride, int vstride,
-                PixelFormat format, const sp<IMemoryHeap>& heap);
+        BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers);
         virtual ~BufferSource();
 
         status_t getStatus() const { return mStatus; }
@@ -121,16 +119,13 @@
         virtual void onDraw(const Region& clip) const;
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
+        virtual bool transformed() const;
     private:
         mutable Mutex   mLock;
-        sp<IMemoryHeap> mHeap;
         sp<Buffer>      mBuffer;
         status_t        mStatus;
-        int             mWidth;
-        int             mHeight;
-        int             mHStride;
-        int             mVStride;
-        int             mFormat;
+        ISurface::BufferHeap mBufferHeap;
+        size_t          mBufferSize;
         mutable sp<MemoryDealer> mTemporaryDealer;
         mutable LayerBitmap mTempBitmap;
         mutable GLuint  mTextureName;
@@ -186,8 +181,9 @@
     public:
                 SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
         virtual ~SurfaceBuffer();
-        virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
-                PixelFormat format, const sp<IMemoryHeap>& heap);
+        virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+        virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
         virtual sp<OverlayRef> createOverlay(
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..2b72d7c
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+        SurfaceFlinger* flinger, DisplayID display, 
+        OrientationAnimation* anim, 
+        const LayerBitmap& bitmap,
+        const LayerBitmap& bitmapIn)
+    : LayerBase(flinger, display), mAnim(anim), 
+      mBitmap(bitmap), mBitmapIn(bitmapIn), 
+      mTextureName(-1), mTextureNameIn(-1)
+{
+    mStartTime = systemTime();
+    mFinishTime = 0;
+    mOrientationCompleted = false;
+    mFirstRedraw = false;
+    mLastNormalizedTime = 0;
+    mLastScale = 0;
+    mNeedsBlending = false;
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+    if (mTextureName != -1U) {
+        LayerBase::deletedTextures.add(mTextureName);
+    }
+    if (mTextureNameIn != -1U) {
+        LayerBase::deletedTextures.add(mTextureNameIn);
+    }
+}
+
+bool LayerOrientationAnim::needsBlending() const 
+{
+    return mNeedsBlending; 
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+    const GraphicPlane& plane(graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+    const Layer::State& s(drawingState());
+    const Transform tr(s.transform);
+    const Point size(getPhysicalSize());
+    uint32_t w = size.x;
+    uint32_t h = size.y;
+    mTransformedBounds = tr.makeBounds(w, h);
+    mLeft = tr.tx();
+    mTop  = tr.ty();
+    transparentRegionScreen.clear();
+    mTransformed = true;
+    mCanUseCopyBit = false;
+    copybit_device_t* copybit = mFlinger->getBlitEngine();
+    if (copybit) { 
+        mCanUseCopyBit = true;
+    }
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+    mFinishTime = systemTime();
+    mOrientationCompleted = true;
+    mFirstRedraw = true;
+    mNeedsBlending = true;
+    mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+    // Animation...
+    const float MIN_SCALE = 0.5f;
+    const float DURATION = ms2ns(200);
+    const float BOUNCES_PER_SECOND = 1.618f;
+    const float BOUNCES_AMPLITUDE = 1.0f/32.0f;
+
+    const nsecs_t now = systemTime();
+    float scale, alpha;
+    
+    if (mOrientationCompleted) {
+        if (mFirstRedraw) {
+            mFirstRedraw = false;
+            
+            // make a copy of what's on screen
+            copybit_image_t image;
+            mBitmapIn.getBitmapSurface(&image);
+            const DisplayHardware& hw(graphicPlane(0).displayHardware());
+            hw.copyBackToImage(image);
+
+            // and erase the screen for this round
+            glDisable(GL_BLEND);
+            glDisable(GL_DITHER);
+            glDisable(GL_SCISSOR_TEST);
+            glClearColor(0,0,0,0);
+            glClear(GL_COLOR_BUFFER_BIT);
+            
+            // FIXME: code below is gross
+            mNeedsBlending = false;
+            LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+            mFlinger->invalidateLayerVisibility(self);
+        }
+
+        // make sure pick-up where we left off
+        const float duration = DURATION * mLastNormalizedTime;
+        const float normalizedTime = (float(now - mFinishTime) / duration);
+        if (normalizedTime <= 1.0f) {
+            const float squaredTime = normalizedTime*normalizedTime;
+            scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+            alpha = (1.0f - normalizedTime);
+            alpha *= alpha;
+            alpha *= alpha;
+        } else {
+            mAnim->onAnimationFinished();
+            scale = 1.0f;
+            alpha = 0.0f;
+        }
+    } else {
+        const float normalizedTime = float(now - mStartTime) / DURATION;
+        if (normalizedTime <= 1.0f) {
+            mLastNormalizedTime = normalizedTime;
+            const float squaredTime = normalizedTime*normalizedTime;
+            scale = (MIN_SCALE-1.0f)*squaredTime + 1.0f;
+            alpha = 1.0f;
+        } else {
+            mLastNormalizedTime = 1.0f;
+            const float to_seconds = DURATION / seconds(1);
+            const float phi = BOUNCES_PER_SECOND * 
+                    (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+            scale = MIN_SCALE + BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+            alpha = 1.0f;
+        }
+        mLastScale = scale;
+    }
+    drawScaled(scale, alpha);
+}
+
+void LayerOrientationAnim::drawScaled(float f, float alpha) const
+{
+    copybit_image_t dst;
+    const GraphicPlane& plane(graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    hw.getDisplaySurface(&dst);
+
+    // clear screen
+    // TODO: with update on demand, we may be able 
+    // to not erase the screen at all during the animation 
+    if (!mOrientationCompleted) {
+        glDisable(GL_BLEND);
+        glDisable(GL_DITHER);
+        glDisable(GL_SCISSOR_TEST);
+        glClearColor(0,0,0,0);
+        glClear(GL_COLOR_BUFFER_BIT);
+    }
+    
+    const int w = dst.w*f; 
+    const int h = dst.h*f; 
+    const int xc = uint32_t(dst.w-w)/2;
+    const int yc = uint32_t(dst.h-h)/2;
+    const copybit_rect_t drect = { xc, yc, xc+w, yc+h }; 
+
+    copybit_image_t src;
+    mBitmap.getBitmapSurface(&src);
+    const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+    int err = NO_ERROR;
+    const int can_use_copybit = canUseCopybit();
+    if (can_use_copybit)  {
+        copybit_device_t* copybit = mFlinger->getBlitEngine();
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+        copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+        if (alpha < 1.0f) {
+            copybit_image_t srcIn;
+            mBitmapIn.getBitmapSurface(&srcIn);
+            region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            err = copybit->stretch(copybit, &dst, &srcIn, &drect, &srect, &it);
+        }
+
+        if (!err && alpha > 0.0f) {
+            region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alpha*255));
+            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+        }
+        LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
+    }
+    if (!can_use_copybit || err) {   
+        GGLSurface t;
+        t.version = sizeof(GGLSurface);
+        t.width  = src.w;
+        t.height = src.h;
+        t.stride = src.w;
+        t.vstride= src.h;
+        t.format = src.format;
+        t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+        Transform tr;
+        tr.set(f,0,0,f);
+        tr.set(xc, yc);
+        
+        // FIXME: we should not access mVertices and mDrawingState like that,
+        // but since we control the animation, we know it's going to work okay.
+        // eventually we'd need a more formal way of doing things like this.
+        LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+        tr.transform(self.mVertices[0], 0, 0);
+        tr.transform(self.mVertices[1], 0, src.h);
+        tr.transform(self.mVertices[2], src.w, src.h);
+        tr.transform(self.mVertices[3], src.w, 0);
+        if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+            // Too slow to do this in software
+            self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+        }
+
+        if (alpha < 1.0f) {
+            copybit_image_t src;
+            mBitmapIn.getBitmapSurface(&src);
+            t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+            if (UNLIKELY(mTextureNameIn == -1LU)) {
+                mTextureNameIn = createTexture();
+                GLuint w=0, h=0;
+                const Region dirty(Rect(t.width, t.height));
+                loadTexture(dirty, mTextureNameIn, t, w, h);
+            }
+            self.mDrawingState.alpha = 255;
+            const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+            drawWithOpenGL(clip, mTextureName, t);
+        }
+
+        t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+        if (UNLIKELY(mTextureName == -1LU)) {
+            mTextureName = createTexture();
+            GLuint w=0, h=0;
+            const Region dirty(Rect(t.width, t.height));
+            loadTexture(dirty, mTextureName, t, w, h);
+        }
+        self.mDrawingState.alpha = int(alpha*255);
+        const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+        drawWithOpenGL(clip, mTextureName, t);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
new file mode 100644
index 0000000..7367685
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <utils/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnim : public LayerBase
+{
+public:    
+    static const uint32_t typeInfo;
+    static const char* const typeID;
+    virtual char const* getTypeID() const { return typeID; }
+    virtual uint32_t getTypeInfo() const { return typeInfo; }
+    
+                LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+                        OrientationAnimation* anim, 
+                        const LayerBitmap& zoomOut,
+                        const LayerBitmap& zoomIn);
+        virtual ~LayerOrientationAnim();
+
+            void onOrientationCompleted();
+
+    virtual void onDraw(const Region& clip) const;
+    virtual Point getPhysicalSize() const;
+    virtual void validateVisibility(const Transform& globalTransform);
+    virtual bool needsBlending() const;
+    virtual bool isSecure() const       { return false; }
+private:
+    void drawScaled(float scale, float alpha) const;
+
+    OrientationAnimation* mAnim;
+    LayerBitmap mBitmap;
+    LayerBitmap mBitmapIn;
+    nsecs_t mStartTime;
+    nsecs_t mFinishTime;
+    bool mOrientationCompleted;
+    mutable bool mFirstRedraw;
+    mutable float mLastNormalizedTime;
+    mutable float mLastScale;
+    mutable GLuint  mTextureName;
+    mutable GLuint  mTextureNameIn;
+    mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/LayerScreenshot.h b/libs/surfaceflinger/LayerScreenshot.h
deleted file mode 100644
index 2d9a8ec..0000000
--- a/libs/surfaceflinger/LayerScreenshot.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LAYER_SCREENSHOT_H
-#define ANDROID_LAYER_SCREENSHOT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Parcel.h>
-
-#include "LayerBase.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class LayerScreenshot : public LayerBase
-{
-public:    
-    static const uint32_t typeInfo;
-    static const char* const typeID;
-    virtual char const* getTypeID() const { return typeID; }
-    virtual uint32_t getTypeInfo() const { return typeInfo; }
-    
-                LayerScreenshot(SurfaceFlinger* flinger, DisplayID display);
-        virtual ~LayerScreenshot();
-
-    virtual void onDraw(const Region& clip) const;
-    virtual bool needsBlending() const  { return true; }
-    virtual bool isSecure() const       { return false; }
-
-    void takeScreenshot(Mutex& lock, Parcel* reply);
-    
-private:
-    mutable Condition   mCV;
-    Parcel*             mReply;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_SCREENSHOT_H
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
new file mode 100644
index 0000000..f6f1326
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+    : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+    // allocate a memory-dealer for this the first time
+    mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
+            ISurfaceComposer::eHardware);
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged()
+{
+    if (mState == DONE)
+        mState = PREPARE;
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+    if (mState != DONE)
+        mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+    bool skip_frame;
+    switch (mState) {
+        default:
+        case DONE:
+            skip_frame = done();
+            break;
+        case PREPARE:
+            skip_frame = prepare();
+            break;
+        case PHASE1:
+            skip_frame = phase1();
+            break;
+        case PHASE2:
+            skip_frame = phase2();
+            break;
+        case FINISH:
+            skip_frame = finished();
+            break;
+    }
+    return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+    if (mFlinger->isFrozen()) {
+        // we are not allowed to draw, but pause a bit to make sure
+        // apps don't end up using the whole CPU, if they depend on
+        // surfaceflinger for synchronization.
+        usleep(8333); // 8.3ms ~ 120fps
+        return true;
+    }
+    return false;
+}
+
+bool OrientationAnimation::prepare()
+{
+    mState = PHASE1;
+    
+    const GraphicPlane& plane(mFlinger->graphicPlane(0));
+    const DisplayHardware& hw(plane.displayHardware());
+    const uint32_t w = hw.getWidth();
+    const uint32_t h = hw.getHeight();
+
+    LayerBitmap bitmap;
+    bitmap.init(mTemporaryDealer);
+    bitmap.setBits(w, h, 1, hw.getFormat());
+
+    LayerBitmap bitmapIn;
+    bitmapIn.init(mTemporaryDealer);
+    bitmapIn.setBits(w, h, 1, hw.getFormat());
+
+    copybit_image_t front;
+    bitmap.getBitmapSurface(&front);
+    hw.copyFrontToImage(front);
+
+    LayerOrientationAnim* l = new LayerOrientationAnim(
+            mFlinger.get(), 0, this, bitmap, bitmapIn);
+    l->initStates(w, h, 0);
+    l->setLayer(INT_MAX-1);
+    mFlinger->addLayer(l);
+    mLayerOrientationAnim = l;
+    return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+    if (mFlinger->isFrozen() == false) {
+        // start phase 2
+        mState = PHASE2;
+        mLayerOrientationAnim->onOrientationCompleted();
+        mLayerOrientationAnim->invalidate();
+        return true;
+        
+    }
+    mLayerOrientationAnim->invalidate();
+    return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+    // do the 2nd phase of the animation
+    mLayerOrientationAnim->invalidate();
+    return false;
+}
+
+bool OrientationAnimation::finished()
+{
+    mState = DONE;
+    mFlinger->removeLayer(mLayerOrientationAnim);
+    mLayerOrientationAnim = NULL;
+    return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
new file mode 100644
index 0000000..ba33fce
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:    
+                 OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+        virtual ~OrientationAnimation();
+
+   void onOrientationChanged();
+   void onAnimationFinished();
+   inline bool run() {
+       if (LIKELY(mState == DONE))
+           return false;
+       return run_impl();
+   }
+
+private:
+    enum {
+        DONE = 0,
+        PREPARE,
+        PHASE1,
+        PHASE2,
+        FINISH
+    };
+
+    bool run_impl();
+    bool done();
+    bool prepare();
+    bool phase1();
+    bool phase2();
+    bool finished();
+
+    sp<SurfaceFlinger> mFlinger;
+    sp<MemoryDealer> mTemporaryDealer;
+    LayerOrientationAnim* mLayerOrientationAnim;
+    int mState;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp
deleted file mode 100644
index c2c1989..0000000
--- a/libs/surfaceflinger/RFBServer.cpp
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "RFBServer"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <netinet/in.h>
-
-#include <cutils/sockets.h>
-
-#include <utils/Log.h>
-#include <ui/Rect.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <linux/input.h>
-#endif
-
-#include "RFBServer.h"
-#include "SurfaceFlinger.h"
-
-/* BUG=773511: this is a temporary hack required while developing the new
-   set of "clean kernel headers" for the Bionic C library. */
-#ifndef KEY_STAR
-#define KEY_STAR    227
-#endif
-#ifndef KEY_SHARP
-#define KEY_SHARP   228
-#endif
-#ifndef KEY_SOFT1
-#define KEY_SOFT1   229
-#endif
-#ifndef KEY_SOFT2
-#define KEY_SOFT2   230
-#endif
-#ifndef KEY_CENTER
-#define KEY_CENTER  232
-#endif
-
-// ----------------------------------------------------------------------------
-
-#define DEBUG_MSG   0
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-const int VNC_PORT = 5900;
-
-RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format)
-    : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0)
-{
-    mFrameBuffer.version = sizeof(mFrameBuffer);
-    mFrameBuffer.width = w;
-    mFrameBuffer.height = h;
-    mFrameBuffer.stride = w;
-    mFrameBuffer.format = format;
-    mFrameBuffer.data = 0;
-}
-
-RFBServer::~RFBServer()
-{
-    if (mRobinThread != 0) {
-        // ask the thread to exit first
-        mRobinThread->exitAndWait();
-    }
-
-    free(mFrameBuffer.data);
-
-    delete [] mIoVec;
-}
-
-void RFBServer::onFirstRef()
-{
-    run("Batman");
-}
-
-status_t RFBServer::readyToRun()
-{
-    LOGI("RFB server ready to run");
-    return NO_ERROR;
-}
-
-bool RFBServer::threadLoop()
-{
-    struct sockaddr addr;
-    socklen_t alen;
-    int serverfd = -1;
-    int port = VNC_PORT;
-
-    do {
-        retry:
-        if (serverfd < 0) {
-            serverfd = socket_loopback_server(port, SOCK_STREAM);
-            if (serverfd < 0) {
-                if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) {
-                    LOGW("port %d already in use, trying %d", port, port+1);
-                    port++;
-                    goto retry;
-                }
-                LOGE("couldn't create socket, port=%d, error %d (%s)",
-                        port, errno, strerror(errno));
-                sleep(1);
-                break;
-            }
-            fcntl(serverfd, F_SETFD, FD_CLOEXEC);
-        }
-
-        alen = sizeof(addr);
-        mFD = accept(serverfd, &addr, &alen);
-
-        if (mFD < 0) {
-            LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno));
-            // we could have run out of file descriptors, wait a bit and
-            // try again.
-            sleep(1);
-            goto retry;
-        }
-        fcntl(mFD, F_SETFD, FD_CLOEXEC);
-
-        // send protocol version and Authentication method
-        mStatus = NO_ERROR;
-        handshake(3, 3, Authentication::None);
-
-        if (alive()) {
-            // create the thread we use to send data to the client
-            mRobinThread = new ServerThread(this);
-        }
-
-        while( alive() ) {
-            // client message must be destroyed at each iteration
-            // (most of the time this is a no-op)
-            ClientMessage msg;
-            waitForClientMessage(msg);
-            if (alive()) {
-                handleClientMessage(msg);
-            }
-        }
-
-    } while( alive() );
-
-    // free-up some resources
-    if (mRobinThread != 0) {
-        mRobinThread->exitAndWait();
-        mRobinThread.clear();
-    }
-
-    free(mFrameBuffer.data);
-    mFrameBuffer.data = 0;
-
-    close(mFD);
-    close(serverfd);
-    mFD = -1;
-
-    // we'll try again
-    return true;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver)
-            : Thread(false), mReceiver(receiver)
-{
-    LOGD("RFB Server Thread created");
-}
-
-RFBServer::ServerThread::~ServerThread()
-{
-    LOGD("RFB Server Thread destroyed");
-}
-
-void RFBServer::ServerThread::onFirstRef()
-{
-    mUpdateBarrier.close();
-    run("Robin");
-}
-
-status_t RFBServer::ServerThread::readyToRun()
-{
-    return NO_ERROR;
-}
-
-void RFBServer::ServerThread::wake()
-{
-    mUpdateBarrier.open();
-}
-
-void RFBServer::ServerThread::exitAndWait()
-{
-    requestExit();
-    mUpdateBarrier.open();
-    requestExitAndWait();
-}
-
-bool RFBServer::ServerThread::threadLoop()
-{
-    sp<RFBServer> receiver(mReceiver.promote());
-    if (receiver == 0)
-        return false;
-
-    // wait for something to do
-    mUpdateBarrier.wait();
-
-    // we're asked to quit, abort everything
-    if (exitPending())
-        return false;
-
-    mUpdateBarrier.close();
-
-    // process updates
-    receiver->sendFrameBufferUpdates();
-    return !exitPending();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth)
-{
-    ProtocolVersion protocolVersion(major, minor);
-    if( !write(protocolVersion) )
-        return;
-
-    if ( !read(protocolVersion) )
-        return;
-
-    int maj, min;
-    if ( protocolVersion.decode(maj, min) != NO_ERROR ) {
-        mStatus = -1;
-        return;
-    }
-
-#if DEBUG_MSG
-    LOGD("client protocol string: <%s>", (char*)protocolVersion.payload());
-    LOGD("client wants protocol version %d.%d\n", maj, min);
-#endif
-
-    Authentication authentication(auth);
-    if( !write(authentication) )
-        return;
-
-    ClientInitialization clientInit;
-    if ( !read(clientInit) )
-        return;
-
-#if DEBUG_MSG
-    LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags());
-#endif
-
-    ServerInitialization serverInit("Android RFB");
-    ServerInitialization::Payload& message(serverInit.message());
-        message.framebufferWidth = htons(mFrameBuffer.width);
-        message.framebufferHeight = htons(mFrameBuffer.height);
-        message.serverPixelFormat.bitsPerPixel = 16;
-        message.serverPixelFormat.depth = 16;
-        message.serverPixelFormat.bigEndianFlag = 0;
-        message.serverPixelFormat.trueColorFlag = 1;
-        message.serverPixelFormat.redMax   = htons((1<<5)-1);
-        message.serverPixelFormat.greenMax = htons((1<<6)-1);
-        message.serverPixelFormat.blueMax  = htons((1<<5)-1);
-        message.serverPixelFormat.redShift     = 11;
-        message.serverPixelFormat.greenShift   = 5;
-        message.serverPixelFormat.blueShift    = 0;
-
-    mIoVec = new iovec[mFrameBuffer.height];
-
-    write(serverInit);
-}
-
-void RFBServer::handleClientMessage(const ClientMessage& msg)
-{
-    switch(msg.type()) {
-    case SET_PIXEL_FORMAT:
-        handleSetPixelFormat(msg.messages().setPixelFormat);
-        break;
-    case SET_ENCODINGS:
-        handleSetEncodings(msg.messages().setEncodings);
-        break;
-    case FRAME_BUFFER_UPDATE_REQ:
-        handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest);
-        break;
-    case KEY_EVENT:
-        handleKeyEvent(msg.messages().keyEvent);
-        break;
-    }
-}
-
-void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg)
-{
-    if (!validatePixelFormat(msg.pixelFormat)) {
-        LOGE("The builtin VNC server only supports the RGB 565 pixel format");
-        LOGD("requested pixel format:");
-        LOGD("bitsPerPixel:     %d", msg.pixelFormat.bitsPerPixel);
-        LOGD("depth:            %d", msg.pixelFormat.depth);
-        LOGD("bigEndianFlag:    %d", msg.pixelFormat.bigEndianFlag);
-        LOGD("trueColorFlag:    %d", msg.pixelFormat.trueColorFlag);
-        LOGD("redmax:           %d", ntohs(msg.pixelFormat.redMax));
-        LOGD("bluemax:          %d", ntohs(msg.pixelFormat.greenMax));
-        LOGD("greenmax:         %d", ntohs(msg.pixelFormat.blueMax));
-        LOGD("redshift:         %d", msg.pixelFormat.redShift);
-        LOGD("greenshift:       %d", msg.pixelFormat.greenShift);
-        LOGD("blueshift:        %d", msg.pixelFormat.blueShift);
-        mStatus = -1;
-    }
-}
-
-bool RFBServer::validatePixelFormat(const PixelFormat& pf)
-{
-    if ((pf.bitsPerPixel != 16) || (pf.depth != 16))
-        return false;
-
-    if (pf.bigEndianFlag || !pf.trueColorFlag)
-        return false;
-
-    if (ntohs(pf.redMax)!=0x1F ||
-        ntohs(pf.greenMax)!=0x3F ||
-        ntohs(pf.blueMax)!=0x1F) {
-        return false;
-    }
-
-    if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0)
-        return false;
-
-    return true;
-}
-
-void RFBServer::handleSetEncodings(const SetEncodings& msg)
-{
-    /* From the RFB specification:
-        Sets the encoding types in which pixel data can be sent by the server.
-        The order of the encoding types given in this message is a hint by the
-        client as to its preference (the first encoding specified being most
-        preferred). The server may or may not choose to make use of this hint.
-        Pixel data may always be sent in raw encoding even if not specified
-        explicitly here.
-    */
-
-    LOGW("SetEncodings received. Only RAW is supported.");
-}
-
-void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg)
-{
-#if DEBUG_MSG
-    LOGD("handle FrameBufferUpdateRequest");
-#endif
-
-    Rect r;
-    r.left = ntohs(msg.x);
-    r.top = ntohs(msg.y);
-    r.right = r.left + ntohs(msg.width);
-    r.bottom = r.top + ntohs(msg.height);
-
-    Mutex::Autolock _l(mRegionLock);
-    mClientRegionRequest.set(r);
-    if (!msg.incremental)
-        mDirtyRegion.orSelf(r);
-
-    mRobinThread->wake();
-}
-
-void RFBServer::handleKeyEvent(const KeyEvent& msg)
-{
-#ifdef HAVE_ANDROID_OS
-
-    int scancode = 0;
-    int code = ntohl(msg.key);
-
-    if (code>='0' && code<='9') {
-        scancode = (code & 0xF) - 1;
-        if (scancode<0) scancode += 10;
-        scancode += KEY_1;
-    } else if (code>=0xFF50 && code<=0xFF58) {
-        static const uint16_t map[] =
-             {  KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
-                KEY_SOFT1, KEY_SOFT2, KEY_END, 0 };
-        scancode = map[code & 0xF];
-    } else if (code>=0xFFE1 && code<=0xFFEE) {
-        static const uint16_t map[] =
-             {  KEY_LEFTSHIFT, KEY_LEFTSHIFT,
-                KEY_COMPOSE, KEY_COMPOSE,
-                KEY_LEFTSHIFT, KEY_LEFTSHIFT,
-                0,0,
-                KEY_LEFTALT, KEY_RIGHTALT,
-                0, 0, 0, 0 };
-        scancode = map[code & 0xF];
-    } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {
-        static const uint16_t map[] = {
-                KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
-                KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
-                KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
-                KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
-                KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };
-        scancode = map[(code & 0x5F) - 'A'];
-    } else {
-        switch (code) {
-            case 0x0003:    scancode = KEY_CENTER;      break;
-            case 0x0020:    scancode = KEY_SPACE;       break;
-            case 0x0023:    scancode = KEY_SHARP;       break;
-            case 0x0033:    scancode = KEY_SHARP;       break;
-            case 0x002C:    scancode = KEY_COMMA;       break;
-            case 0x003C:    scancode = KEY_COMMA;       break;
-            case 0x002E:    scancode = KEY_DOT;         break;
-            case 0x003E:    scancode = KEY_DOT;         break;
-            case 0x002F:    scancode = KEY_SLASH;       break;
-            case 0x003F:    scancode = KEY_SLASH;       break;
-            case 0x0032:    scancode = KEY_EMAIL;       break;
-            case 0x0040:    scancode = KEY_EMAIL;       break;
-            case 0xFF08:    scancode = KEY_BACKSPACE;   break;
-            case 0xFF1B:    scancode = KEY_BACK;        break;
-            case 0xFF09:    scancode = KEY_TAB;         break;
-            case 0xFF0D:    scancode = KEY_ENTER;       break;
-            case 0x002A:    scancode = KEY_STAR;        break;
-            case 0xFFBE:    scancode = KEY_SEND;        break; // F1
-            case 0xFFBF:    scancode = KEY_END;         break; // F2
-            case 0xFFC0:    scancode = KEY_HOME;        break; // F3
-            case 0xFFC5:    scancode = KEY_POWER;       break; // F8
-        }
-    }
-
-#if DEBUG_MSG
-   LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode);
-#endif
-
-    if (scancode) {
-        mEventInjector.injectKey(uint16_t(scancode),
-             msg.downFlag ? EventInjector::DOWN : EventInjector::UP);
-    }
-#endif
-}
-
-void RFBServer::waitForClientMessage(ClientMessage& msg)
-{
-    if ( !read(msg.payload(), 1) )
-        return;
-
-    switch(msg.type()) {
-
-    case SET_PIXEL_FORMAT:
-        read(msg.payload(1), sizeof(SetPixelFormat)-1);
-        break;
-
-    case FIX_COLOUR_MAP_ENTRIES:
-        mStatus = UNKNOWN_ERROR;
-        return;
-
-    case SET_ENCODINGS:
-    {
-        if ( !read(msg.payload(1), sizeof(SetEncodings)-1) )
-            return;
-
-        size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4;
-        if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) {
-            mStatus = NO_MEMORY;
-            return;
-        }
-
-        if ( !read(msg.payload(sizeof(SetEncodings)), size) )
-            return;
-
-        break;
-    }
-
-    case FRAME_BUFFER_UPDATE_REQ:
-        read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1);
-        break;
-
-    case KEY_EVENT:
-        read(msg.payload(1), sizeof(KeyEvent)-1);
-        break;
-
-    case POINTER_EVENT:
-        read(msg.payload(1), sizeof(PointerEvent)-1);
-        break;
-
-    case CLIENT_CUT_TEXT:
-    {
-        if ( !read(msg.payload(1), sizeof(ClientCutText)-1) )
-            return;
-
-        size_t size = ntohl( msg.messages().clientCutText.length );
-        if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) {
-            mStatus = NO_MEMORY;
-            return;
-        }
-
-        if ( !read(msg.payload(sizeof(SetEncodings)), size) )
-            return;
-
-        break;
-    }
-
-    default:
-        LOGE("Unknown Message %d", msg.type());
-        mStatus = UNKNOWN_ERROR;
-        return;
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-bool RFBServer::write(const Message& msg)
-{
-    write(msg.payload(), msg.size());
-    return alive();
-}
-
-bool RFBServer::read(Message& msg)
-{
-    read(msg.payload(), msg.size());
-    return alive();
-}
-
-bool RFBServer::write(const void* buffer, int size)
-{
-    int wr = ::write(mFD, buffer, size);
-    if (wr != size) {
-        //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
-        mStatus = (wr == -1) ? errno : -1;
-    }
-    return alive();
-}
-
-bool RFBServer::read(void* buffer, int size)
-{
-    int rd = ::read(mFD, buffer, size);
-    if (rd != size) {
-        //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno));
-        mStatus = (rd == -1) ? errno : -1;
-    }
-    return alive();
-}
-
-bool RFBServer::alive() const
-{
-    return  mStatus == 0;
-}
-
-bool RFBServer::isConnected() const
-{
-    return alive();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg)
-{
-    Mutex::Autolock _l(mRegionLock);
-
-    // update dirty region
-    mDirtyRegion.orSelf(reg);
-
-    // remember the front-buffer
-    mFrontBuffer = front;
-
-    // The client has not requested anything, don't do anything more
-    if (mClientRegionRequest.isEmpty())
-        return;
-
-    // wake the sending thread up
-    mRobinThread->wake();
-}
-
-void RFBServer::sendFrameBufferUpdates()
-{
-    Vector<Rect> rects;
-    size_t countRects;
-    GGLSurface fb;
-
-    { // Scope for the lock
-        Mutex::Autolock _l(mRegionLock);
-        if (mFrontBuffer.data == 0)
-            return;
-
-        const Region reg( mDirtyRegion.intersect(mClientRegionRequest) );
-        if (reg.isEmpty())
-            return;
-
-        mDirtyRegion.subtractSelf(reg);
-        countRects = reg.rects(rects);
-
-        // copy the frame-buffer so we can stay responsive
-        size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format);
-        size_t bpr = mFrameBuffer.stride * bytesPerPix;
-        if (mFrameBuffer.data == 0) {
-            mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height);
-            if (mFrameBuffer.data == 0)
-            	return;
-        }
-
-        memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height);
-        fb = mFrameBuffer;
-    }
-
-    FrameBufferUpdate msgHeader;
-    msgHeader.type = 0;
-    msgHeader.numberOfRectangles = htons(countRects);
-    write(&msgHeader, sizeof(msgHeader));
-
-    Rectangle rectangle;
-    for (size_t i=0 ; i<countRects ; i++) {
-        const Rect& r = rects[i];
-        rectangle.x = htons( r.left );
-        rectangle.y = htons( r.top );
-        rectangle.w = htons( r.width() );
-        rectangle.h = htons( r.height() );
-        rectangle.encoding = htons( SetEncodings::Raw );
-        write(&rectangle, sizeof(rectangle));
-        size_t h = r.height();
-        size_t w = r.width();
-        size_t bytesPerPix = bytesPerPixel(fb.format);
-        size_t bpr = fb.stride * bytesPerPix;
-        size_t bytes = w * bytesPerPix;
-        size_t offset = (r.top * bpr) + (r.left * bytesPerPix);
-        uint8_t* src = static_cast<uint8_t*>(fb.data) + offset;
-        iovec* iov = mIoVec;
-        while (h--) {
-            iov->iov_base = src;
-            iov->iov_len = bytes;
-            src += bpr;
-            iov++;
-        }
-        size_t iovcnt = iov - mIoVec;
-        int wr = ::writev(mFD, mIoVec, iovcnt);
-        if (wr < 0) {
-            //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
-            mStatus =  errno;
-        }
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::Message::Message(size_t size)
-    : mSize(size), mAllocatedSize(size)
-{
-    mPayload = malloc(size);
-}
-
-RFBServer::Message::Message(void* payload, size_t size)
-    : mPayload(payload), mSize(size), mAllocatedSize(0)
-{
-}
-
-RFBServer::Message::~Message()
-{
-    if (mAllocatedSize)
-        free(mPayload);
-}
-
-status_t RFBServer::Message::resize(size_t size)
-{
-    if (size > mAllocatedSize) {
-        void* newp;
-        if (mAllocatedSize) {
-            newp = realloc(mPayload, size);
-            if (!newp) return NO_MEMORY;
-        } else {
-            newp = malloc(size);
-            if (!newp) return NO_MEMORY;
-            memcpy(newp, mPayload, mSize);
-            mAllocatedSize = size;
-        }
-        mPayload = newp;
-    }
-    mSize = size;
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::EventInjector::EventInjector()
-    : mFD(-1)
-{
-}
-
-RFBServer::EventInjector::~EventInjector()
-{
-}
-
-void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value)
-{
-#ifdef HAVE_ANDROID_OS
-    // XXX: we need to open the right event device
-    int version;
-    mFD = open("/dev/input/event0", O_RDWR);
-    ioctl(mFD, EVIOCGVERSION, &version);
-
-    input_event ev;
-    memset(&ev, 0, sizeof(ev));
-    ev.type = EV_KEY;
-    ev.code = code;
-    ev.value = value;
-    ::write(mFD, &ev, sizeof(ev));
-
-    close(mFD);
-    mFD = -1;
-#endif
-}
-
-
-}; // namespace android
-
diff --git a/libs/surfaceflinger/RFBServer.h b/libs/surfaceflinger/RFBServer.h
deleted file mode 100644
index 420912e..0000000
--- a/libs/surfaceflinger/RFBServer.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RFB_SERVER_H
-#define ANDROID_RFB_SERVER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <ui/Region.h>
-#include <ui/PixelFormat.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "Barrier.h"
-
-namespace android {
-
-class SurfaceFlinger;
-
-class RFBServer : public Thread
-{
-public:
-                        RFBServer(uint32_t w, uint32_t h, android::PixelFormat format);
-    virtual             ~RFBServer();
-
-    void    frameBufferUpdated(const GGLSurface& front, const Region& reg);
-    bool    isConnected() const;
-
-private:
-            typedef uint8_t     card8;
-            typedef uint16_t    card16;
-            typedef uint32_t    card32;
-
-            struct Message {
-                                Message(size_t size);
-                virtual         ~Message();
-                void*           payload(int offset=0) {
-                    return static_cast<char*>(mPayload)+offset;
-                }
-                void const *    payload(int offset=0) const {
-                    return static_cast<char const *>(mPayload)+offset;
-                }
-                size_t          size() const { return mSize; }
-            protected:
-                                Message(void* payload, size_t size);
-                status_t        resize(size_t size);
-            private:
-                void*       mPayload;
-                size_t      mSize;
-                size_t      mAllocatedSize;
-            };
-
-            struct ProtocolVersion : public Message {
-                ProtocolVersion(uint8_t major, uint8_t minor)
-                    : Message(&messageData, 12) {
-                    char* p = static_cast<char*>(payload());
-                    snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA);
-                }
-                status_t decode(int& maj, int& min) {
-                    char* p = static_cast<char*>(payload());
-                    int n = sscanf(p, "RFB %03u.%03u", &maj, &min);
-                    return (n == 2) ? NO_ERROR : NOT_ENOUGH_DATA;
-                }
-            private:
-                char messageData[12+1];
-            };
-            
-            struct Authentication : public Message {
-                enum { Failed=0, None=1, Vnc=2 };
-                Authentication(int auth) : Message(&messageData, 4) {
-                    *static_cast<card32*>(payload()) = htonl(auth);
-                }
-            private:
-                card32 messageData;
-            };
-            
-            struct ClientInitialization : public Message {
-                ClientInitialization() : Message(&messageData, 1) { }
-                int sharedFlags() {
-                    return messageData;
-                }
-            private:
-                card8 messageData;
-            };
-
-            struct PixelFormat {
-                card8   bitsPerPixel;
-                card8   depth;
-                card8   bigEndianFlag;
-                card8   trueColorFlag;
-                card16  redMax;
-                card16  greenMax;
-                card16  blueMax;
-                card8   redShift;
-                card8   greenShift;
-                card8   blueShift;
-                uint8_t padding[3];
-            } __attribute__((packed));
-            
-            struct ServerInitialization : public Message {
-                ServerInitialization(char const * name)
-                    : Message(sizeof(Payload) + strlen(name))
-                {
-                    const size_t nameLength = size() - sizeof(Payload);
-                    message().nameLength = htonl(nameLength); 
-                    memcpy((char*)message().nameString, name,nameLength);
-                }
-                struct Payload {
-                    card16      framebufferWidth;
-                    card16      framebufferHeight;
-                    PixelFormat serverPixelFormat;
-                    card32      nameLength;
-                    card8       nameString[0];
-                } __attribute__((packed));
-                Payload& message() {
-                    return *static_cast<Payload*>(payload());
-                }
-            };
-
-            // client messages...
-            
-            struct SetPixelFormat {
-                card8           type;
-                uint8_t         padding[3];
-                PixelFormat     pixelFormat;
-            } __attribute__((packed));
-
-            struct SetEncodings {
-                enum { Raw=0, CoR=1, RRE=2, CoRRE=4, Hextile=5 };
-                card8           type;
-                uint8_t         padding;
-                card16          numberOfEncodings;
-                card32          encodings[0];
-            } __attribute__((packed));
-
-            struct FrameBufferUpdateRequest {
-                card8           type;
-                card8           incremental;
-                card16          x;
-                card16          y;
-                card16          width;
-                card16          height;
-            } __attribute__((packed));
-            
-            struct KeyEvent {
-                card8           type;
-                card8           downFlag;
-                uint8_t         padding[2];
-                card32          key;
-            } __attribute__((packed));
-
-            struct PointerEvent {
-                card8           type;
-                card8           buttonMask;
-                card16          x;
-                card16          y;
-            } __attribute__((packed));
-
-            struct ClientCutText {
-                card8           type;
-                uint8_t         padding[3];
-                card32          length;
-                card8           text[0];
-            } __attribute__((packed));
-            
-            union ClientMessages {
-                card8                       type;
-                SetPixelFormat              setPixelFormat;
-                SetEncodings                setEncodings;
-                FrameBufferUpdateRequest    frameBufferUpdateRequest;
-                KeyEvent                    keyEvent;
-                PointerEvent                pointerEvent;
-                ClientCutText               clientCutText;
-            };
-
-            struct Rectangle {
-                card16      x;
-                card16      y;
-                card16      w;
-                card16      h;
-                card32      encoding;
-            } __attribute__((packed));
-
-            struct FrameBufferUpdate {
-                card8       type;
-                uint8_t     padding;
-                card16      numberOfRectangles;
-                Rectangle   rectangles[0];            
-            } __attribute__((packed));
-
-            enum {
-                SET_PIXEL_FORMAT        = 0,
-                FIX_COLOUR_MAP_ENTRIES  = 1,
-                SET_ENCODINGS           = 2,
-                FRAME_BUFFER_UPDATE_REQ = 3,
-                KEY_EVENT               = 4,
-                POINTER_EVENT           = 5,
-                CLIENT_CUT_TEXT         = 6,
-            };
-
-            struct ClientMessage : public Message {
-                ClientMessage()
-                    : Message(&messageData, sizeof(messageData)) {
-                }
-                const ClientMessages& messages() const {
-                    return *static_cast<ClientMessages const *>(payload());
-                }
-                const int type() const {
-                    return messages().type;
-                }
-                status_t resize(size_t size) {
-                    return Message::resize(size);
-                }
-
-                ClientMessages messageData;
-            };
-
-            
-            class ServerThread : public Thread
-            {
-                friend class RFBServer;
-            public:
-                        ServerThread(const sp<RFBServer>& receiver);
-                virtual ~ServerThread();
-                void wake();
-                void exitAndWait();
-            private:
-                virtual bool threadLoop();
-                virtual status_t readyToRun();
-                virtual void onFirstRef();
-                wp<RFBServer> mReceiver;
-                bool (RFBServer::*mAction)();
-                Barrier mUpdateBarrier;
-            };
-            
-            class EventInjector {
-            public:
-                enum { UP=0, DOWN=1 };
-                EventInjector();
-                ~EventInjector();
-                void injectKey(uint16_t code, uint16_t value);
-            private:
-                struct input_event {
-                    struct timeval time;
-                    uint16_t type;
-                    uint16_t code;
-                    uint32_t value;
-                };
-                int mFD;
-            };
-            
-            void        handshake(uint8_t major, uint8_t minor, uint32_t auth);
-            void        waitForClientMessage(ClientMessage& msg);
-            void        handleClientMessage(const ClientMessage& msg);
-            void        handleSetPixelFormat(const SetPixelFormat& msg);
-            void        handleSetEncodings(const SetEncodings& msg);
-            void        handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg);
-            void        handleKeyEvent(const KeyEvent& msg);
-            void        sendFrameBufferUpdates();
-
-            bool        validatePixelFormat(const PixelFormat& pf);
-            bool        alive() const;
-            bool        write(const Message& msg);
-            bool        read(Message& msg);
-
-            bool        write(const void* buffer, int size);
-            bool        read(void* buffer, int size);
-
-    virtual bool        threadLoop();
-    virtual status_t    readyToRun();
-    virtual void        onFirstRef();
-
-            sp<ServerThread>    mRobinThread;
-
-            int         mFD;
-            int         mStatus;
-            iovec*      mIoVec;
-    
-            EventInjector   mEventInjector;
-
-            Mutex       mRegionLock;
-            // This is the region requested by the client since the last
-            // time we updated it
-            Region      mClientRegionRequest;
-            // This is the region of the screen that needs to be sent to the
-            // client since the last time we updated it.
-            // Typically this is the dirty region, but not necessarily, for
-            // instance if the client asked for a non incremental update.
-            Region      mDirtyRegion;
-            
-            GGLSurface  mFrameBuffer;
-            GGLSurface  mFrontBuffer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_RFB_SERVER_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 554e8e7..242d026 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -53,20 +53,15 @@
 #include "LayerBuffer.h"
 #include "LayerDim.h"
 #include "LayerBitmap.h"
-#include "LayerScreenshot.h"
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
 #include "SurfaceFlinger.h"
-#include "RFBServer.h"
 #include "VRamHeap.h"
 
 #include "DisplayHardware/DisplayHardware.h"
 #include "GPUHardware/GPUHardware.h"
 
 
-// the VNC server even on local ports presents a significant
-// thread as it can allow an application to control and "see" other
-// applications, de-facto bypassing security permissions.
-#define ENABLE_VNC_SERVER   0
-
 #define DISPLAY_COUNT       1
 
 namespace android {
@@ -185,6 +180,7 @@
         mDeferReleaseConsole(false),
         mFreezeDisplay(false),
         mFreezeCount(0),
+        mFreezeDisplayTime(0),
         mDebugRegion(0),
         mDebugCpu(0),
         mDebugFps(0),
@@ -225,6 +221,7 @@
 SurfaceFlinger::~SurfaceFlinger()
 {
     glDeleteTextures(1, &mWormholeTexName);
+    delete mOrientationAnimation;
 }
 
 copybit_device_t* SurfaceFlinger::getBlitEngine() const
@@ -448,6 +445,8 @@
      *  We're now ready to accept clients...
      */
 
+    mOrientationAnimation = new OrientationAnimation(this);
+    
     // start CPU gauge display
     if (mDebugCpu)
         mCpuGauge = new CPUGauge(this, ms2ns(500));
@@ -456,9 +455,6 @@
     if (mDebugNoBootAnimation == false)
         mBootAnimation = new BootAnimation(this);
 
-    if (ENABLE_VNC_SERVER)
-        mRFBServer = new RFBServer(w, h, f);
-
     return NO_ERROR;
 }
 
@@ -472,17 +468,25 @@
 {
     // wait for something to do
     if (UNLIKELY(isFrozen())) {
-        // wait 2 seconds
-        int err = mSyncObject.wait(ms2ns(3000));
+        // wait 5 seconds
+        const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+        const nsecs_t now = systemTime();
+        if (mFreezeDisplayTime == 0) {
+            mFreezeDisplayTime = now;
+        }
+        nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+        int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
         if (err != NO_ERROR) {
             if (isFrozen()) {
                 // we timed out and are still frozen
                 LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
                         mFreezeDisplay, mFreezeCount);
                 mFreezeCount = 0;
+                mFreezeDisplay = false;
             }
         }
     } else {
+        mFreezeDisplayTime = 0;
         mSyncObject.wait();
     }
 }
@@ -556,11 +560,8 @@
 
 void SurfaceFlinger::postFramebuffer()
 {
-    if (UNLIKELY(isFrozen())) {
-        // we are not allowed to draw, but pause a bit to make sure
-        // apps don't end up using the whole CPU, if they depend on
-        // surfaceflinger for synchronization.
-        usleep(8333); // 8.3ms ~ 120fps
+    const bool skip = mOrientationAnimation->run();
+    if (UNLIKELY(skip)) {
         return;
     }
 
@@ -571,18 +572,6 @@
             debugShowFPS();
         }
 
-        if (UNLIKELY(ENABLE_VNC_SERVER &&
-                mRFBServer!=0 && mRFBServer->isConnected())) {
-            if (!mSecureFrameBuffer) {
-                GGLSurface fb;
-                // backbufer, is going to become the front buffer really soon
-                hw.getDisplaySurface(&fb);
-                if (LIKELY(fb.data != 0)) {
-                    mRFBServer->frameBufferUpdated(fb, mInvalidRegion);
-                }
-            }
-        }
-
         hw.flip(mInvalidRegion);
 
         mInvalidRegion.clear();
@@ -685,18 +674,13 @@
 
             mVisibleRegionsDirty = true;
             mDirtyRegion.set(hw.bounds());
+
+            mOrientationAnimation->onOrientationChanged();
         }
 
         if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
             // freezing or unfreezing the display -> trigger animation if needed
             mFreezeDisplay = mCurrentState.freezeDisplay;
-            const nsecs_t now = systemTime();
-            if (mFreezeDisplay) {
-                mFreezeDisplayTime = now;
-            } else {
-                //LOGD("Screen was frozen for %llu us",
-                //        ns2us(now-mFreezeDisplayTime));
-            }
         }
 
         // some layers might have been removed, so
@@ -875,19 +859,9 @@
 
     uint32_t flags = hw.getFlags();
     if (flags & DisplayHardware::BUFFER_PRESERVED) {
-        if (flags & DisplayHardware::COPY_BACK_EXTENSION) {
-            // yay. nothing to do here.
-        } else {
-            if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
-                // we need to fully redraw the part that will be updated
-                mDirtyRegion.set(mInvalidRegion.bounds());
-            } else {
-                // TODO: we only need te redraw the part that had been drawn
-                // the round before and is not drawn now
-            }
-        }
+        // here we assume DisplayHardware::flip()'s  implementation
+        // performs the copy-back optimization.
     } else {
-        // COPY_BACK_EXTENSION makes no sense here
         if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
             // we need to fully redraw the part that will be updated
             mDirtyRegion.set(mInvalidRegion.bounds());
@@ -1077,6 +1051,29 @@
     // XXX: mFPS has the value we want
  }
 
+status_t SurfaceFlinger::addLayer(LayerBase* layer)
+{
+    Mutex::Autolock _l(mStateLock);
+    addLayer_l(layer);
+    setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+{
+    Mutex::Autolock _l(mStateLock);
+    removeLayer_l(layer);
+    setTransactionFlags(eTransactionNeeded);
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+{
+    layer->forceVisibilityTransaction();
+    setTransactionFlags(eTraversalNeeded);
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
 {
     ssize_t i = mCurrentState.layersSortedByZ.add(
@@ -1555,55 +1552,17 @@
 
     status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
     if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
-        if (code == 1012) {
-            // take screen-shot of the front buffer
-            if (UNLIKELY(checkCallingPermission(
-                    String16("android.permission.READ_FRAME_BUFFER")) == false))
-            { // not allowed
-                LOGE("Permission Denial: "
-                        "can't take screenshots from pid=%d, uid=%d\n",
-                        IPCThreadState::self()->getCallingPid(),
-                        IPCThreadState::self()->getCallingUid());
-                return PERMISSION_DENIED;
-            }
-
-            if (UNLIKELY(mSecureFrameBuffer)) {
-                LOGE("A secure window is on screen: "
-                        "can't take screenshots from pid=%d, uid=%d\n",
-                        IPCThreadState::self()->getCallingPid(),
-                        IPCThreadState::self()->getCallingUid());
-                return PERMISSION_DENIED;
-            }
-
-            LOGI("Taking a screenshot...");
-
-            LayerScreenshot* l = new LayerScreenshot(this, 0);
-
-            Mutex::Autolock _l(mStateLock);
-            const DisplayHardware& hw(graphicPlane(0).displayHardware());
-            l->initStates(hw.getWidth(), hw.getHeight(), 0);
-            l->setLayer(INT_MAX);
-
-            addLayer_l(l);
-            setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
-
-            l->takeScreenshot(mStateLock, reply);
-
-            removeLayer_l(l);
-            setTransactionFlags(eTransactionNeeded);
-            return NO_ERROR;
-        } else {
-            // HARDWARE_TEST stuff...
-            if (UNLIKELY(checkCallingPermission(
-                    String16("android.permission.HARDWARE_TEST")) == false))
-            { // not allowed
-                LOGE("Permission Denial: pid=%d, uid=%d\n",
-                        IPCThreadState::self()->getCallingPid(),
-                        IPCThreadState::self()->getCallingUid());
-                return PERMISSION_DENIED;
-            }
-            int n;
-            switch (code) {
+        // HARDWARE_TEST stuff...
+        if (UNLIKELY(checkCallingPermission(
+                String16("android.permission.HARDWARE_TEST")) == false))
+        { // not allowed
+            LOGE("Permission Denial: pid=%d, uid=%d\n",
+                    IPCThreadState::self()->getCallingPid(),
+                    IPCThreadState::self()->getCallingUid());
+            return PERMISSION_DENIED;
+        }
+        int n;
+        switch (code) {
             case 1000: // SHOW_CPU
                 n = data.readInt32();
                 mDebugCpu = n ? 1 : 0;
@@ -1636,8 +1595,8 @@
                 const DisplayHardware& hw(graphicPlane(0).displayHardware());
                 mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
                 signalEvent();
-                }
-                return NO_ERROR;
+            }
+            return NO_ERROR;
             case 1005: // ask GPU revoke
                 mGPU->friendlyRevoke();
                 return NO_ERROR;
@@ -1653,13 +1612,12 @@
                 reply->writeInt32(mDebugRegion);
                 reply->writeInt32(mDebugBackground);
                 return NO_ERROR;
-            case 1013: { // screenshot
+            case 1013: {
                 Mutex::Autolock _l(mStateLock);
                 const DisplayHardware& hw(graphicPlane(0).displayHardware());
                 reply->writeInt32(hw.getPageFlipCount());
             }
             return NO_ERROR;
-            }
         }
     }
     return err;
@@ -1813,10 +1771,33 @@
     mGlobalTransform = mOrientationTransform * mTransform;
 }
 
+status_t GraphicPlane::orientationToTransfrom(
+        int orientation, int w, int h, Transform* tr)
+{    
+    float a, b, c, d, x, y;
+    switch (orientation) {
+    case ISurfaceComposer::eOrientationDefault:
+        a=1; b=0; c=0; d=1; x=0; y=0;
+        break;
+    case ISurfaceComposer::eOrientation90:
+        a=0; b=-1; c=1; d=0; x=w; y=0;
+        break;
+    case ISurfaceComposer::eOrientation180:
+        a=-1; b=0; c=0; d=-1; x=w; y=h;
+        break;
+    case ISurfaceComposer::eOrientation270:
+        a=0; b=1; c=-1; d=0; x=0; y=h;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    tr->set(a, b, c, d);
+    tr->set(x, y);
+    return NO_ERROR;
+}
+
 status_t GraphicPlane::setOrientation(int orientation)
 {
-    float a, b, c, d, x, y;
-
     const DisplayHardware& hw(displayHardware());
     const float w = hw.getWidth();
     const float h = hw.getHeight();
@@ -1830,30 +1811,21 @@
 
     // If the rotation can be handled in hardware, this is where
     // the magic should happen.
-
-    switch (orientation) {
-    case ISurfaceComposer::eOrientation90:
-        a=0; b=-1; c=1; d=0; x=w; y=0;
-        break;
-    case ISurfaceComposer::eOrientation180:
-        a=-1; b=0; c=0; d=-1; x=w; y=h;
-        break;
-    case ISurfaceComposer::eOrientation270:
-        a=0; b=1; c=-1; d=0; x=0; y=h;
-        break;
-    case 42: {
+    if (UNLIKELY(orientation == 42)) {
+        float a, b, c, d, x, y;
         const float r = (3.14159265f / 180.0f) * 42.0f;
         const float si = sinf(r);
         const float co = cosf(r);
         a=co; b=-si; c=si; d=co;
         x = si*(h*0.5f) + (1-co)*(w*0.5f);
         y =-si*(w*0.5f) + (1-co)*(h*0.5f);
-    } break;
-    default:
-        return BAD_VALUE;
+        mOrientationTransform.set(a, b, c, d);
+        mOrientationTransform.set(x, y);
+    } else {
+        GraphicPlane::orientationToTransfrom(orientation, w, h,
+                &mOrientationTransform);
     }
-    mOrientationTransform.set(a, b, c, d);
-    mOrientationTransform.set(x, y);
+    
     mGlobalTransform = mOrientationTransform * mTransform;
     return NO_ERROR;
 }
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index a242f1a..f7d7764 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -35,11 +35,11 @@
 #include <private/ui/LayerState.h>
 #include <private/ui/SurfaceFlingerSynchro.h>
 
+#include "Barrier.h"
+#include "BootAnimation.h"
+#include "CPUGauge.h"
 #include "Layer.h"
 #include "Tokenizer.h"
-#include "CPUGauge.h"
-#include "BootAnimation.h"
-#include "Barrier.h"
 
 struct copybit_device_t;
 struct overlay_device_t;
@@ -48,16 +48,17 @@
 
 // ---------------------------------------------------------------------------
 
-class BClient;
 class Client;
+class BClient;
 class DisplayHardware;
+class FreezeLock;
 class GPUHardwareInterface;
 class IGPUCallback;
 class Layer;
 class LayerBuffer;
-class RFBServer;
+class LayerOrientationAnim;
+class OrientationAnimation;
 class SurfaceHeapManager;
-class FreezeLock;
 
 typedef int32_t ClientID;
 
@@ -110,6 +111,8 @@
 class GraphicPlane
 {
 public:
+    static status_t orientationToTransfrom(int orientation, int w, int h,
+            Transform* tr);
 
                                 GraphicPlane();
                                 ~GraphicPlane();
@@ -181,7 +184,12 @@
 
             copybit_device_t* getBlitEngine() const;
             overlay_control_device_t* getOverlayEngine() const;
+
             
+    status_t removeLayer(LayerBase* layer);
+    status_t addLayer(LayerBase* layer);
+    status_t invalidateLayerVisibility(LayerBase* layer);
+    
 private:
     friend class BClient;
     friend class LayerBase;
@@ -337,7 +345,6 @@
                 sp<GPUHardwareInterface>    mGPU;
                 GLuint                      mWormholeTexName;
                 sp<BootAnimation>           mBootAnimation;
-                sp<RFBServer>               mRFBServer;
                 nsecs_t                     mBootTime;
                 
                 // Can only accessed from the main thread, these members
@@ -352,6 +359,8 @@
                 bool                        mFreezeDisplay;
                 int32_t                     mFreezeCount;
                 nsecs_t                     mFreezeDisplayTime;
+                friend class OrientationAnimation;
+                OrientationAnimation*       mOrientationAnimation;
 
                 // access protected by mDebugLock
     mutable     Mutex                       mDebugLock;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 77bc576..0ccd71f 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -35,8 +35,6 @@
 #include <utils/MemoryHeapPmem.h>
 #include <utils/MemoryHeapBase.h>
 
-#include <GLES/eglnatives.h>
-
 #include "GPUHardware/GPUHardware.h"
 #include "SurfaceFlinger.h"
 #include "VRamHeap.h"
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 50c6008..b3cbda1 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -84,8 +84,10 @@
     mRawCallbackCookie = 0;
     mJpegCallback = 0;
     mJpegCallbackCookie = 0;
-    mFrameCallback = 0;
-    mFrameCallbackCookie = 0;
+    mPreviewCallback = 0;
+    mPreviewCallbackCookie = 0;
+    mRecordingCallback = 0;
+    mRecordingCallbackCookie = 0;
     mErrorCallback = 0;
     mErrorCallbackCookie = 0;
     mAutoFocusCallback = 0;
@@ -108,6 +110,8 @@
     if (c->mCamera != 0) {
         c->mCamera->asBinder()->linkToDeath(c);
         c->mStatus = NO_ERROR;
+    } else {
+        c.clear();
     }
     return c;
 }
@@ -184,6 +188,15 @@
     return c->startPreview();
 }
 
+// start recording mode, must call setPreviewDisplay first
+status_t Camera::startRecording()
+{
+    LOGV("startRecording");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->startRecording();
+}
+
 // stop preview mode
 void Camera::stopPreview()
 {
@@ -193,6 +206,24 @@
     c->stopPreview();
 }
 
+// stop recording mode
+void Camera::stopRecording()
+{
+    LOGV("stopRecording");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    c->stopRecording();
+}
+
+// release a recording frame
+void Camera::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+    LOGV("releaseRecordingFrame");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return;
+    c->releaseRecordingFrame(mem);
+}
+
 // get preview state
 bool Camera::previewEnabled()
 {
@@ -202,6 +233,15 @@
     return c->previewEnabled();
 }
 
+// get recording state
+bool Camera::recordingEnabled()
+{
+    LOGV("recordingEnabled");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return false;
+    return c->recordingEnabled();
+}
+
 status_t Camera::autoFocus()
 {
     LOGV("autoFocus");
@@ -266,14 +306,21 @@
     mJpegCallbackCookie = cookie;
 }
 
-void Camera::setFrameCallback(frame_callback cb, void *cookie, int frame_callback_flag)
+void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
 {
-    LOGV("setFrameCallback");
-    mFrameCallback = cb;
-    mFrameCallbackCookie = cookie;
+    LOGV("setPreviewCallback");
+    mPreviewCallback = cb;
+    mPreviewCallbackCookie = cookie;
     sp <ICamera> c = mCamera;
     if (c == 0) return;
-    mCamera->setFrameCallbackFlag(frame_callback_flag);
+    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)
@@ -316,12 +363,21 @@
     }
 }
 
-// callback from camera service when video frame is ready
-void Camera::frameCallback(const sp<IMemory>& frame)
+// callback from camera service when preview frame is ready
+void Camera::previewCallback(const sp<IMemory>& frame)
 {
     LOGV("frameCallback");
-    if (mFrameCallback) {
-        mFrameCallback(frame, mFrameCallbackCookie);
+    if (mPreviewCallback) {
+        mPreviewCallback(frame, mPreviewCallbackCookie);
+    }
+}
+
+// callback from camera service when a recording frame is ready
+void Camera::recordingCallback(const sp<IMemory>& frame)
+{
+    LOGV("recordingCallback");
+    if (mRecordingCallback) {
+        mRecordingCallback(frame, mRecordingCallbackCookie);
     }
 }
 
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 7ca77bb..6c25836 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -24,6 +24,9 @@
 
 namespace android {
 
+static const char* portrait = "portrait";
+static const char* landscape = "landscape";
+
 CameraParameters::CameraParameters()
                 : mMap()
 {
@@ -182,6 +185,23 @@
     set("preview-format", format);
 }
 
+int CameraParameters::getOrientation() const
+{
+    const char* orientation = get("orientation");
+    if (orientation && !strcmp(orientation, portrait))
+        return CAMERA_ORIENTATION_PORTRAIT;
+    return CAMERA_ORIENTATION_LANDSCAPE;
+}
+
+void CameraParameters::setOrientation(int orientation)
+{
+    if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
+        set("preview-format", portrait);
+    } else {
+        set("preview-format", landscape);
+    }
+}
+
 const char *CameraParameters::getPreviewFormat() const
 {
     return get("preview-format");
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
index 44258a8..d06c98b 100644
--- a/libs/ui/EGLDisplaySurface.cpp
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -42,7 +42,7 @@
 #include <linux/msm_mdp.h>
 #endif
 
-#include <GLES/egl.h>
+#include <EGL/egl.h>
 
 #include <pixelflinger/format.h>
 
@@ -71,8 +71,6 @@
     egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
     egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
     egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
-    egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle;
-    egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer;
     egl_native_window_t::connect = 0;
     egl_native_window_t::disconnect = 0;
 
@@ -136,15 +134,6 @@
     EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
     return that->swapBuffers();
 }
-uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) {
-    EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
-    return that->nextBuffer();
-}
-void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window,
-        int l, int t, int w, int h) {
-    EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
-    that->setSwapRectangle(l, t, w, h);
-}
 
 void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
 {
@@ -249,15 +238,6 @@
     return mPageFlipCount;
 }
 
-uint32_t EGLDisplaySurface::nextBuffer()
-{
-    // update the address of the buffer to draw to next
-    const GGLSurface& buffer = mFb[mIndex];
-    egl_native_window_t::offset =
-        intptr_t(buffer.data) - egl_native_window_t::base;
-    return 0;
-}
-
 void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
 {
 #if HAVE_ANDROID_OS
@@ -318,6 +298,59 @@
     }
 }
 
+void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+    if (mBlitEngine) {
+        copybit_image_t src = {
+                w:      egl_native_window_t::stride,
+                h:      egl_native_window_t::height,
+                format: egl_native_window_t::format,
+                offset: mFb[mIndex].data - mFb[0].data,
+                base:   (void*)egl_native_window_t::base,
+                fd:     egl_native_window_t::fd
+        };
+        region_iterator it(Region(Rect(
+                egl_native_window_t::width, egl_native_window_t::height)));
+        mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+    } else
+#endif
+    {
+        uint8_t* const screen_src = mFb[  mIndex].data;
+        const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+        const size_t bpr = egl_native_window_t::stride * bpp;
+        memcpy((char*)dst.base + dst.offset, screen_src,
+                bpr*egl_native_window_t::height);
+    }
+}
+
+void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+    if (mBlitEngine) {
+        copybit_image_t src = {
+                w:      egl_native_window_t::stride,
+                h:      egl_native_window_t::height,
+                format: egl_native_window_t::format,
+                offset: mFb[1-mIndex].data - mFb[0].data,
+                base:   (void*)egl_native_window_t::base,
+                fd:     egl_native_window_t::fd
+        };
+        region_iterator it(Region(Rect(
+                egl_native_window_t::width, egl_native_window_t::height)));
+        mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+    } else
+#endif
+    {
+        uint8_t* const screen_src = mFb[1-mIndex].data;
+        const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+        const size_t bpr = egl_native_window_t::stride * bpp;
+        memcpy((char*)dst.base + dst.offset, screen_src,
+                bpr*egl_native_window_t::height);
+    }
+}
+
+
 status_t EGLDisplaySurface::mapFrameBuffer()
 {
     char const * const device_template[] = {
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
index d55fb70..f1071cf 100644
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -28,7 +28,7 @@
 #include <ui/DisplayInfo.h>
 #include <ui/Rect.h>
 
-#include <GLES/egl.h>
+#include <EGL/egl.h>
 
 #include <pixelflinger/format.h>
 
@@ -48,8 +48,6 @@
     egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
     egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
     egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
-    egl_native_window_t::nextBuffer = &EGLNativeWindowSurface::hook_nextBuffer;
-    egl_native_window_t::setSwapRectangle = &EGLNativeWindowSurface::hook_setSwapRectangle;
     egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
     egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
     
@@ -98,18 +96,6 @@
     return that->swapBuffers();
 }
 
-uint32_t EGLNativeWindowSurface::hook_nextBuffer(NativeWindowType window)
-{
-    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
-    return that->nextBuffer();
-}
-
-void EGLNativeWindowSurface::hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h)
-{
-    EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
-    that->setSwapRectangle(l, t, w, h);
-}
-
 void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
 {
     mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
@@ -138,17 +124,6 @@
     return 0;
 }
 
-uint32_t EGLNativeWindowSurface::nextBuffer()
-{
-    const sp<Surface>& surface(mSurface);
-    Surface::SurfaceInfo info;
-    surface->nextBuffer(&info);
-    // update the address of the buffer to draw to next
-    egl_native_window_t::base   = intptr_t(info.base);
-    egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
-    return 0;
-}
-
 void EGLNativeWindowSurface::connect()
 {   
     if (!mConnected) {
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 700aa3a..3b29b09 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -71,10 +71,11 @@
 
 EventHub::device_t::device_t(int32_t _id, const char* _path)
     : id(_id), path(_path), classes(0)
-    , layoutMap(new KeyLayoutMap()), next(NULL) {
+    , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
 }
 
 EventHub::device_t::~device_t() {
+    delete [] keyBitmask;
     delete layoutMap;
 }
 
@@ -403,6 +404,36 @@
     return true;
 }
 
+/*
+ * Inspect the known devices to determine whether physical keys exist for the given
+ * framework-domain key codes.
+ */
+bool EventHub::hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags) {
+    for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
+        outFlags[codeIndex] = 0;
+
+        // check each available hardware device for support for this keycode
+        Vector<int32_t> scanCodes;
+        for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
+            if (mDevices[n]) {
+                status_t err = mDevices[n]->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
+                if (!err) {
+                    // check the possible scan codes identified by the layout map against the
+                    // map of codes actually emitted by the driver
+                    for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+                        if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
+                            outFlags[codeIndex] = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
 // ----------------------------------------------------------------------------
 
 int EventHub::open_device(const char *deviceName)
@@ -527,6 +558,16 @@
                 break;
             }
         }
+        if ((device->classes & CLASS_KEYBOARD) != 0) {
+            device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+            if (device->keyBitmask != NULL) {
+                memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
+            } else {
+                delete device;
+                LOGE("out of memory allocating key bitmask");
+                return -1;
+            }
+        }
     }
     if (test_bit(BTN_MOUSE, key_bitmask)) {
         uint8_t rel_bitmask[(REL_MAX+1)/8];
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 7b0922e..ab0fef1 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -28,7 +28,7 @@
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     SET_PREVIEW_DISPLAY,
-    SET_FRAME_CALLBACK_FLAG,
+    SET_PREVIEW_CALLBACK_FLAG,
     START_PREVIEW,
     STOP_PREVIEW,
     AUTO_FOCUS,
@@ -38,7 +38,11 @@
     CONNECT,
     LOCK,
     UNLOCK,
-    PREVIEW_ENABLED
+    PREVIEW_ENABLED,
+    START_RECORDING,
+    STOP_RECORDING,
+    RECORDING_ENABLED,
+    RELEASE_RECORDING_FRAME,
 };
 
 class BpCamera: public BpInterface<ICamera>
@@ -69,15 +73,15 @@
         return reply.readInt32();
     }
 
-    // set the frame callback flag to affect how the received frames from
-    // preview are handled.
-    void setFrameCallbackFlag(int frame_callback_flag)
+    // set the preview callback flag to affect how the received frames from
+    // preview are handled. See Camera.h for details.
+    void setPreviewCallbackFlag(int flag)
     {
-        LOGV("setFrameCallbackFlag(%d)", frame_callback_flag);
+        LOGV("setPreviewCallbackFlag(%d)", flag);
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
-        data.writeInt32(frame_callback_flag);
-        remote()->transact(SET_FRAME_CALLBACK_FLAG, data, &reply);
+        data.writeInt32(flag);
+        remote()->transact(SET_PREVIEW_CALLBACK_FLAG, data, &reply);
     }
 
     // start preview mode, must call setPreviewDisplay first
@@ -90,6 +94,16 @@
         return reply.readInt32();
     }
 
+    // start recording mode, must call setPreviewDisplay first
+    status_t startRecording()
+    {
+        LOGV("startRecording");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(START_RECORDING, data, &reply);
+        return reply.readInt32();
+    }
+
     // stop preview mode
     void stopPreview()
     {
@@ -99,6 +113,24 @@
         remote()->transact(STOP_PREVIEW, data, &reply);
     }
 
+    // stop recording mode
+    void stopRecording()
+    {
+        LOGV("stopRecording");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(STOP_RECORDING, data, &reply);
+    }
+
+    void releaseRecordingFrame(const sp<IMemory>& mem)
+    {
+        LOGV("releaseRecordingFrame");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeStrongBinder(mem->asBinder());
+        remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+    }
+
     // check preview state
     bool previewEnabled()
     {
@@ -109,6 +141,16 @@
         return reply.readInt32();
     }
 
+    // check recording state
+    bool recordingEnabled()
+    {
+        LOGV("recordingEnabled");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(RECORDING_ENABLED, data, &reply);
+        return reply.readInt32();
+    }
+
     // auto focus
     status_t autoFocus()
     {
@@ -202,11 +244,11 @@
             reply->writeInt32(setPreviewDisplay(surface));
             return NO_ERROR;
         } break;
-        case SET_FRAME_CALLBACK_FLAG: {
-            LOGV("SET_FRAME_CALLBACK_TYPE");
+        case SET_PREVIEW_CALLBACK_FLAG: {
+            LOGV("SET_PREVIEW_CALLBACK_TYPE");
             CHECK_INTERFACE(ICamera, data, reply);
-            int frame_callback_flag = data.readInt32();
-            setFrameCallbackFlag(frame_callback_flag);
+            int callback_flag = data.readInt32();
+            setPreviewCallbackFlag(callback_flag);
             return NO_ERROR;
         } break;
         case START_PREVIEW: {
@@ -215,18 +257,43 @@
             reply->writeInt32(startPreview());
             return NO_ERROR;
         } break;
+        case START_RECORDING: {
+            LOGV("START_RECORDING");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(startRecording());
+            return NO_ERROR;
+        } break;
         case STOP_PREVIEW: {
             LOGV("STOP_PREVIEW");
             CHECK_INTERFACE(ICamera, data, reply);
             stopPreview();
             return NO_ERROR;
         } break;
+        case STOP_RECORDING: {
+            LOGV("STOP_RECORDING");
+            CHECK_INTERFACE(ICamera, data, reply);
+            stopRecording();
+            return NO_ERROR;
+        } break;
+        case RELEASE_RECORDING_FRAME: {
+            LOGV("RELEASE_RECORDING_FRAME");
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+            releaseRecordingFrame(mem);
+            return NO_ERROR;
+        } break;
         case PREVIEW_ENABLED: {
             LOGV("PREVIEW_ENABLED");
             CHECK_INTERFACE(ICamera, data, reply);
             reply->writeInt32(previewEnabled());
             return NO_ERROR;
         } break;
+        case RECORDING_ENABLED: {
+            LOGV("RECORDING_ENABLED");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(recordingEnabled());
+            return NO_ERROR;
+        } break;
         case AUTO_FOCUS: {
             LOGV("AUTO_FOCUS");
             CHECK_INTERFACE(ICamera, data, reply);
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index c5d6d52..4bec9d2 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -28,9 +28,10 @@
     SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
     RAW_CALLBACK,
     JPEG_CALLBACK,
-    FRAME_CALLBACK,
+    PREVIEW_CALLBACK,
     ERROR_CALLBACK,
-    AUTOFOCUS_CALLBACK
+    AUTOFOCUS_CALLBACK,
+    RECORDING_CALLBACK,
 };
 
 class BpCameraClient: public BpInterface<ICameraClient>
@@ -70,14 +71,24 @@
         remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    // callback from camera service to app with video frame data
-    void frameCallback(const sp<IMemory>& frame)
+    // callback from camera service to app with preview frame data
+    void previewCallback(const sp<IMemory>& frame)
     {
-        LOGV("frameCallback");
+        LOGV("previewCallback");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
         data.writeStrongBinder(frame->asBinder());
-        remote()->transact(FRAME_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+        remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    // callback from camera service to app with recording frame data
+    void recordingCallback(const sp<IMemory>& frame)
+    {
+        LOGV("recordingCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeStrongBinder(frame->asBinder());
+        remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
     // callback from camera service to app to report error
@@ -135,11 +146,18 @@
             jpegCallback(picture);
             return NO_ERROR;
         } break;
-        case FRAME_CALLBACK: {
-            LOGV("FRAME_CALLBACK");
+        case PREVIEW_CALLBACK: {
+            LOGV("PREVIEW_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
-            frameCallback(frame);
+            previewCallback(frame);
+            return NO_ERROR;
+        } break;
+        case RECORDING_CALLBACK: {
+            LOGV("RECORDING_CALLBACK");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
+            recordingCallback(frame);
             return NO_ERROR;
         } break;
         case ERROR_CALLBACK: {
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 6f3cd47..d5e9f81 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -27,12 +27,33 @@
 
 namespace android {
 
-enum {
-    REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
-    UNREGISTER_BUFFERS,
-    POST_BUFFER, // one-way transaction
-    CREATE_OVERLAY,
-};
+ISurface::BufferHeap::BufferHeap() 
+    : w(0), h(0), hor_stride(0), ver_stride(0), format(0),
+    transform(0), flags(0) 
+{     
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+        int32_t hor_stride, int32_t ver_stride,
+        PixelFormat format, const sp<IMemoryHeap>& heap)
+    : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+      format(format), transform(0), flags(0), heap(heap) 
+{
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+        int32_t hor_stride, int32_t ver_stride,
+        PixelFormat format, uint32_t transform, uint32_t flags,
+        const sp<IMemoryHeap>& heap)
+        : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+          format(format), transform(transform), flags(flags), heap(heap) 
+{
+}
+
+
+ISurface::BufferHeap::~BufferHeap() 
+{     
+}
 
 class BpSurface : public BpInterface<ISurface>
 {
@@ -42,17 +63,18 @@
     {
     }
 
-    virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
-            PixelFormat format, const sp<IMemoryHeap>& heap)
+    virtual status_t registerBuffers(const BufferHeap& buffers)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
-        data.writeInt32(w);
-        data.writeInt32(h);
-        data.writeInt32(hstride);
-        data.writeInt32(vstride);
-        data.writeInt32(format);
-        data.writeStrongBinder(heap->asBinder());
+        data.writeInt32(buffers.w);
+        data.writeInt32(buffers.h);
+        data.writeInt32(buffers.hor_stride);
+        data.writeInt32(buffers.ver_stride);
+        data.writeInt32(buffers.format);
+        data.writeInt32(buffers.transform);
+        data.writeInt32(buffers.flags);
+        data.writeStrongBinder(buffers.heap->asBinder());
         remote()->transact(REGISTER_BUFFERS, data, &reply);
         status_t result = reply.readInt32();
         return result;
@@ -102,13 +124,16 @@
     switch(code) {
         case REGISTER_BUFFERS: {
             CHECK_INTERFACE(ISurface, data, reply);
-            int w = data.readInt32();
-            int h = data.readInt32();
-            int hs= data.readInt32();
-            int vs= data.readInt32();
-            PixelFormat f = data.readInt32();
-            sp<IMemoryHeap> heap(interface_cast<IMemoryHeap>(data.readStrongBinder()));
-            status_t err = registerBuffers(w,h,hs,vs,f,heap);
+            BufferHeap buffer;
+            buffer.w = data.readInt32();
+            buffer.h = data.readInt32();
+            buffer.hor_stride = data.readInt32();
+            buffer.ver_stride= data.readInt32();
+            buffer.format = data.readInt32();
+            buffer.transform = data.readInt32();
+            buffer.flags = data.readInt32();
+            buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
+            status_t err = registerBuffers(buffer);
             reply->writeInt32(err);
             return NO_ERROR;
         } break;
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index 605c8ae..b65ed97 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -19,6 +19,18 @@
 
 namespace android {
 
+size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
+{
+    size_t size;
+    if ((components >= 6) && (components <= 8)) {
+        // YCbCr formats are differents.
+        size = (width * bitsPerPixel)>>3;
+    } else {
+        size = width * bytesPerPixel;
+    }
+    return size;
+}
+
 ssize_t bytesPerPixel(PixelFormat format)
 {
     PixelFormatInfo info;
@@ -47,7 +59,25 @@
     if (!valid) {
         return BAD_INDEX;
     }
-
+    
+    #define COMPONENT(name) \ 
+        case GGL_##name: info->components = PixelFormatInfo::name; break;
+    
+    switch (i->components) {
+        COMPONENT(ALPHA)
+        COMPONENT(RGB)
+        COMPONENT(RGBA)
+        COMPONENT(LUMINANCE)
+        COMPONENT(LUMINANCE_ALPHA)
+        COMPONENT(Y_CB_CR_SP)
+        COMPONENT(Y_CB_CR_P)
+        COMPONENT(Y_CB_CR_I)
+        default:
+            return BAD_INDEX;
+    }
+    
+    #undef COMPONENT
+    
     info->format = format;
     info->bytesPerPixel = i->size;
     info->bitsPerPixel  = i->bitsPerPixel;
@@ -59,6 +89,7 @@
     info->l_green       = i->gl;
     info->h_blue        = i->bh;
     info->l_blue        = i->bl;
+
     return NO_ERROR;
 }
 
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 26fb22a..2fdaa71 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -120,13 +120,18 @@
         char name[];
     };
 
-    const char *map_to_name(uint64_t pc, const char* def) {
+    const char *map_to_name(uint64_t pc, const char* def, uint64_t* start) {
         mapinfo* mi = getMapInfoList();
         while(mi) {
-            if ((pc >= mi->start) && (pc < mi->end))
+            if ((pc >= mi->start) && (pc < mi->end)) {
+                if (start) 
+                    *start = mi->start;
                 return mi->name;
+            }
             mi = mi->next;
         }
+        if (start) 
+            *start = 0;
         return def;
     }
 
@@ -183,8 +188,15 @@
         }
     }
     
-    static const char *mapAddressToName(const void* pc, const char* def) {
-        return sMapInfo.map_to_name((uint64_t)pc, def);
+    static const char *mapAddressToName(const void* pc, const char* def,
+            void const** start) 
+    {
+        uint64_t s;
+        char const* name = sMapInfo.map_to_name(uint64_t(uintptr_t(pc)), def, &s);
+        if (start) {
+            *start = (void*)s;
+        }
+        return name;
     }
 
 };
@@ -297,8 +309,9 @@
         res.append(name);
         res.append(tmp2);
     } else { 
-        name = MapInfo::mapAddressToName(ip, "<unknown>");
-        snprintf(tmp, 256, "pc %p  %s", ip, name);
+        void const* start = 0;
+        name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
+        snprintf(tmp, 256, "pc %08lx  %s", uintptr_t(ip)-uintptr_t(start), name);
         res.append(tmp);
     }
     res.append("\n");
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
index 2962b25..4225e67 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/utils/Parcel.cpp
@@ -658,15 +658,20 @@
     status_t err;
     err = writeInt32(handle.numFds);
     if (err != NO_ERROR) return err;
-    
+
     err = writeInt32(handle.numInts);
     if (err != NO_ERROR) return err;
-    
+
     for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++)
         err = writeDupFileDescriptor(handle.data[i]);
-    
+
+    if (err != NO_ERROR) {
+        LOGD("write native handle, write dup fd failed");
+        return err;
+    }
+
     err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts);
-    
+
     return err;
 }
 
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 5a09fb4..2ad3bfe 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -176,7 +176,9 @@
 
 void* Res_png_9patch::serialize()
 {
-    void* newData = malloc(serializedSize());
+    // Use calloc since we're going to leave a few holes in the data
+    // and want this to run cleanly under valgrind
+    void* newData = calloc(1, serializedSize());
     serialize(newData);
     return newData;
 }
@@ -1736,7 +1738,7 @@
 }
 
 ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
-        uint32_t* outSpecFlags) const
+        uint32_t* outSpecFlags, ResTable_config* outConfig) const
 {
     if (mError != NO_ERROR) {
         return mError;
@@ -1809,7 +1811,7 @@
             (const Res_value*)(((const uint8_t*)type) + offset);
         ResTable_config thisConfig;
         thisConfig.copyFromDtoH(type->config);
-        
+
         if (outSpecFlags != NULL) {
             if (typeClass->typeSpecFlags != NULL) {
                 *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
@@ -1834,6 +1836,9 @@
         outValue->res0 = bestValue->res0;
         outValue->dataType = bestValue->dataType;
         outValue->data = dtohl(bestValue->data);
+        if (outConfig != NULL) {
+            *outConfig = bestItem;
+        }
         TABLE_NOISY(size_t len;
               printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
                      bestPackage->header->index,
@@ -3147,13 +3152,13 @@
             const char16_t* pos = s;
             while (pos < end && !failed) {
                 const char16_t* start = pos;
-                end++;
+                pos++;
                 while (pos < end && *pos != '|') {
                     pos++;
                 }
-				//printf("Looking for: %s\n", String8(start, pos-start).string());
+                //printf("Looking for: %s\n", String8(start, pos-start).string());
                 const bag_entry* bagi = bag;
-				ssize_t i;
+                ssize_t i;
                 for (i=0; i<cnt; i++, bagi++) {
                     if (!Res_INTERNALID(bagi->map.name.ident)) {
                         //printf("Trying attr #%08x\n", bagi->map.name.ident);
@@ -3181,7 +3186,7 @@
             }
             unlockBag(bag);
             if (!failed) {
-				//printf("Final flag value: 0x%lx\n", outValue->data);
+                //printf("Final flag value: 0x%lx\n", outValue->data);
                 return true;
             }
         }
@@ -3189,7 +3194,7 @@
 
         if (fromAccessor) {
             if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
-				//printf("Final flag value: 0x%lx\n", outValue->data);
+                //printf("Final flag value: 0x%lx\n", outValue->data);
                 return true;
             }
         }
@@ -3484,7 +3489,7 @@
         
         ResTable_config thisConfig;
         thisConfig.copyFromDtoH(thisType->config);
-        
+
         TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
                             "orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
                            entryIndex, typeIndex+1, dtohl(thisType->config.size),
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index 1f81cad..aef67f2 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -244,7 +244,6 @@
 
 // ---------------------------------------------------------------------------
 
-// Note: not dealing with generating surrogate pairs.
 static char16_t* allocFromUTF8(const char* in, size_t len)
 {
     if (len == 0) return getEmptyString();
@@ -255,7 +254,10 @@
     
     while (p < end) {
         chars++;
-        p += utf8_char_len(*p);
+        int utf8len = utf8_char_len(*p);
+        uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, utf8len);
+        if (codepoint > 0xFFFF) chars++; // this will be a surrogate pair in utf16
+        p += utf8len;
     }
     
     SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
@@ -265,7 +267,19 @@
         char16_t* d = str;
         while (p < end) {
             size_t len = utf8_char_len(*p);
-            *d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len);
+            uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, len);
+
+            // Convert the UTF32 codepoint to one or more UTF16 codepoints
+            if (codepoint <= 0xFFFF) {
+                // Single UTF16 character
+                *d++ = (char16_t) codepoint;
+            } else {
+                // Multiple UTF16 characters with surrogates
+                codepoint = codepoint - 0x10000;
+                *d++ = (char16_t) ((codepoint >> 10) + 0xD800);
+                *d++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+            }
+
             p += len;
         }
         *d = 0;
@@ -388,7 +402,7 @@
         ->editResize((len+1)*sizeof(char16_t));
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
-        memcpy(str, other, len*sizeof(char16_t));
+        memmove(str, other, len*sizeof(char16_t));
         str[len] = 0;
         mString = str;
         return NO_ERROR;
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index ab843f6..c50d343 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -317,8 +317,10 @@
         ->editResize(myLen+otherLen+1);
     if (buf) {
         char* str = (char*)buf->data();
-        memcpy(str+myLen, other, otherLen+1);
         mString = str;
+        str += myLen;
+        memcpy(str, other, otherLen);
+        str[otherLen] = '\0';
         return NO_ERROR;
     }
     return NO_MEMORY;
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 74271ba..9287c0b 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+// #define LOG_NDEBUG 0
 #define LOG_TAG "libutils.threads"
 
 #include <utils/threads.h>
@@ -838,146 +839,6 @@
 #error "condition variables not supported on this platform"
 #endif
 
-
-/*
- * ===========================================================================
- *      ReadWriteLock class
- * ===========================================================================
- */
-
-#if 0
-#pragma mark -
-#pragma mark ReadWriteLock
-#endif
-
-/*
- * Add a reader.  Readers are nice.  They share.
- */
-void ReadWriteLock::lockForRead()
-{
-    mLock.lock();
-    while (mNumWriters > 0) {
-        LOG(LOG_DEBUG, "thread", "+++ lockForRead: waiting\n");
-        mReadWaiter.wait(mLock);
-    }
-    assert(mNumWriters == 0);
-    mNumReaders++;
-#if defined(PRINT_RENDER_TIMES)
-    if (mNumReaders == 1)
-        mDebugTimer.start();
-#endif
-    mLock.unlock();
-}
-
-/*
- * Try to add a reader.  If it doesn't work right away, return "false".
- */
-bool ReadWriteLock::tryLockForRead()
-{
-    mLock.lock();
-    if (mNumWriters > 0) {
-        mLock.unlock();
-        return false;
-    }
-    assert(mNumWriters == 0);
-    mNumReaders++;
-#if defined(PRINT_RENDER_TIMES)
-    if (mNumReaders == 1)
-        mDebugTimer.start();
-#endif
-    mLock.unlock();
-    return true;
-}
-
-/*
- * Remove a reader.
- */
-void ReadWriteLock::unlockForRead()
-{
-    mLock.lock();
-    if (mNumReaders == 0) {
-        LOG(LOG_WARN, "thread",
-            "WARNING: unlockForRead requested, but not locked\n");
-        return;
-    }
-    assert(mNumReaders > 0);
-    assert(mNumWriters == 0);
-    mNumReaders--;
-    if (mNumReaders == 0) {           // last reader?
-#if defined(PRINT_RENDER_TIMES)
-        mDebugTimer.stop();
-        printf(" rdlk held %.3f msec\n",
-            (double) mDebugTimer.durationUsecs() / 1000.0);
-#endif
-        //printf("+++ signaling writers (if any)\n");
-        mWriteWaiter.signal();      // wake one writer (if any)
-    }
-    mLock.unlock();
-}
-
-/*
- * Add a writer.  This requires exclusive access to the object.
- */
-void ReadWriteLock::lockForWrite()
-{
-    mLock.lock();
-    while (mNumReaders > 0 || mNumWriters > 0) {
-        LOG(LOG_DEBUG, "thread", "+++ lockForWrite: waiting\n");
-        mWriteWaiter.wait(mLock);
-    }
-    assert(mNumReaders == 0);
-    assert(mNumWriters == 0);
-    mNumWriters++;
-#if defined(PRINT_RENDER_TIMES)
-    mDebugTimer.start();
-#endif
-    mLock.unlock();
-}
-
-/*
- * Try to add a writer.  If it doesn't work right away, return "false".
- */
-bool ReadWriteLock::tryLockForWrite()
-{
-    mLock.lock();
-    if (mNumReaders > 0 || mNumWriters > 0) {
-        mLock.unlock();
-        return false;
-    }
-    assert(mNumReaders == 0);
-    assert(mNumWriters == 0);
-    mNumWriters++;
-#if defined(PRINT_RENDER_TIMES)
-    mDebugTimer.start();
-#endif
-    mLock.unlock();
-    return true;
-}
-
-/*
- * Remove a writer.
- */
-void ReadWriteLock::unlockForWrite()
-{
-    mLock.lock();
-    if (mNumWriters == 0) {
-        LOG(LOG_WARN, "thread",
-            "WARNING: unlockForWrite requested, but not locked\n");
-        return;
-    }
-    assert(mNumWriters == 1);
-    mNumWriters--;
-#if defined(PRINT_RENDER_TIMES)
-    mDebugTimer.stop();
-    //printf(" wrlk held %.3f msec\n",
-    //    (double) mDebugTimer.durationUsecs() / 1000.0);
-#endif
-    // mWriteWaiter.signal();       // should other writers get first dibs?
-    //printf("+++ signaling readers (if any)\n");
-    mReadWaiter.broadcast();        // wake all readers (if any)
-    mLock.unlock();
-}
-
 // ----------------------------------------------------------------------------
 
 #if 0
@@ -1025,6 +886,8 @@
     // hold a strong reference on ourself
     mHoldSelf = this;
 
+    mRunning = true;
+
     bool res;
     if (mCanCallJava) {
         res = createThreadEtc(_threadLoop,
@@ -1038,14 +901,16 @@
         mStatus = UNKNOWN_ERROR;   // something happened!
         mRunning = false;
         mThread = thread_id_t(-1);
+        mHoldSelf.clear();  // "this" may have gone away after this.
+
+        return UNKNOWN_ERROR;
     }
     
-    if (mStatus < 0) {
-        // something happened, don't leak
-        mHoldSelf.clear();
-    }
-    
-    return mStatus;
+    // Do not refer to mStatus here: The thread is already running (may, in fact
+    // already have exited with a valid mStatus result). The NO_ERROR indication
+    // here merely indicates successfully starting the thread and does not
+    // imply successful termination/execution.
+    return NO_ERROR;
 }
 
 int Thread::_threadLoop(void* user)
@@ -1055,20 +920,32 @@
     wp<Thread> weak(strong);
     self->mHoldSelf.clear();
 
-    // we're about to run...
-    self->mStatus = self->readyToRun();
-    if (self->mStatus!=NO_ERROR || self->mExitPending) {
-        // pretend the thread never started...
-        self->mExitPending = false;
-        self->mRunning = false;
-        return 0;
-    }
-    
-    // thread is running now
-    self->mRunning = true;
+    bool first = true;
 
     do {
-        bool result = self->threadLoop();
+        bool result;
+        if (first) {
+            first = false;
+            self->mStatus = self->readyToRun();
+            result = (self->mStatus == NO_ERROR);
+
+            if (result && !self->mExitPending) {
+                // Binder threads (and maybe others) rely on threadLoop
+                // running at least once after a successful ::readyToRun()
+                // (unless, of course, the thread has already been asked to exit
+                // at that point).
+                // This is because threads are essentially used like this:
+                //   (new ThreadSubclass())->run();
+                // The caller therefore does not retain a strong reference to
+                // the thread and the thread would simply disappear after the
+                // successful ::readyToRun() call instead of entering the
+                // threadLoop at least once.
+                result = self->threadLoop();
+            }
+        } else {
+            result = self->threadLoop();
+        }
+
         if (result == false || self->mExitPending) {
             self->mExitPending = true;
             self->mLock.lock();
@@ -1095,24 +972,23 @@
 
 status_t Thread::requestExitAndWait()
 {
-    if (mStatus == OK) {
+    if (mThread == getThreadId()) {
+        LOGW(
+        "Thread (this=%p): don't call waitForExit() from this "
+        "Thread object's thread. It's a guaranteed deadlock!",
+        this);
 
-        if (mThread == getThreadId()) {
-            LOGW(
-            "Thread (this=%p): don't call waitForExit() from this "
-            "Thread object's thread. It's a guaranteed deadlock!",
-            this);
-            return WOULD_BLOCK;
-        }
-        
-        requestExit();
-
-        Mutex::Autolock _l(mLock);
-        while (mRunning == true) {
-            mThreadExitedCondition.wait(mLock);
-        }
-        mExitPending = false;
+        return WOULD_BLOCK;
     }
+    
+    requestExit();
+
+    Mutex::Autolock _l(mLock);
+    while (mRunning == true) {
+        mThreadExitedCondition.wait(mLock);
+    }
+    mExitPending = false;
+
     return mStatus;
 }