Merge change 24998 into eclair

* changes:
  Add Panasonic KX-TH112 to blacklist.
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index 24496bb..35f4846 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -265,6 +265,11 @@
     return NO_ERROR;
 }
 
+status_t CameraHardwareStub::cancelAutoFocus()
+{
+    return NO_ERROR;
+}
+
 /*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
 {
     CameraHardwareStub *c = (CameraHardwareStub *)cookie;
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 000906a..f957fa8 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -51,6 +51,7 @@
     virtual void        releaseRecordingFrame(const sp<IMemory>& mem);
 
     virtual status_t    autoFocus();
+    virtual status_t    cancelAutoFocus();
     virtual status_t    takePicture();
     virtual status_t    cancelPicture();
     virtual status_t    dump(int fd, const Vector<String16>& args) const;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index f425f6b..bab7d08 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -798,7 +798,6 @@
 }
 #endif
 
-// take a picture - image is returned in callback
 status_t CameraService::Client::autoFocus()
 {
     LOGD("autoFocus (pid %d)", getCallingPid());
@@ -815,6 +814,22 @@
     return mHardware->autoFocus();
 }
 
+status_t CameraService::Client::cancelAutoFocus()
+{
+    LOGD("cancelAutoFocus (pid %d)", getCallingPid());
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+
+    if (mHardware == 0) {
+        LOGE("mHardware is NULL, returning.");
+        return INVALID_OPERATION;
+    }
+
+    return mHardware->cancelAutoFocus();
+}
+
 // take a picture - image is returned in callback
 status_t CameraService::Client::takePicture()
 {
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index f8c7216..0a909cf 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -110,6 +110,9 @@
         // auto focus
         virtual status_t        autoFocus();
 
+        // cancel auto focus
+        virtual status_t        cancelAutoFocus();
+
         // take a picture - returns an IMemory (ref-counted mmap)
         virtual status_t        takePicture();
 
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index ae6e255..9ceb8fd 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -143,6 +143,9 @@
             // autoFocus - status returned from callback
             status_t    autoFocus();
 
+            // cancel auto focus
+            status_t    cancelAutoFocus();
+
             // take a picture - picture returned from callback
             status_t    takePicture();
 
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 535f70e..5fbb7d8 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -161,6 +161,14 @@
     virtual status_t    autoFocus() = 0;
 
     /**
+     * Cancels auto-focus function. If the auto-focus is still in progress,
+     * this function will cancel it. Whether the auto-focus is in progress
+     * or not, this function will return the focus position to the default.
+     * If the camera does not support auto-focus, this is a no-op.
+     */
+    virtual status_t    cancelAutoFocus() = 0;
+
+    /**
      * Take a picture.
      */
     virtual status_t    takePicture() = 0;
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
index 1df7914..7595e36 100644
--- a/include/ui/ICamera.h
+++ b/include/ui/ICamera.h
@@ -76,6 +76,9 @@
     // auto focus
     virtual status_t        autoFocus() = 0;
 
+    // cancel auto focus
+    virtual status_t        cancelAutoFocus() = 0;
+
     // take a picture
     virtual status_t        takePicture() = 0;
 
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 790a655..4f7500f 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -677,8 +677,8 @@
     }
 }
 
-void AudioFlinger::audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2) {
-    Mutex::Autolock _l(mLock);
+// audioConfigChanged_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2) {
     int ioHandle = 0;
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -700,7 +700,7 @@
         size_t size = mNotificationClients.size();
         for (size_t i = 0; i < size; i++) {
             sp<IBinder> binder = mNotificationClients.itemAt(i);
-            LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
+            LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get());
             sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
             client->ioConfigChanged(event, ioHandle, param2);
         }
@@ -803,8 +803,8 @@
         LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
         ConfigEvent *configEvent = mConfigEvents[0];
         mConfigEvents.removeAt(0);
-        // release mLock because audioConfigChanged() will call
-        // Audioflinger::audioConfigChanged() which locks AudioFlinger mLock thus creating
+        // release mLock because audioConfigChanged() will lock AudioFlinger mLock
+        // before calling Audioflinger::audioConfigChanged_l() thus creating
         // potential cross deadlock between AudioFlinger::mLock and mLock
         mLock.unlock();
         audioConfigChanged(configEvent->mEvent, configEvent->mParam);
@@ -1118,7 +1118,8 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged(event, this, param2);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    mAudioFlinger->audioConfigChanged_l(event, this, param2);
 }
 
 void AudioFlinger::PlaybackThread::readOutputParameters()
@@ -1239,7 +1240,7 @@
                 // active tracks were late. Sleep a little bit to give
                 // them another chance. If we're too late, write 0s to audio
                 // hardware to avoid underrun.
-                if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                if (mBytesWritten == 0 || sleepTime < kMaxBufferRecoveryInUsecs) {
                     usleep(kBufferRecoveryInUsecs);
                 } else {
                     memset (curBuf, 0, mixBufferSize);
@@ -1272,8 +1273,6 @@
     if (!mStandby) {
         mOutput->standby();
     }
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
 
     LOGV("MixerThread %p exiting", this);
     return false;
@@ -1741,7 +1740,8 @@
                 standbyTime = systemTime() + kStandbyTimeInNsecs;
             } else {
                 sleepTime += kBufferRecoveryInUsecs;
-                if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                if (mBytesWritten == 0 || !AudioSystem::isLinearPCM(mFormat) ||
+                    sleepTime < kMaxBufferRecoveryInUsecs) {
                     usleep(kBufferRecoveryInUsecs);
                 } else {
                     memset (mMixBuffer, 0, mFrameCount * mFrameSize);
@@ -1771,8 +1771,6 @@
     if (!mStandby) {
         mOutput->standby();
     }
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
 
     LOGV("DirectOutputThread %p exiting", this);
     return false;
@@ -1964,9 +1962,6 @@
         }
     }
 
-    sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
-    processConfigEvents();
-
     return false;
 }
 
@@ -3046,9 +3041,6 @@
     }
     mActiveTrack.clear();
 
-    sendConfigEvent(AudioSystem::INPUT_CLOSED);
-    processConfigEvents();
-
     LOGV("RecordThread %p exiting", this);
     return false;
 }
@@ -3233,7 +3225,8 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged(event, this, param2);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    mAudioFlinger->audioConfigChanged_l(event, this, param2);
 }
 
 void AudioFlinger::RecordThread::readInputParameters()
@@ -3378,6 +3371,8 @@
                 }
             }
         }
+        void *param2 = 0;
+        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, thread, param2);
         mPlaybackThreads.removeItem(output);
     }
     thread->exit();
@@ -3497,6 +3492,8 @@
         }
 
         LOGV("closeInput() %d", input);
+        void *param2 = 0;
+        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, thread, param2);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 65c148e..7a6641f 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -616,7 +616,7 @@
               MixerThread *checkMixerThread_l(int output) const;
               RecordThread *checkRecordThread_l(int input) const;
               float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
-              void audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2);
+              void audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2);
 
     friend class AudioBuffer;
 
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 12a7725..0c6d340 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -242,6 +242,14 @@
     return c->autoFocus();
 }
 
+status_t Camera::cancelAutoFocus()
+{
+    LOGV("cancelAutoFocus");
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->cancelAutoFocus();
+}
+
 // take a picture
 status_t Camera::takePicture()
 {
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 805c2ca..fd7e084 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -32,6 +32,7 @@
     START_PREVIEW,
     STOP_PREVIEW,
     AUTO_FOCUS,
+    CANCEL_AUTO_FOCUS,
     TAKE_PICTURE,
     SET_PARAMETERS,
     GET_PARAMETERS,
@@ -162,6 +163,17 @@
         return ret;
     }
 
+    // cancel focus
+    status_t cancelAutoFocus()
+    {
+        LOGV("cancelAutoFocus");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(CANCEL_AUTO_FOCUS, data, &reply);
+        status_t ret = reply.readInt32();
+        return ret;
+    }
+
     // take a picture - returns an IMemory (ref-counted mmap)
     status_t takePicture()
     {
@@ -294,6 +306,12 @@
             reply->writeInt32(autoFocus());
             return NO_ERROR;
         } break;
+        case CANCEL_AUTO_FOCUS: {
+            LOGV("CANCEL_AUTO_FOCUS");
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(cancelAutoFocus());
+            return NO_ERROR;
+        } break;
         case TAKE_PICTURE: {
             LOGV("TAKE_PICTURE");
             CHECK_INTERFACE(ICamera, data, reply);