auto import from //branches/cupcake/...@137873
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 440778d..57a53bd 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -119,7 +119,8 @@
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
         mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
-        mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false)
+        mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
+        mRouteRestoreTime(0), mMusicMuteSaved(false)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
     mAudioHardware = AudioHardwareInterface::create();
@@ -166,7 +167,7 @@
         setMasterMute(false);
 
         // Start record thread
-        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
         if (mAudioRecordThread != 0) {
             mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
         }
@@ -242,6 +243,12 @@
             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;
@@ -482,7 +489,11 @@
         if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
             enableA2dp = true;
         }
-        setA2dpEnabled_l(enableA2dp);
+        if (mA2dpDisableCount > 0) {
+            mA2dpSuppressed = enableA2dp;
+        } else {
+            setA2dpEnabled_l(enableA2dp);
+        }
         LOGV("setOutput done\n");
     }
 #endif
@@ -798,9 +809,9 @@
                 if (--mForcedSpeakerCount == 0) {
                     mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
                 }
-                LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);            
+                LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
             } else {
-                LOGE("mForcedSpeakerCount is already zero");            
+                LOGE("mForcedSpeakerCount is already zero");
             }
         }
         break;
@@ -825,6 +836,41 @@
     }
 }
 
+#ifdef WITH_A2DP
+void AudioFlinger::handleStreamDisablesA2dp(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mA2dpDisableCount++ == 0) {
+                if (mA2dpEnabled) {
+                    setA2dpEnabled_l(false);
+                    mA2dpSuppressed = true;
+                }
+            }
+            LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            AutoMutex lock(mHardwareLock);
+            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
 
 // ----------------------------------------------------------------------------
 
@@ -1455,6 +1501,11 @@
         if (streamForcedToSpeaker(track->type())) {
             mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
         }        
+#ifdef WITH_A2DP
+        if (streamDisablesA2dp(track->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_ADDED);
+        }
+#endif
     }
 }
 
@@ -1472,6 +1523,11 @@
         if (streamForcedToSpeaker(track->type())) {
             mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
         }
+#ifdef WITH_A2DP
+        if (streamDisablesA2dp(track->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_REMOVED);
+        }
+#endif
     }
 }
 
@@ -2311,8 +2367,10 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
+            const sp<AudioFlinger>& audioFlinger) :
     mAudioHardware(audioHardware),
+    mAudioFlinger(audioFlinger),
     mActive(false)
 {
 }
@@ -2417,6 +2475,12 @@
 
     mRecordTrack = recordTrack;
 
+#ifdef WITH_A2DP
+    if (streamDisablesA2dp(recordTrack->type())) {
+        mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_ADDED);
+    }
+#endif
+
     // signal thread to start
     LOGV("Signal record thread");
     mWaitWorkCV.signal();
@@ -2429,6 +2493,11 @@
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
     if (mActive && (recordTrack == mRecordTrack.get())) {
+#ifdef WITH_A2DP
+        if (streamDisablesA2dp(recordTrack->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_REMOVED);
+        }
+#endif
         mActive = false;
         mStopped.wait(mLock);
     }
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index c505336..596e7f3 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -165,6 +165,7 @@
     void                    checkA2dpEnabledChange_l();
 #endif
     static bool             streamForcedToSpeaker(int streamType);
+    static bool             streamDisablesA2dp(int streamType);
     
     // Management of forced route to speaker for certain track types.
     enum force_speaker_command {
@@ -174,6 +175,9 @@
         FORCE_ROUTE_RESTORE
     };
     void                    handleForcedSpeakerRoute(int command);
+#ifdef WITH_A2DP
+    void                    handleStreamDisablesA2dp(int command);
+#endif
 
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -576,7 +580,7 @@
     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; }
@@ -590,6 +594,7 @@
     private:
                 AudioRecordThread();
                 AudioHardwareInterface              *mAudioHardware;
+                sp<AudioFlinger>                    mAudioFlinger;
                 sp<MixerThread::RecordTrack>        mRecordTrack;
                 Mutex                               mLock;
                 Condition                           mWaitWorkCV;
@@ -620,6 +625,10 @@
     mutable     int                                 mHardwareStatus;
                 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;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 900282a..d915a84 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -179,6 +179,7 @@
         mDeferReleaseConsole(false),
         mFreezeDisplay(false),
         mFreezeCount(0),
+        mFreezeDisplayTime(0),
         mDebugRegion(0),
         mDebugCpu(0),
         mDebugFps(0),
@@ -467,16 +468,24 @@
     // wait for something to do
     if (UNLIKELY(isFrozen())) {
         // wait 5 seconds
-        int err = mSyncObject.wait(ms2ns(5000));
+        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();
     }
 }
@@ -671,13 +680,6 @@
         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
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index ae0ae1e..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;