Merge "mediaplayer: support dynamic playback rate"
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index e5e4e90..3dbf75e 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -526,7 +526,7 @@
         !strcmp(format, PIXEL_FORMAT_RGBA8888) ?
             HAL_PIXEL_FORMAT_RGBA_8888 :    // RGB8888
         !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
-            HAL_PIXEL_FORMAT_RAW_SENSOR :   // Raw sensor data
+            HAL_PIXEL_FORMAT_RAW16 :   // Raw sensor data
         -1;
 }
 
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index fc3e437..a75cb48 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -209,6 +209,20 @@
         return status;
     }
 
+    virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+            const sp<IBinder>& clientBinder)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeString16(cameraId);
+        data.writeInt32(enabled ? 1 : 0);
+        data.writeStrongBinder(clientBinder);
+        remote()->transact(BnCameraService::SET_TORCH_MODE, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        return reply.readInt32();
+    }
+
     // connect to camera service (pro client)
     virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId,
                                 const String16 &clientPackageName, int clientUid,
@@ -490,6 +504,16 @@
             }
             return NO_ERROR;
         } break;
+        case SET_TORCH_MODE: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            String16 cameraId = data.readString16();
+            bool enabled = data.readInt32() != 0 ? true : false;
+            const sp<IBinder> clientBinder = data.readStrongBinder();
+            status_t status = setTorchMode(cameraId, enabled, clientBinder);
+            reply->writeNoException();
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp
index b2f1729..90a8bc2 100644
--- a/camera/ICameraServiceListener.cpp
+++ b/camera/ICameraServiceListener.cpp
@@ -29,6 +29,7 @@
 namespace {
     enum {
         STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+        TORCH_STATUS_CHANGED,
     };
 }; // namespace anonymous
 
@@ -54,8 +55,21 @@
                            data,
                            &reply,
                            IBinder::FLAG_ONEWAY);
+    }
 
-        reply.readExceptionCode();
+    virtual void onTorchStatusChanged(TorchStatus status, const String16 &cameraId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                              ICameraServiceListener::getInterfaceDescriptor());
+
+        data.writeInt32(static_cast<int32_t>(status));
+        data.writeString16(cameraId);
+
+        remote()->transact(TORCH_STATUS_CHANGED,
+                           data,
+                           &reply,
+                           IBinder::FLAG_ONEWAY);
     }
 };
 
@@ -75,7 +89,16 @@
             int32_t cameraId = data.readInt32();
 
             onStatusChanged(status, cameraId);
-            reply->writeNoException();
+
+            return NO_ERROR;
+        } break;
+        case TORCH_STATUS_CHANGED: {
+            CHECK_INTERFACE(ICameraServiceListener, data, reply);
+
+            TorchStatus status = static_cast<TorchStatus>(data.readInt32());
+            String16 cameraId = data.readString16();
+
+            onTorchStatusChanged(status, cameraId);
 
             return NO_ERROR;
         } break;
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 1f5867a..24b2327 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -89,6 +89,12 @@
         mCondition.broadcast();
     }
 
+    void onTorchStatusChanged(TorchStatus status, const String16& cameraId) {
+        dout << "On torch status changed: 0x" << std::hex
+             << (unsigned int) status << " cameraId " << cameraId.string()
+             << std::endl;
+    }
+
     status_t waitForStatusChange(Status& newStatus) {
         Mutex::Autolock al(mMutex);
 
@@ -469,7 +475,7 @@
         CMP_STR(NV16, YCbCr_422_SP);
         CMP_STR(NV21, YCrCb_420_SP);
         CMP_STR(YUY2, YCbCr_422_I);
-        CMP_STR(RAW,  RAW_SENSOR);
+        CMP_STR(RAW,  RAW16);
         CMP_STR(RGBA, RGBA_8888);
 
         std::cerr << "Unknown format string " << str << std::endl;
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index f7f06bb..cc41efe 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -53,6 +53,7 @@
         GET_LEGACY_PARAMETERS,
         SUPPORTS_CAMERA_API,
         CONNECT_LEGACY,
+        SET_TORCH_MODE,
     };
 
     enum {
@@ -142,6 +143,12 @@
             int clientUid,
             /*out*/
             sp<ICamera>& device) = 0;
+
+    /**
+     * Turn on or off a camera's torch mode.
+     */
+    virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+            const sp<IBinder>& clientBinder) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
index 0a0e43a..9e8b912 100644
--- a/include/camera/ICameraServiceListener.h
+++ b/include/camera/ICameraServiceListener.h
@@ -66,9 +66,33 @@
         STATUS_UNKNOWN          = 0xFFFFFFFF,
     };
 
+    /**
+     * The torch mode status of a camera.
+     *
+     * Initial status will be transmitted with onTorchStatusChanged immediately
+     * after this listener is added to the service listener list.
+     */
+    enum TorchStatus {
+        // The camera's torch mode has become available to use via
+        // setTorchMode().
+        TORCH_STATUS_AVAILABLE      = TORCH_MODE_STATUS_AVAILABLE,
+        // The camera's torch mode has become not available to use via
+        // setTorchMode().
+        TORCH_STATUS_NOT_AVAILABLE  = TORCH_MODE_STATUS_RESOURCE_BUSY,
+        // The camera's torch mode has been turned off by setTorchMode().
+        TORCH_STATUS_OFF            = TORCH_MODE_STATUS_OFF,
+        // The camera's torch mode has been turned on by setTorchMode().
+        TORCH_STATUS_ON             = 0x80000000,
+
+        // Use to initialize variables only
+        TORCH_STATUS_UNKNOWN        = 0xFFFFFFFF,
+    };
+
     DECLARE_META_INTERFACE(CameraServiceListener);
 
     virtual void onStatusChanged(Status status, int32_t cameraId) = 0;
+
+    virtual void onTorchStatusChanged(TorchStatus status, const String16& cameraId) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 899b324..a195fe8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -26,6 +26,7 @@
 
 namespace android {
 
+class AMessage;
 class MediaBuffer;
 class MediaSource;
 class MetaData;
@@ -48,6 +49,7 @@
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     void beginBox(const char *fourcc);
+    void beginBox(uint32_t id);
     void writeInt8(int8_t x);
     void writeInt16(int16_t x);
     void writeInt32(int32_t x);
@@ -62,6 +64,7 @@
     int32_t getTimeScale() const { return mTimeScale; }
 
     status_t setGeoData(int latitudex10000, int longitudex10000);
+    status_t setCaptureRate(float captureFps);
     virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
     virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
 
@@ -88,6 +91,7 @@
     off64_t mFreeBoxOffset;
     bool mStreamableFile;
     off64_t mEstimatedMoovBoxSize;
+    off64_t mMoovExtraSize;
     uint32_t mInterleaveDurationUs;
     int32_t mTimeScale;
     int64_t mStartTimestampUs;
@@ -102,6 +106,8 @@
 
     List<off64_t> mBoxes;
 
+    sp<AMessage> mMetaKeys;
+
     void setStartTimestampUs(int64_t timeUs);
     int64_t getStartTimestampUs();  // Not const
     status_t startTracks(MetaData *params);
@@ -195,6 +201,12 @@
     void writeGeoDataBox();
     void writeLatitude(int degreex10000);
     void writeLongitude(int degreex10000);
+
+    void addDeviceMeta();
+    void writeHdlr();
+    void writeKeys();
+    void writeIlst();
+    void writeMetaBox();
     void sendSessionSummary();
     void release();
     status_t reset();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 2551040..55763f0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -75,6 +75,7 @@
       mAudioSource(AUDIO_SOURCE_CNT),
       mVideoSource(VIDEO_SOURCE_LIST_END),
       mCaptureTimeLapse(false),
+      mCaptureFps(0.0f),
       mStarted(false) {
 
     ALOGV("Constructor");
@@ -263,6 +264,31 @@
     return OK;
 }
 
+// Attempt to parse an float literal optionally surrounded by whitespace,
+// returns true on success, false otherwise.
+static bool safe_strtof(const char *s, float *val) {
+    char *end;
+
+    // It is lame, but according to man page, we have to set errno to 0
+    // before calling strtof().
+    errno = 0;
+    *val = strtof(s, &end);
+
+    if (end == s || errno == ERANGE) {
+        return false;
+    }
+
+    // Skip trailing whitespace
+    while (isspace(*end)) {
+        ++end;
+    }
+
+    // For a successful return, the string must contain nothing but a valid
+    // float literal optionally surrounded by whitespace.
+
+    return *end == '\0';
+}
+
 // Attempt to parse an int64 literal optionally surrounded by whitespace,
 // returns true on success, false otherwise.
 static bool safe_strtoi64(const char *s, int64_t *val) {
@@ -546,8 +572,10 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
-    ALOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
+status_t StagefrightRecorder::setParamTimeLapseFps(float fps) {
+    ALOGV("setParamTimeLapseFps: %.2f", fps);
+
+    int64_t timeUs = (int64_t) (1000000.0 / fps + 0.5f);
 
     // Not allowing time more than a day
     if (timeUs <= 0 || timeUs > 86400*1E6) {
@@ -555,6 +583,7 @@
         return BAD_VALUE;
     }
 
+    mCaptureFps = fps;
     mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
     return OK;
 }
@@ -682,11 +711,10 @@
         if (safe_strtoi32(value.string(), &timeLapseEnable)) {
             return setParamTimeLapseEnable(timeLapseEnable);
         }
-    } else if (key == "time-between-time-lapse-frame-capture") {
-        int64_t timeBetweenTimeLapseFrameCaptureUs;
-        if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureUs)) {
-            return setParamTimeBetweenTimeLapseFrameCapture(
-                    timeBetweenTimeLapseFrameCaptureUs);
+    } else if (key == "time-lapse-fps") {
+        float fps;
+        if (safe_strtof(value.string(), &fps)) {
+            return setParamTimeLapseFps(fps);
         }
     } else {
         ALOGE("setParameter: failed to find key %s", key.string());
@@ -1581,10 +1609,11 @@
 
     status_t err = OK;
     sp<MediaWriter> writer;
+    sp<MPEG4Writer> mp4writer;
     if (mOutputFormat == OUTPUT_FORMAT_WEBM) {
         writer = new WebmWriter(mOutputFd);
     } else {
-        writer = new MPEG4Writer(mOutputFd);
+        writer = mp4writer = new MPEG4Writer(mOutputFd);
     }
 
     if (mVideoSource < VIDEO_SOURCE_LIST_END) {
@@ -1617,13 +1646,15 @@
             mTotalBitRate += mAudioBitRate;
         }
 
+        if (mCaptureTimeLapse) {
+            mp4writer->setCaptureRate(mCaptureFps);
+        }
+
         if (mInterleaveDurationUs > 0) {
-            reinterpret_cast<MPEG4Writer *>(writer.get())->
-                setInterleaveDuration(mInterleaveDurationUs);
+            mp4writer->setInterleaveDuration(mInterleaveDurationUs);
         }
         if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
-            reinterpret_cast<MPEG4Writer *>(writer.get())->
-                setGeoData(mLatitudex10000, mLongitudex10000);
+            mp4writer->setGeoData(mLatitudex10000, mLongitudex10000);
         }
     }
     if (mMaxFileDurationUs != 0) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index b5a49d3..f34c229 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -109,6 +109,7 @@
     int32_t mTotalBitRate;
 
     bool mCaptureTimeLapse;
+    float mCaptureFps;
     int64_t mTimeBetweenTimeLapseFrameCaptureUs;
     sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
 
@@ -155,7 +156,7 @@
     status_t setParamAudioSamplingRate(int32_t sampleRate);
     status_t setParamAudioTimeScale(int32_t timeScale);
     status_t setParamTimeLapseEnable(int32_t timeLapseEnable);
-    status_t setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs);
+    status_t setParamTimeLapseFps(float fps);
     status_t setParamVideoEncodingBitRate(int32_t bitRate);
     status_t setParamVideoIFramesInterval(int32_t seconds);
     status_t setParamVideoEncoderProfile(int32_t profile);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 9b446b8..cbc5e0d 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -130,23 +130,37 @@
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<MediaExtractor> extractor;
+    String8 mimeType;
+    float confidence;
+    sp<AMessage> dummy;
+    bool isWidevineStreaming = false;
 
     CHECK(mDataSource != NULL);
 
     if (mIsWidevine) {
-        String8 mimeType;
-        float confidence;
-        sp<AMessage> dummy;
-        bool success;
-
-        success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
-        if (!success
-                || strcasecmp(
+        isWidevineStreaming = SniffWVM(
+                mDataSource, &mimeType, &confidence, &dummy);
+        if (!isWidevineStreaming ||
+                strcasecmp(
                     mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
             ALOGE("unsupported widevine mime: %s", mimeType.string());
             return UNKNOWN_ERROR;
         }
+    } else if (mIsStreaming) {
+        if (mSniffedMIME.empty()) {
+            if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
+                return UNKNOWN_ERROR;
+            }
+            mSniffedMIME = mimeType.string();
+        }
+        isWidevineStreaming = !strcasecmp(
+                mSniffedMIME.c_str(), MEDIA_MIMETYPE_CONTAINER_WVM);
+    }
 
+    if (isWidevineStreaming) {
+        // we don't want cached source for widevine streaming.
+        mCachedSource.clear();
+        mDataSource = mHttpSource;
         mWVMExtractor = new WVMExtractor(mDataSource);
         mWVMExtractor->setAdaptiveStreamingMode(true);
         if (mUIDValid) {
@@ -181,14 +195,6 @@
             if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
                     && !strncasecmp(fileMime, "video/wvm", 9)) {
                 mIsWidevine = true;
-                if (!mUri.empty()) {
-                  // streaming, but the app forgot to specify widevine:// url
-                  mWVMExtractor = static_cast<WVMExtractor *>(extractor.get());
-                  mWVMExtractor->setAdaptiveStreamingMode(true);
-                  if (mUIDValid) {
-                    mWVMExtractor->setUID(mUID);
-                  }
-                }
             }
         }
     }
@@ -656,10 +662,10 @@
     int32_t kbps = 0;
     status_t err = UNKNOWN_ERROR;
 
-    if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    } else if (mWVMExtractor != NULL) {
+    if (mWVMExtractor != NULL) {
         err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
+    } else if (mCachedSource != NULL) {
+        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
     }
 
     if (err == OK) {
@@ -681,7 +687,13 @@
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
-    if (mCachedSource != NULL) {
+    ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
+            "WVMExtractor and NuCachedSource both present");
+
+    if (mWVMExtractor != NULL) {
+        cachedDurationUs =
+                mWVMExtractor->getCachedDurationUs(&finalStatus);
+    } else if (mCachedSource != NULL) {
         cachedDataRemaining =
                 mCachedSource->approxDataRemaining(&finalStatus);
 
@@ -697,9 +709,6 @@
                 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
             }
         }
-    } else if (mWVMExtractor != NULL) {
-        cachedDurationUs
-            = mWVMExtractor->getCachedDurationUs(&finalStatus);
     }
 
     if (finalStatus != OK) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index beb6f20..6f6e362 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -29,6 +29,7 @@
 #include <utils/Log.h>
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
@@ -62,6 +63,14 @@
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
 static const int64_t kInitialDelayTimeUs     = 700000LL;
 
+static const char kMetaKey_Model[]      = "com.android.model";
+static const char kMetaKey_Version[]    = "com.android.version";
+static const char kMetaKey_Build[]      = "com.android.build";
+static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
+
+/* uncomment to include model and build in meta */
+//#define SHOW_MODEL_BUILD 1
+
 class MPEG4Writer::Track {
 public:
     Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
@@ -358,11 +367,14 @@
       mOffset(0),
       mMdatOffset(0),
       mEstimatedMoovBoxSize(0),
+      mMoovExtraSize(0),
       mInterleaveDurationUs(1000000),
       mLatitudex10000(0),
       mLongitudex10000(0),
       mAreGeoTagsAvailable(false),
+      mMetaKeys(new AMessage()),
       mStartTimeOffsetMs(-1) {
+    addDeviceMeta();
 }
 
 MPEG4Writer::~MPEG4Writer() {
@@ -482,6 +494,34 @@
     return OK;
 }
 
+void MPEG4Writer::addDeviceMeta() {
+    // add device info and estimate space in 'moov'
+    char val[PROPERTY_VALUE_MAX];
+    size_t n;
+    // meta size is estimated by adding up the following:
+    // - meta header structures, which occur only once (total 66 bytes)
+    // - size for each key, which consists of a fixed header (32 bytes),
+    //   plus key length and data length.
+    mMoovExtraSize += 66;
+    if (property_get("ro.build.version.release", val, NULL)
+            && (n = strlen(val)) > 0) {
+        mMetaKeys->setString(kMetaKey_Version, val, n + 1);
+        mMoovExtraSize += sizeof(kMetaKey_Version) + n + 32;
+    }
+#ifdef SHOW_MODEL_BUILD
+    if (property_get("ro.product.model", val, NULL)
+            && (n = strlen(val)) > 0) {
+        mMetaKeys->setString(kMetaKey_Model, val, n + 1);
+        mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32;
+    }
+    if (property_get("ro.build.display.id", val, NULL)
+            && (n = strlen(val)) > 0) {
+        mMetaKeys->setString(kMetaKey_Build, val, n + 1);
+        mMoovExtraSize += sizeof(kMetaKey_Build) + n + 32;
+    }
+#endif
+}
+
 int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
     // This implementation is highly experimental/heurisitic.
     //
@@ -535,6 +575,9 @@
         size = MAX_MOOV_BOX_SIZE;
     }
 
+    // Account for the extra stuff (Geo, meta keys, etc.)
+    size += mMoovExtraSize;
+
     ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the"
          " estimated moov size %" PRId64 " bytes",
          mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
@@ -946,6 +989,7 @@
     if (mAreGeoTagsAvailable) {
         writeUdtaBox();
     }
+    writeMetaBox();
     int32_t id = 1;
     for (List<Track *>::iterator it = mTracks.begin();
         it != mTracks.end(); ++it, ++id) {
@@ -1115,6 +1159,14 @@
     return bytes;
 }
 
+void MPEG4Writer::beginBox(uint32_t id) {
+    mBoxes.push_back(mWriteMoovBoxToMemory?
+            mMoovBoxBufferOffset: mOffset);
+
+    writeInt32(0);
+    writeInt32(id);
+}
+
 void MPEG4Writer::beginBox(const char *fourcc) {
     CHECK_EQ(strlen(fourcc), 4);
 
@@ -1239,6 +1291,18 @@
     mLatitudex10000 = latitudex10000;
     mLongitudex10000 = longitudex10000;
     mAreGeoTagsAvailable = true;
+    mMoovExtraSize += 30;
+    return OK;
+}
+
+status_t MPEG4Writer::setCaptureRate(float captureFps) {
+    if (captureFps <= 0.0f) {
+        return BAD_VALUE;
+    }
+
+    mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps);
+    mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
+
     return OK;
 }
 
@@ -3070,6 +3134,103 @@
     endBox();
 }
 
+void MPEG4Writer::writeHdlr() {
+    beginBox("hdlr");
+    writeInt32(0); // Version, Flags
+    writeInt32(0); // Predefined
+    writeFourcc("mdta");
+    writeInt32(0); // Reserved[0]
+    writeInt32(0); // Reserved[1]
+    writeInt32(0); // Reserved[2]
+    writeInt8(0);  // Name (empty)
+    endBox();
+}
+
+void MPEG4Writer::writeKeys() {
+    size_t count = mMetaKeys->countEntries();
+
+    beginBox("keys");
+    writeInt32(0);     // Version, Flags
+    writeInt32(count); // Entry_count
+    for (size_t i = 0; i < count; i++) {
+        AMessage::Type type;
+        const char *key = mMetaKeys->getEntryNameAt(i, &type);
+        size_t n = strlen(key);
+        writeInt32(n + 8);
+        writeFourcc("mdta");
+        write(key, n); // write without the \0
+    }
+    endBox();
+}
+
+void MPEG4Writer::writeIlst() {
+    size_t count = mMetaKeys->countEntries();
+
+    beginBox("ilst");
+    for (size_t i = 0; i < count; i++) {
+        beginBox(i + 1); // key id (1-based)
+        beginBox("data");
+        AMessage::Type type;
+        const char *key = mMetaKeys->getEntryNameAt(i, &type);
+        switch (type) {
+            case AMessage::kTypeString:
+            {
+                AString val;
+                CHECK(mMetaKeys->findString(key, &val));
+                writeInt32(1); // type = UTF8
+                writeInt32(0); // default country/language
+                write(val.c_str(), strlen(val.c_str())); // write without \0
+                break;
+            }
+
+            case AMessage::kTypeFloat:
+            {
+                float val;
+                CHECK(mMetaKeys->findFloat(key, &val));
+                writeInt32(23); // type = float32
+                writeInt32(0);  // default country/language
+                writeInt32(*reinterpret_cast<int32_t *>(&val));
+                break;
+            }
+
+            case AMessage::kTypeInt32:
+            {
+                int32_t val;
+                CHECK(mMetaKeys->findInt32(key, &val));
+                writeInt32(67); // type = signed int32
+                writeInt32(0);  // default country/language
+                writeInt32(val);
+                break;
+            }
+
+            default:
+            {
+                ALOGW("Unsupported key type, writing 0 instead");
+                writeInt32(77); // type = unsigned int32
+                writeInt32(0);  // default country/language
+                writeInt32(0);
+                break;
+            }
+        }
+        endBox(); // data
+        endBox(); // key id
+    }
+    endBox(); // ilst
+}
+
+void MPEG4Writer::writeMetaBox() {
+    size_t count = mMetaKeys->countEntries();
+    if (count == 0) {
+        return;
+    }
+
+    beginBox("meta");
+    writeHdlr();
+    writeKeys();
+    writeIlst();
+    endBox();
+}
+
 /*
  * Geodata is stored according to ISO-6709 standard.
  */
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
index 4debc48..bd01a1a 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
@@ -34,6 +34,9 @@
     params->nVersion.s.nStep = 0;
 }
 
+// Microsoft WAV GSM encoding packs two GSM frames into 65 bytes.
+static const int kMSGSMFrameSize = 65;
+
 SoftGSM::SoftGSM(
         const char *name,
         const OMX_CALLBACKTYPE *callbacks,
@@ -64,7 +67,7 @@
     def.eDir = OMX_DirInput;
     def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
-    def.nBufferSize = sizeof(gsm_frame);
+    def.nBufferSize = 1024 / kMSGSMFrameSize * kMSGSMFrameSize;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
@@ -207,8 +210,8 @@
             mSignalledError = true;
         }
 
-        if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) {
-            ALOGE("input buffer not multiple of 65 (%d).", inHeader->nFilledLen);
+        if(((inHeader->nFilledLen / kMSGSMFrameSize) * kMSGSMFrameSize) != inHeader->nFilledLen) {
+            ALOGE("input buffer not multiple of %d (%d).", kMSGSMFrameSize, inHeader->nFilledLen);
             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
             mSignalledError = true;
         }
@@ -258,6 +261,25 @@
     return ret;
 }
 
+void SoftGSM::onPortFlushCompleted(OMX_U32 portIndex) {
+    if (portIndex == 0) {
+        gsm_destroy(mGsm);
+        mGsm = gsm_create();
+        int msopt = 1;
+        gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
+    }
+}
+
+void SoftGSM::onReset() {
+    gsm_destroy(mGsm);
+    mGsm = gsm_create();
+    int msopt = 1;
+    gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
+    mSignalledError = false;
+}
+
+
+
 
 }  // namespace android
 
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.h b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
index 8ab6116..0303dea 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.h
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
@@ -43,6 +43,9 @@
 
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onReset();
+
 private:
     enum {
         kNumBuffers = 4,
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index dfb5e59..2d3a25a 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -33,7 +33,6 @@
 struct LiveDataSource;
 struct M3UParser;
 struct PlaylistFetcher;
-struct Parcel;
 
 struct LiveSession : public AHandler {
     enum Flags {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index bf59460..4779d6a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -158,7 +158,7 @@
     switch (portIndex) {
         case kPortIndexInput:  return "Input";
         case kPortIndexOutput: return "Output";
-        case ~0:               return "All";
+        case ~0U:              return "All";
         default:               return "port";
     }
 }
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index f029333..642ff82 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -77,8 +77,10 @@
 LOCAL_SRC_FILES += \
     AudioWatchdog.cpp        \
     FastCapture.cpp          \
+    FastCaptureDumpState.cpp \
     FastCaptureState.cpp     \
     FastMixer.cpp            \
+    FastMixerDumpState.cpp   \
     FastMixerState.cpp       \
     FastThread.cpp           \
     FastThreadDumpState.cpp  \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9ad437a..f3780a9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -826,14 +826,20 @@
     if (ret != NO_ERROR) {
         return false;
     }
-
+    bool mute = true;
     bool state = AUDIO_MODE_INVALID;
     AutoMutex lock(mHardwareLock);
-    audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
     mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
-    dev->get_mic_mute(dev, &state);
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+        status_t result = dev->get_mic_mute(dev, &state);
+        if (result == NO_ERROR) {
+            mute = mute && state;
+        }
+    }
     mHardwareStatus = AUDIO_HW_IDLE;
-    return state;
+
+    return mute;
 }
 
 status_t AudioFlinger::setMasterMute(bool muted)
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 0c9b976..1c4f670 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -210,13 +210,4 @@
     }
 }
 
-FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
-    mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
-{
-}
-
-FastCaptureDumpState::~FastCaptureDumpState()
-{
-}
-
 }   // namespace android
diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h
index e61e026..da0fe2f 100644
--- a/services/audioflinger/FastCapture.h
+++ b/services/audioflinger/FastCapture.h
@@ -20,24 +20,12 @@
 #include "FastThread.h"
 #include "StateQueue.h"
 #include "FastCaptureState.h"
-#include "FastThreadDumpState.h"
+#include "FastCaptureDumpState.h"
 
 namespace android {
 
 typedef StateQueue<FastCaptureState> FastCaptureStateQueue;
 
-struct FastCaptureDumpState : FastThreadDumpState {
-    FastCaptureDumpState();
-    /*virtual*/ ~FastCaptureDumpState();
-
-    // FIXME by renaming, could pull up many of these to FastThreadDumpState
-    uint32_t mReadSequence;     // incremented before and after each read()
-    uint32_t mFramesRead;       // total number of frames read successfully
-    uint32_t mReadErrors;       // total number of read() errors
-    uint32_t mSampleRate;
-    size_t   mFrameCount;
-};
-
 class FastCapture : public FastThread {
 
 public:
diff --git a/services/audioflinger/FastCaptureDumpState.cpp b/services/audioflinger/FastCaptureDumpState.cpp
new file mode 100644
index 0000000..00f8da0
--- /dev/null
+++ b/services/audioflinger/FastCaptureDumpState.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "FastCaptureDumpState.h"
+
+namespace android {
+
+FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
+    mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
+{
+}
+
+FastCaptureDumpState::~FastCaptureDumpState()
+{
+}
+
+}   // android
diff --git a/services/audioflinger/FastCaptureDumpState.h b/services/audioflinger/FastCaptureDumpState.h
new file mode 100644
index 0000000..ee99099
--- /dev/null
+++ b/services/audioflinger/FastCaptureDumpState.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 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_AUDIO_FAST_CAPTURE_DUMP_STATE_H
+#define ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H
+
+#include <stdint.h>
+#include "Configuration.h"
+#include "FastThreadDumpState.h"
+
+namespace android {
+
+struct FastCaptureDumpState : FastThreadDumpState {
+    FastCaptureDumpState();
+    /*virtual*/ ~FastCaptureDumpState();
+
+    // FIXME by renaming, could pull up many of these to FastThreadDumpState
+    uint32_t mReadSequence;     // incremented before and after each read()
+    uint32_t mFramesRead;       // total number of frames read successfully
+    uint32_t mReadErrors;       // total number of read() errors
+    uint32_t mSampleRate;
+    size_t   mFrameCount;
+};
+
+}   // android
+
+#endif  // ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 141a79e..67e2e6e 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -27,6 +27,7 @@
 
 #include "Configuration.h"
 #include <time.h>
+#include <utils/Debug.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <system/audio.h>
@@ -456,223 +457,4 @@
     }
 }
 
-FastMixerDumpState::FastMixerDumpState(
-#ifdef FAST_MIXER_STATISTICS
-        uint32_t samplingN
-#endif
-        ) : FastThreadDumpState(),
-    mWriteSequence(0), mFramesWritten(0),
-    mNumTracks(0), mWriteErrors(0),
-    mSampleRate(0), mFrameCount(0),
-    mTrackMask(0)
-{
-#ifdef FAST_MIXER_STATISTICS
-    increaseSamplingN(samplingN);
-#endif
-}
-
-#ifdef FAST_MIXER_STATISTICS
-void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
-{
-    if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
-        return;
-    }
-    uint32_t additional = samplingN - mSamplingN;
-    // sample arrays aren't accessed atomically with respect to the bounds,
-    // so clearing reduces chance for dumpsys to read random uninitialized samples
-    memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
-    memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
-#ifdef CPU_FREQUENCY_STATISTICS
-    memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
-#endif
-    mSamplingN = samplingN;
-}
-#endif
-
-FastMixerDumpState::~FastMixerDumpState()
-{
-}
-
-// helper function called by qsort()
-static int compare_uint32_t(const void *pa, const void *pb)
-{
-    uint32_t a = *(const uint32_t *)pa;
-    uint32_t b = *(const uint32_t *)pb;
-    if (a < b) {
-        return -1;
-    } else if (a > b) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
-void FastMixerDumpState::dump(int fd) const
-{
-    if (mCommand == FastMixerState::INITIAL) {
-        dprintf(fd, "  FastMixer not initialized\n");
-        return;
-    }
-#define COMMAND_MAX 32
-    char string[COMMAND_MAX];
-    switch (mCommand) {
-    case FastMixerState::INITIAL:
-        strcpy(string, "INITIAL");
-        break;
-    case FastMixerState::HOT_IDLE:
-        strcpy(string, "HOT_IDLE");
-        break;
-    case FastMixerState::COLD_IDLE:
-        strcpy(string, "COLD_IDLE");
-        break;
-    case FastMixerState::EXIT:
-        strcpy(string, "EXIT");
-        break;
-    case FastMixerState::MIX:
-        strcpy(string, "MIX");
-        break;
-    case FastMixerState::WRITE:
-        strcpy(string, "WRITE");
-        break;
-    case FastMixerState::MIX_WRITE:
-        strcpy(string, "MIX_WRITE");
-        break;
-    default:
-        snprintf(string, COMMAND_MAX, "%d", mCommand);
-        break;
-    }
-    double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
-            (mMeasuredWarmupTs.tv_nsec / 1000000.0);
-    double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
-    dprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
-                "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
-                "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
-                "            mixPeriod=%.2f ms\n",
-                 string, mWriteSequence, mFramesWritten,
-                 mNumTracks, mWriteErrors, mUnderruns, mOverruns,
-                 mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
-                 mixPeriodSec * 1e3);
-#ifdef FAST_MIXER_STATISTICS
-    // find the interval of valid samples
-    uint32_t bounds = mBounds;
-    uint32_t newestOpen = bounds & 0xFFFF;
-    uint32_t oldestClosed = bounds >> 16;
-    uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
-    if (n > mSamplingN) {
-        ALOGE("too many samples %u", n);
-        n = mSamplingN;
-    }
-    // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
-    // and adjusted CPU load in MHz normalized for CPU clock frequency
-    CentralTendencyStatistics wall, loadNs;
-#ifdef CPU_FREQUENCY_STATISTICS
-    CentralTendencyStatistics kHz, loadMHz;
-    uint32_t previousCpukHz = 0;
-#endif
-    // Assuming a normal distribution for cycle times, three standard deviations on either side of
-    // the mean account for 99.73% of the population.  So if we take each tail to be 1/1000 of the
-    // sample set, we get 99.8% combined, or close to three standard deviations.
-    static const uint32_t kTailDenominator = 1000;
-    uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
-    // loop over all the samples
-    for (uint32_t j = 0; j < n; ++j) {
-        size_t i = oldestClosed++ & (mSamplingN - 1);
-        uint32_t wallNs = mMonotonicNs[i];
-        if (tail != NULL) {
-            tail[j] = wallNs;
-        }
-        wall.sample(wallNs);
-        uint32_t sampleLoadNs = mLoadNs[i];
-        loadNs.sample(sampleLoadNs);
-#ifdef CPU_FREQUENCY_STATISTICS
-        uint32_t sampleCpukHz = mCpukHz[i];
-        // skip bad kHz samples
-        if ((sampleCpukHz & ~0xF) != 0) {
-            kHz.sample(sampleCpukHz >> 4);
-            if (sampleCpukHz == previousCpukHz) {
-                double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
-                double adjMHz = megacycles / mixPeriodSec;  // _not_ wallNs * 1e9
-                loadMHz.sample(adjMHz);
-            }
-        }
-        previousCpukHz = sampleCpukHz;
-#endif
-    }
-    if (n) {
-        dprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
-                    wall.n() * mixPeriodSec);
-        dprintf(fd, "    wall clock time in ms per mix cycle:\n"
-                    "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                    wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
-                    wall.stddev()*1e-6);
-        dprintf(fd, "    raw CPU load in us per mix cycle:\n"
-                    "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                    loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
-                    loadNs.stddev()*1e-3);
-    } else {
-        dprintf(fd, "  No FastMixer statistics available currently\n");
-    }
-#ifdef CPU_FREQUENCY_STATISTICS
-    dprintf(fd, "  CPU clock frequency in MHz:\n"
-                "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
-    dprintf(fd, "  adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
-                "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
-                loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
-#endif
-    if (tail != NULL) {
-        qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
-        // assume same number of tail samples on each side, left and right
-        uint32_t count = n / kTailDenominator;
-        CentralTendencyStatistics left, right;
-        for (uint32_t i = 0; i < count; ++i) {
-            left.sample(tail[i]);
-            right.sample(tail[n - (i + 1)]);
-        }
-        dprintf(fd, "  Distribution of mix cycle times in ms for the tails "
-                    "(> ~3 stddev outliers):\n"
-                    "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
-                    "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                    left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
-                    right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
-                    right.stddev()*1e-6);
-        delete[] tail;
-    }
-#endif
-    // The active track mask and track states are updated non-atomically.
-    // So if we relied on isActive to decide whether to display,
-    // then we might display an obsolete track or omit an active track.
-    // Instead we always display all tracks, with an indication
-    // of whether we think the track is active.
-    uint32_t trackMask = mTrackMask;
-    dprintf(fd, "  Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
-            FastMixerState::kMaxFastTracks, trackMask);
-    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
-    for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
-        bool isActive = trackMask & 1;
-        const FastTrackDump *ftDump = &mTracks[i];
-        const FastTrackUnderruns& underruns = ftDump->mUnderruns;
-        const char *mostRecent;
-        switch (underruns.mBitFields.mMostRecent) {
-        case UNDERRUN_FULL:
-            mostRecent = "full";
-            break;
-        case UNDERRUN_PARTIAL:
-            mostRecent = "partial";
-            break;
-        case UNDERRUN_EMPTY:
-            mostRecent = "empty";
-            break;
-        default:
-            mostRecent = "?";
-            break;
-        }
-        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
-                (underruns.mBitFields.mFull) & UNDERRUN_MASK,
-                (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
-                (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
-                mostRecent, ftDump->mFramesReady);
-    }
-}
-
 }   // namespace android
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index fde8c2b..7649db2 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,11 +17,7 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_H
 #define ANDROID_AUDIO_FAST_MIXER_H
 
-#include <linux/futex.h>
-#include <sys/syscall.h>
-#include <utils/Debug.h>
 #include "FastThread.h"
-#include <utils/Thread.h>
 #include "StateQueue.h"
 #include "FastMixerState.h"
 #include "FastMixerDumpState.h"
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
new file mode 100644
index 0000000..0ddd908
--- /dev/null
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2014 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 "FastMixerDumpState"
+//#define LOG_NDEBUG 0
+
+#include "Configuration.h"
+#ifdef FAST_MIXER_STATISTICS
+#include <cpustats/CentralTendencyStatistics.h>
+#ifdef CPU_FREQUENCY_STATISTICS
+#include <cpustats/ThreadCpuUsage.h>
+#endif
+#endif
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include "FastMixerDumpState.h"
+
+namespace android {
+
+FastMixerDumpState::FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+        uint32_t samplingN
+#endif
+        ) : FastThreadDumpState(),
+    mWriteSequence(0), mFramesWritten(0),
+    mNumTracks(0), mWriteErrors(0),
+    mSampleRate(0), mFrameCount(0),
+    mTrackMask(0)
+{
+#ifdef FAST_MIXER_STATISTICS
+    increaseSamplingN(samplingN);
+#endif
+}
+
+#ifdef FAST_MIXER_STATISTICS
+void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
+{
+    if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
+        return;
+    }
+    uint32_t additional = samplingN - mSamplingN;
+    // sample arrays aren't accessed atomically with respect to the bounds,
+    // so clearing reduces chance for dumpsys to read random uninitialized samples
+    memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
+    memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
+#ifdef CPU_FREQUENCY_STATISTICS
+    memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
+#endif
+    mSamplingN = samplingN;
+}
+#endif
+
+FastMixerDumpState::~FastMixerDumpState()
+{
+}
+
+// helper function called by qsort()
+static int compare_uint32_t(const void *pa, const void *pb)
+{
+    uint32_t a = *(const uint32_t *)pa;
+    uint32_t b = *(const uint32_t *)pb;
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+void FastMixerDumpState::dump(int fd) const
+{
+    if (mCommand == FastMixerState::INITIAL) {
+        dprintf(fd, "  FastMixer not initialized\n");
+        return;
+    }
+#define COMMAND_MAX 32
+    char string[COMMAND_MAX];
+    switch (mCommand) {
+    case FastMixerState::INITIAL:
+        strcpy(string, "INITIAL");
+        break;
+    case FastMixerState::HOT_IDLE:
+        strcpy(string, "HOT_IDLE");
+        break;
+    case FastMixerState::COLD_IDLE:
+        strcpy(string, "COLD_IDLE");
+        break;
+    case FastMixerState::EXIT:
+        strcpy(string, "EXIT");
+        break;
+    case FastMixerState::MIX:
+        strcpy(string, "MIX");
+        break;
+    case FastMixerState::WRITE:
+        strcpy(string, "WRITE");
+        break;
+    case FastMixerState::MIX_WRITE:
+        strcpy(string, "MIX_WRITE");
+        break;
+    default:
+        snprintf(string, COMMAND_MAX, "%d", mCommand);
+        break;
+    }
+    double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
+            (mMeasuredWarmupTs.tv_nsec / 1000000.0);
+    double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
+    dprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+                "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+                "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
+                "            mixPeriod=%.2f ms\n",
+                 string, mWriteSequence, mFramesWritten,
+                 mNumTracks, mWriteErrors, mUnderruns, mOverruns,
+                 mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
+                 mixPeriodSec * 1e3);
+#ifdef FAST_MIXER_STATISTICS
+    // find the interval of valid samples
+    uint32_t bounds = mBounds;
+    uint32_t newestOpen = bounds & 0xFFFF;
+    uint32_t oldestClosed = bounds >> 16;
+    uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
+    if (n > mSamplingN) {
+        ALOGE("too many samples %u", n);
+        n = mSamplingN;
+    }
+    // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
+    // and adjusted CPU load in MHz normalized for CPU clock frequency
+    CentralTendencyStatistics wall, loadNs;
+#ifdef CPU_FREQUENCY_STATISTICS
+    CentralTendencyStatistics kHz, loadMHz;
+    uint32_t previousCpukHz = 0;
+#endif
+    // Assuming a normal distribution for cycle times, three standard deviations on either side of
+    // the mean account for 99.73% of the population.  So if we take each tail to be 1/1000 of the
+    // sample set, we get 99.8% combined, or close to three standard deviations.
+    static const uint32_t kTailDenominator = 1000;
+    uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
+    // loop over all the samples
+    for (uint32_t j = 0; j < n; ++j) {
+        size_t i = oldestClosed++ & (mSamplingN - 1);
+        uint32_t wallNs = mMonotonicNs[i];
+        if (tail != NULL) {
+            tail[j] = wallNs;
+        }
+        wall.sample(wallNs);
+        uint32_t sampleLoadNs = mLoadNs[i];
+        loadNs.sample(sampleLoadNs);
+#ifdef CPU_FREQUENCY_STATISTICS
+        uint32_t sampleCpukHz = mCpukHz[i];
+        // skip bad kHz samples
+        if ((sampleCpukHz & ~0xF) != 0) {
+            kHz.sample(sampleCpukHz >> 4);
+            if (sampleCpukHz == previousCpukHz) {
+                double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
+                double adjMHz = megacycles / mixPeriodSec;  // _not_ wallNs * 1e9
+                loadMHz.sample(adjMHz);
+            }
+        }
+        previousCpukHz = sampleCpukHz;
+#endif
+    }
+    if (n) {
+        dprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
+                    wall.n() * mixPeriodSec);
+        dprintf(fd, "    wall clock time in ms per mix cycle:\n"
+                    "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+                    wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
+                    wall.stddev()*1e-6);
+        dprintf(fd, "    raw CPU load in us per mix cycle:\n"
+                    "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+                    loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
+                    loadNs.stddev()*1e-3);
+    } else {
+        dprintf(fd, "  No FastMixer statistics available currently\n");
+    }
+#ifdef CPU_FREQUENCY_STATISTICS
+    dprintf(fd, "  CPU clock frequency in MHz:\n"
+                "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+                kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+    dprintf(fd, "  adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
+                "    mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
+                loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+#endif
+    if (tail != NULL) {
+        qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
+        // assume same number of tail samples on each side, left and right
+        uint32_t count = n / kTailDenominator;
+        CentralTendencyStatistics left, right;
+        for (uint32_t i = 0; i < count; ++i) {
+            left.sample(tail[i]);
+            right.sample(tail[n - (i + 1)]);
+        }
+        dprintf(fd, "  Distribution of mix cycle times in ms for the tails "
+                    "(> ~3 stddev outliers):\n"
+                    "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
+                    "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+                    left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
+                    right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
+                    right.stddev()*1e-6);
+        delete[] tail;
+    }
+#endif
+    // The active track mask and track states are updated non-atomically.
+    // So if we relied on isActive to decide whether to display,
+    // then we might display an obsolete track or omit an active track.
+    // Instead we always display all tracks, with an indication
+    // of whether we think the track is active.
+    uint32_t trackMask = mTrackMask;
+    dprintf(fd, "  Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+            FastMixerState::kMaxFastTracks, trackMask);
+    dprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
+    for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
+        bool isActive = trackMask & 1;
+        const FastTrackDump *ftDump = &mTracks[i];
+        const FastTrackUnderruns& underruns = ftDump->mUnderruns;
+        const char *mostRecent;
+        switch (underruns.mBitFields.mMostRecent) {
+        case UNDERRUN_FULL:
+            mostRecent = "full";
+            break;
+        case UNDERRUN_PARTIAL:
+            mostRecent = "partial";
+            break;
+        case UNDERRUN_EMPTY:
+            mostRecent = "empty";
+            break;
+        default:
+            mostRecent = "?";
+            break;
+        }
+        dprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
+                (underruns.mBitFields.mFull) & UNDERRUN_MASK,
+                (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
+                (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
+                mostRecent, ftDump->mFramesReady);
+    }
+}
+
+}   // android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 1ae191c..f8354dd 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
 #define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
 
+#include <stdint.h>
 #include "Configuration.h"
 #include "FastThreadDumpState.h"
+#include "FastMixerState.h"
 
 namespace android {
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 15dd408..384bd25 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -23,7 +23,9 @@
 #include "Configuration.h"
 #include <math.h>
 #include <fcntl.h>
+#include <linux/futex.h>
 #include <sys/stat.h>
+#include <sys/syscall.h>
 #include <cutils/properties.h>
 #include <media/AudioParameter.h>
 #include <media/AudioResamplerPublic.h>
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 7757ea2..78cec31 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -20,6 +20,7 @@
 //#define LOG_NDEBUG 0
 
 #include "Configuration.h"
+#include <linux/futex.h>
 #include <math.h>
 #include <sys/syscall.h>
 #include <utils/Log.h>
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index de9551d..5d6423a 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -23,6 +23,7 @@
 LOCAL_SRC_FILES:=               \
     CameraService.cpp \
     CameraDeviceFactory.cpp \
+    CameraFlashlight.cpp \
     common/Camera2ClientBase.cpp \
     common/CameraDeviceBase.cpp \
     common/CameraModule.cpp \
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
new file mode 100644
index 0000000..00a70eb
--- /dev/null
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2015 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 "CameraFlashlight"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <cutils/properties.h>
+
+#include "camera/CameraMetadata.h"
+#include "CameraFlashlight.h"
+#include "gui/IGraphicBufferConsumer.h"
+#include "gui/BufferQueue.h"
+#include "camera/camera2/CaptureRequest.h"
+#include "CameraDeviceFactory.h"
+
+
+namespace android {
+
+CameraFlashlight::CameraFlashlight(CameraModule& cameraModule,
+        const camera_module_callbacks_t& callbacks) :
+        mCameraModule(&cameraModule),
+        mCallbacks(&callbacks) {
+}
+
+CameraFlashlight::~CameraFlashlight() {
+}
+
+status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
+    ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
+            cameraId.string());
+    if (mFlashControl != NULL) {
+        return INVALID_OPERATION;
+    }
+
+    status_t res = OK;
+
+    if (mCameraModule->getRawModule()->module_api_version >=
+            CAMERA_MODULE_API_VERSION_2_4) {
+        mFlashControl = new FlashControl(*mCameraModule, *mCallbacks);
+        if (mFlashControl == NULL) {
+            ALOGV("%s: cannot create flash control for module api v2.4+",
+                     __FUNCTION__);
+            return NO_MEMORY;
+        }
+    } else {
+        uint32_t deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+
+        if (mCameraModule->getRawModule()->module_api_version >=
+                CAMERA_MODULE_API_VERSION_2_0) {
+            camera_info info;
+            res = mCameraModule->getCameraInfo(
+                    atoi(String8(cameraId).string()), &info);
+            if (res) {
+                ALOGV("%s: failed to get camera info for camera %s",
+                        __FUNCTION__, cameraId.string());
+                return res;
+            }
+            deviceVersion = info.device_version;
+        }
+
+        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+            CameraDeviceClientFlashControl *flashControl =
+                    new CameraDeviceClientFlashControl(*mCameraModule,
+                                                       *mCallbacks);
+            if (!flashControl) {
+                return NO_MEMORY;
+            }
+
+            mFlashControl = flashControl;
+        }
+        else {
+            // todo: implement for device api 1
+            return INVALID_OPERATION;
+        }
+    }
+
+    return OK;
+}
+
+status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) {
+    if (!mCameraModule) {
+        return NO_INIT;
+    }
+
+    ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
+            cameraId.string(), enabled);
+
+    status_t res = OK;
+    Mutex::Autolock l(mLock);
+
+    if (mFlashControl == NULL) {
+        res = createFlashlightControl(cameraId);
+        if (res) {
+            return res;
+        }
+        res =  mFlashControl->setTorchMode(cameraId, enabled);
+        return res;
+    }
+
+    // if flash control already exists, turning on torch mode may fail if it's
+    // tied to another camera device for module v2.3 and below.
+    res = mFlashControl->setTorchMode(cameraId, enabled);
+    if (res == BAD_INDEX) {
+        // flash control is tied to another camera device, need to close it and
+        // try again.
+        mFlashControl.clear();
+        res = createFlashlightControl(cameraId);
+        if (res) {
+            return res;
+        }
+        res = mFlashControl->setTorchMode(cameraId, enabled);
+    }
+
+    return res;
+}
+
+bool CameraFlashlight::hasFlashUnit(const String16& cameraId) {
+    status_t res;
+
+    Mutex::Autolock l(mLock);
+
+    if (mFlashControl == NULL) {
+        res = createFlashlightControl(cameraId);
+        if (res) {
+            ALOGE("%s: failed to create flash control for %s ",
+                    __FUNCTION__, cameraId.string());
+            return false;
+        }
+    }
+
+    bool flashUnit = false;
+
+    // if flash control already exists, querying if a camera device has a flash
+    // unit may fail if it's module v1
+    res = mFlashControl->hasFlashUnit(cameraId, &flashUnit);
+    if (res == BAD_INDEX) {
+        // need to close the flash control before query.
+        mFlashControl.clear();
+        res = createFlashlightControl(cameraId);
+        if (res) {
+            ALOGE("%s: failed to create flash control for %s ", __FUNCTION__,
+                    cameraId.string());
+            return false;
+        }
+        res = mFlashControl->hasFlashUnit(cameraId, &flashUnit);
+        if (res) {
+            flashUnit = false;
+        }
+    }
+
+    return flashUnit;
+}
+
+status_t CameraFlashlight::prepareDeviceOpen() {
+    ALOGV("%s: prepare for device open", __FUNCTION__);
+
+    Mutex::Autolock l(mLock);
+
+    if (mCameraModule && mCameraModule->getRawModule()->module_api_version <
+            CAMERA_MODULE_API_VERSION_2_4) {
+        // framework is going to open a camera device, all flash light control
+        // should be closed for backward compatible support.
+        if (mFlashControl != NULL) {
+            mFlashControl.clear();
+        }
+    }
+
+    return OK;
+}
+
+
+FlashControlBase::~FlashControlBase() {
+}
+
+
+FlashControl::FlashControl(CameraModule& cameraModule,
+        const camera_module_callbacks_t& callbacks) :
+    mCameraModule(&cameraModule) {
+}
+
+FlashControl::~FlashControl() {
+}
+
+status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) {
+    if (!hasFlash) {
+        return BAD_VALUE;
+    }
+
+    *hasFlash = false;
+
+    Mutex::Autolock l(mLock);
+
+    if (!mCameraModule) {
+        return NO_INIT;
+    }
+
+    camera_info info;
+    status_t res = mCameraModule->getCameraInfo(atoi(String8(cameraId).string()),
+            &info);
+    if (res != 0) {
+        return res;
+    }
+
+    CameraMetadata metadata;
+    metadata = info.static_camera_characteristics;
+    camera_metadata_entry flashAvailable =
+            metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+    if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
+        *hasFlash = true;
+    }
+
+    return OK;
+}
+
+status_t FlashControl::setTorchMode(const String16& cameraId, bool enabled) {
+    ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
+            cameraId.string(), enabled);
+
+    Mutex::Autolock l(mLock);
+    if (!mCameraModule) {
+        return NO_INIT;
+    }
+
+    return mCameraModule->setTorchMode(String8(cameraId).string(), enabled);
+}
+
+CameraDeviceClientFlashControl::CameraDeviceClientFlashControl(
+        CameraModule& cameraModule,
+        const camera_module_callbacks_t& callbacks) :
+        mCameraModule(&cameraModule),
+        mCallbacks(&callbacks),
+        mTorchEnabled(false),
+        mMetadata(NULL) {
+}
+
+CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
+    if (mDevice != NULL) {
+        mDevice->flush();
+        mDevice->deleteStream(mStreamId);
+        mDevice.clear();
+    }
+    if (mMetadata) {
+        delete mMetadata;
+    }
+
+    mAnw.clear();
+    mSurfaceTexture.clear();
+    mProducer.clear();
+    mConsumer.clear();
+
+    if (mTorchEnabled) {
+        if (mCallbacks) {
+            ALOGV("%s: notify the framework that torch was turned off",
+                    __FUNCTION__);
+            mCallbacks->torch_mode_status_change(mCallbacks,
+                    String8(mCameraId).string(), TORCH_MODE_STATUS_OFF);
+        }
+    }
+}
+
+status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width,
+        int32_t height) {
+    status_t res;
+    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+
+    mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
+            true, true);
+    if (mSurfaceTexture == NULL) {
+        return NO_MEMORY;
+    }
+
+    int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    res = mSurfaceTexture->setDefaultBufferSize(width, height);
+    if (res) {
+        return res;
+    }
+    res = mSurfaceTexture->setDefaultBufferFormat(format);
+    if (res) {
+        return res;
+    }
+
+    bool useAsync = false;
+    int32_t consumerUsage;
+    res = mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
+    if (res) {
+        return res;
+    }
+
+    if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
+        useAsync = true;
+    }
+
+    mAnw = new Surface(mProducer, useAsync);
+    if (mAnw == NULL) {
+        return NO_MEMORY;
+    }
+    res = mDevice->createStream(mAnw, width, height, format, &mStreamId);
+    if (res) {
+        return res;
+    }
+
+    res = mDevice->configureStreams();
+    if (res) {
+        return res;
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
+        const camera_info& info, int32_t *width, int32_t *height) {
+    if (!width || !height) {
+        return BAD_VALUE;
+    }
+
+    int32_t w = INT32_MAX;
+    int32_t h = 1;
+
+    CameraMetadata metadata;
+    metadata = info.static_camera_characteristics;
+    camera_metadata_entry streamConfigs =
+            metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+    for (size_t i = 0; i < streamConfigs.count; i += 4) {
+        int32_t fmt = streamConfigs.data.i32[i];
+        if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED) {
+            int32_t ww = streamConfigs.data.i32[i + 1];
+            int32_t hh = streamConfigs.data.i32[i + 2];
+
+            if (w* h > ww * hh) {
+                w = ww;
+                h = hh;
+            }
+        }
+    }
+
+    if (w == INT32_MAX) {
+        return NAME_NOT_FOUND;
+    }
+
+    *width = w;
+    *height = h;
+
+    return OK;
+}
+
+status_t CameraDeviceClientFlashControl::connectCameraDevice(
+        const String16& cameraId) {
+    String8 id = String8(cameraId);
+    camera_info info;
+    status_t res = mCameraModule->getCameraInfo(atoi(id.string()), &info);
+    if (res != 0) {
+        ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
+                mCameraId.string());
+        return res;
+    }
+
+    mDevice = CameraDeviceFactory::createDevice(atoi(id.string()));
+    if (mDevice == NULL) {
+        return NO_MEMORY;
+    }
+
+    res = mDevice->initialize(mCameraModule);
+    if (res) {
+        goto fail;
+    }
+
+    int32_t width, height;
+    res = getSmallestSurfaceSize(info, &width, &height);
+    if (res) {
+        return res;
+    }
+    res = initializeSurface(width, height);
+    if (res) {
+        goto fail;
+    }
+
+    mCameraId = cameraId;
+
+    return OK;
+
+fail:
+    mDevice.clear();
+    return res;
+}
+
+
+status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId,
+        bool *hasFlash) {
+    ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__,
+            cameraId.string());
+
+    Mutex::Autolock l(mLock);
+    return hasFlashUnitLocked(cameraId, hasFlash);
+
+}
+
+status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
+        const String16& cameraId, bool *hasFlash) {
+    if (!mCameraModule) {
+        ALOGE("%s: camera module is NULL", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    if (!hasFlash) {
+        return BAD_VALUE;
+    }
+
+    camera_info info;
+    status_t res = mCameraModule->getCameraInfo(
+            atoi(String8(cameraId).string()), &info);
+    if (res != 0) {
+        ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
+                cameraId.string());
+        return res;
+    }
+
+    CameraMetadata metadata;
+    metadata = info.static_camera_characteristics;
+    camera_metadata_entry flashAvailable =
+            metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+    if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
+        *hasFlash = true;
+    }
+
+    return OK;
+}
+
+status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) {
+    status_t res;
+
+    if (mMetadata == NULL) {
+        mMetadata = new CameraMetadata();
+        if (mMetadata == NULL) {
+            return NO_MEMORY;
+        }
+        res = mDevice->createDefaultRequest(
+                CAMERA3_TEMPLATE_PREVIEW, mMetadata);
+        if (res) {
+            return res;
+        }
+    }
+
+    uint8_t torchOn = enabled ? ANDROID_FLASH_MODE_TORCH :
+                                ANDROID_FLASH_MODE_OFF;
+
+    mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1);
+    mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1);
+
+    int32_t requestId = 0;
+    mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1);
+
+    List<const CameraMetadata> metadataRequestList;
+    metadataRequestList.push_back(*mMetadata);
+
+    int64_t lastFrameNumber = 0;
+    res = mDevice->captureList(metadataRequestList, &lastFrameNumber);
+
+    return res;
+}
+
+
+status_t CameraDeviceClientFlashControl::setTorchMode(
+        const String16& cameraId, bool enabled) {
+    bool hasFlash = false;
+
+    Mutex::Autolock l(mLock);
+    status_t res = hasFlashUnitLocked(cameraId, &hasFlash);
+
+    // pre-check
+    if (enabled) {
+        // invalid camera?
+        if (res) {
+            return -EINVAL;
+        }
+        // no flash unit?
+        if (!hasFlash) {
+            return -ENOSYS;
+        }
+        // already opened for a different device?
+        if (mDevice != NULL && cameraId != mCameraId) {
+            return BAD_INDEX;
+        }
+    } else if (mDevice == NULL || cameraId != mCameraId) {
+        // disabling the torch mode of an un-opened or different device.
+        return OK;
+    }
+
+    if (mDevice == NULL) {
+        res = connectCameraDevice(cameraId);
+        if (res) {
+            return res;
+        }
+    }
+
+    res = submitTorchRequest(enabled);
+    if (res) {
+        return res;
+    }
+
+    mTorchEnabled = enabled;
+    return OK;
+}
+
+}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
new file mode 100644
index 0000000..a0de0b0
--- /dev/null
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 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_SERVERS_CAMERA_CAMERAFLASHLIGHT_H
+#define ANDROID_SERVERS_CAMERA_CAMERAFLASHLIGHT_H
+
+#include "hardware/camera_common.h"
+#include "utils/KeyedVector.h"
+#include "gui/GLConsumer.h"
+#include "gui/Surface.h"
+#include "common/CameraDeviceBase.h"
+
+namespace android {
+
+/**
+ * FlashControlBase is a base class for flash control. It defines the functions
+ * that a flash control for each camera module/device version should implement.
+ */
+class FlashControlBase : public virtual VirtualLightRefBase {
+    public:
+        virtual ~FlashControlBase();
+
+        // Whether a camera device has a flash unit. Calling this function may
+        // cause the torch mode to be turned off in HAL v1 devices. If
+        // previously-on torch mode is turned off,
+        // callbacks.torch_mode_status_change() should be invoked.
+        virtual status_t hasFlashUnit(const String16& cameraId,
+                    bool *hasFlash) = 0;
+
+        // set the torch mode to on or off.
+        virtual status_t setTorchMode(const String16& cameraId,
+                    bool enabled) = 0;
+};
+
+/**
+ * CameraFlashlight can be used by camera service to control flashflight.
+ */
+class CameraFlashlight : public virtual VirtualLightRefBase {
+    public:
+        CameraFlashlight(CameraModule& cameraModule,
+                const camera_module_callbacks_t& callbacks);
+        virtual ~CameraFlashlight();
+
+        // set the torch mode to on or off.
+        status_t setTorchMode(const String16& cameraId, bool enabled);
+
+        // Whether a camera device has a flash unit. Calling this function may
+        // cause the torch mode to be turned off in HAL v1 devices.
+        bool hasFlashUnit(const String16& cameraId);
+
+        // Notify CameraFlashlight that camera service is going to open a camera
+        // device. CameraFlashlight will free the resources that may cause the
+        // camera open to fail. Camera service must call this function before
+        // opening a camera device.
+        status_t prepareDeviceOpen();
+
+    private:
+        // create flashlight control based on camera module API and camera
+        // device API versions.
+        status_t createFlashlightControl(const String16& cameraId);
+
+        sp<FlashControlBase> mFlashControl;
+        CameraModule *mCameraModule;
+        const camera_module_callbacks_t *mCallbacks;
+
+        Mutex mLock;
+};
+
+/**
+ * Flash control for camera module v2.4 and above.
+ */
+class FlashControl : public FlashControlBase {
+    public:
+        FlashControl(CameraModule& cameraModule,
+                const camera_module_callbacks_t& callbacks);
+        virtual ~FlashControl();
+
+        // FlashControlBase
+        status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
+        status_t setTorchMode(const String16& cameraId, bool enabled);
+
+    private:
+        CameraModule *mCameraModule;
+
+        Mutex mLock;
+};
+
+/**
+ * Flash control for camera module <= v2.3 and camera HAL v2-v3
+ */
+class CameraDeviceClientFlashControl : public FlashControlBase {
+    public:
+        CameraDeviceClientFlashControl(CameraModule& cameraModule,
+                const camera_module_callbacks_t& callbacks);
+        virtual ~CameraDeviceClientFlashControl();
+
+        // FlashControlBase
+        status_t setTorchMode(const String16& cameraId, bool enabled);
+        status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
+
+    private:
+        // connect to a camera device
+        status_t connectCameraDevice(const String16& cameraId);
+
+        // initialize a surface
+        status_t initializeSurface(int32_t width, int32_t height);
+
+        // submit a request with the given torch mode
+        status_t submitTorchRequest(bool enabled);
+
+        // get the smallest surface size of IMPLEMENTATION_DEFINED
+        status_t getSmallestSurfaceSize(const camera_info& info, int32_t *width,
+                    int32_t *height);
+
+        status_t hasFlashUnitLocked(const String16& cameraId, bool *hasFlash);
+
+        CameraModule *mCameraModule;
+        const camera_module_callbacks_t *mCallbacks;
+        String16 mCameraId;
+        bool mTorchEnabled;
+        CameraMetadata *mMetadata;
+
+        sp<CameraDeviceBase> mDevice;
+
+        sp<IGraphicBufferProducer> mProducer;
+        sp<IGraphicBufferConsumer>  mConsumer;
+        sp<GLConsumer> mSurfaceTexture;
+        sp<ANativeWindow> mAnw;
+        int32_t mStreamId;
+
+        Mutex mLock;
+};
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c1b7806..d65ac21 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -87,6 +87,38 @@
         camera_id,
         new_status);
 }
+
+static void torch_mode_status_change(
+        const struct camera_module_callbacks* callbacks,
+        const char* camera_id,
+        int new_status) {
+    if (!callbacks || !camera_id) {
+        ALOGE("%s invalid parameters. callbacks %p, camera_id %p", __FUNCTION__,
+                callbacks, camera_id);
+    }
+    sp<CameraService> cs = const_cast<CameraService*>(
+                                static_cast<const CameraService*>(callbacks));
+
+    ICameraServiceListener::TorchStatus status;
+    switch (new_status) {
+        case TORCH_MODE_STATUS_AVAILABLE:
+            status = ICameraServiceListener::TORCH_STATUS_AVAILABLE;
+            break;
+        case TORCH_MODE_STATUS_RESOURCE_BUSY:
+            status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+            break;
+        case TORCH_MODE_STATUS_OFF:
+            status = ICameraServiceListener::TORCH_STATUS_OFF;
+            break;
+        default:
+            ALOGE("Unknown torch status %d", new_status);
+            return;
+    }
+
+    cs->onTorchStatusChanged(
+        String16(camera_id),
+        status);
+}
 } // extern "C"
 
 // ----------------------------------------------------------------------------
@@ -96,7 +128,7 @@
 static CameraService *gCameraService;
 
 CameraService::CameraService()
-    :mSoundRef(0), mModule(0)
+    :mSoundRef(0), mModule(0), mFlashlight(0)
 {
     ALOGI("CameraService started (pid=%d)", getpid());
     gCameraService = this;
@@ -106,6 +138,8 @@
     }
 
     this->camera_device_status_change = android::camera_device_status_change;
+    this->torch_mode_status_change = android::torch_mode_status_change;
+
 }
 
 void CameraService::onFirstRef()
@@ -122,6 +156,8 @@
     }
     else {
         mModule = new CameraModule(rawModule);
+        mFlashlight = new CameraFlashlight(*mModule, *this);
+
         const hw_module_t *common = mModule->getRawModule();
         ALOGI("Loaded \"%s\" camera module", common->name);
         mNumberOfCameras = mModule->getNumberOfCameras();
@@ -132,6 +168,12 @@
         }
         for (int i = 0; i < mNumberOfCameras; i++) {
             setCameraFree(i);
+
+            String16 cameraName = String16(String8::format("%d", i));
+            if (mFlashlight->hasFlashUnit(cameraName)) {
+                mTorchStatusMap.add(cameraName,
+                        ICameraServiceListener::TORCH_STATUS_AVAILABLE);
+            }
         }
 
         if (common->module_api_version >= CAMERA_MODULE_API_VERSION_2_1) {
@@ -226,6 +268,37 @@
 
 }
 
+void CameraService::onTorchStatusChanged(const String16& cameraId,
+        ICameraServiceListener::TorchStatus newStatus) {
+    Mutex::Autolock al(mTorchStatusMutex);
+    onTorchStatusChangedLocked(cameraId, newStatus);
+}
+
+void CameraService::onTorchStatusChangedLocked(const String16& cameraId,
+        ICameraServiceListener::TorchStatus newStatus) {
+    ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
+            __FUNCTION__, cameraId.string(), newStatus);
+
+    if (getTorchStatusLocked(cameraId) == newStatus) {
+        ALOGE("%s: Torch state transition to the same status 0x%x not allowed",
+              __FUNCTION__, (uint32_t)newStatus);
+        return;
+    }
+
+    status_t res = setTorchStatusLocked(cameraId, newStatus);
+    if (res) {
+        ALOGE("%s: Failed to set the torch status", __FUNCTION__,
+                (uint32_t)newStatus);
+        return;
+    }
+
+    Vector<sp<ICameraServiceListener> >::const_iterator it;
+    for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+        (*it)->onTorchStatusChanged(newStatus, cameraId);
+    }
+}
+
+
 int32_t CameraService::getNumberOfCameras() {
     return mNumberOfCameras;
 }
@@ -680,6 +753,9 @@
         int halVersion,
         bool legacyMode) {
 
+    // give flashlight a chance to close devices if necessary.
+    mFlashlight->prepareDeviceOpen();
+
     int facing = -1;
     int deviceVersion = getDeviceVersion(cameraId, &facing);
 
@@ -856,6 +932,47 @@
     return OK;
 }
 
+status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
+        const sp<IBinder>& clientBinder) {
+    if (enabled && clientBinder == NULL) {
+        ALOGE("%s: torch client binder is NULL", __FUNCTION__);
+        return -ENOSYS;
+    }
+
+    Mutex::Autolock al(mTorchStatusMutex);
+    status_t res = mFlashlight->setTorchMode(cameraId, enabled);
+    if (res) {
+        ALOGE("%s: setting torch mode of camera %s to %d failed", __FUNCTION__,
+                cameraId.string(), enabled);
+        return res;
+    }
+
+    // update the link to client's death
+    ssize_t index = mTorchClientMap.indexOfKey(cameraId);
+    if (enabled) {
+        if (index == NAME_NOT_FOUND) {
+            mTorchClientMap.add(cameraId, clientBinder);
+        } else {
+            const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+            oldBinder->unlinkToDeath(this);
+
+            mTorchClientMap.replaceValueAt(index, clientBinder);
+        }
+        clientBinder->linkToDeath(this);
+    } else if (index != NAME_NOT_FOUND) {
+        sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+        oldBinder->unlinkToDeath(this);
+    }
+
+    // notify the listeners the change.
+    ICameraServiceListener::TorchStatus status = enabled ?
+            ICameraServiceListener::TORCH_STATUS_ON :
+            ICameraServiceListener::TORCH_STATUS_OFF;
+    onTorchStatusChangedLocked(cameraId, status);
+
+    return OK;
+}
+
 status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
                                             const sp<IBinder>& remoteCallback) {
     status_t status = client->initialize(mModule);
@@ -981,6 +1098,9 @@
         int facing = -1;
         int deviceVersion = getDeviceVersion(cameraId, &facing);
 
+        // give flashlight a chance to close devices if necessary.
+        mFlashlight->prepareDeviceOpen();
+
         switch(deviceVersion) {
           case CAMERA_DEVICE_API_VERSION_1_0:
             ALOGW("Camera using old HAL version: %d", deviceVersion);
@@ -1052,6 +1172,16 @@
         }
     }
 
+    /* Immediately signal current torch status to this listener only */
+    {
+        Mutex::Autolock al(mTorchStatusMutex);
+        for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) {
+            listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i),
+                    mTorchStatusMap.keyAt(i));
+        }
+
+    }
+
     return OK;
 }
 status_t CameraService::removeListener(
@@ -1731,6 +1861,23 @@
     return NO_ERROR;
 }
 
+void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
+    Mutex::Autolock al(mTorchStatusMutex);
+    for (size_t i = 0; i < mTorchClientMap.size(); i++) {
+        if (mTorchClientMap[i] == who) {
+            // turn off the torch mode that was turned on by dead client
+            String16 cameraId = mTorchClientMap.keyAt(i);
+            mFlashlight->setTorchMode(cameraId, false);
+            mTorchClientMap.removeItemsAt(i);
+
+            // notify torch mode was turned off
+            onTorchStatusChangedLocked(cameraId,
+                    ICameraServiceListener::TORCH_STATUS_OFF);
+            break;
+        }
+    }
+}
+
 /*virtual*/void CameraService::binderDied(
     const wp<IBinder> &who) {
 
@@ -1741,6 +1888,10 @@
 
     ALOGV("java clients' binder died");
 
+    // check torch client
+    handleTorchClientBinderDied(who);
+
+    // check camera device client
     sp<BasicClient> cameraClient = getClientByRemote(who);
 
     if (cameraClient == 0) {
@@ -1834,4 +1985,27 @@
     return mStatusList[cameraId];
 }
 
+ICameraServiceListener::TorchStatus CameraService::getTorchStatusLocked(
+        const String16& cameraId) const {
+    ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
+    if (index == NAME_NOT_FOUND) {
+        return ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+    }
+
+    return mTorchStatusMap.valueAt(index);
+}
+
+status_t CameraService::setTorchStatusLocked(const String16& cameraId,
+        ICameraServiceListener::TorchStatus status) {
+    ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
+    if (index == NAME_NOT_FOUND) {
+        return BAD_VALUE;
+    }
+    ICameraServiceListener::TorchStatus& item =
+            mTorchStatusMap.editValueAt(index);
+    item = status;
+
+    return OK;
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 7d0df3a..84bcdb8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -36,6 +36,8 @@
 #include <camera/CameraParameters.h>
 
 #include <camera/ICameraServiceListener.h>
+#include "CameraFlashlight.h"
+
 
 #include "common/CameraModule.h"
 
@@ -70,6 +72,9 @@
     // HAL Callbacks
     virtual void        onDeviceStatusChanged(int cameraId,
                                               int newStatus);
+    virtual void        onTorchStatusChanged(const String16& cameraId,
+                                             ICameraServiceListener::TorchStatus
+                                                   newStatus);
 
     /////////////////////////////////////////////////////////////////////
     // ICameraService
@@ -112,6 +117,9 @@
             /*out*/
             String16* parameters);
 
+    virtual status_t    setTorchMode(const String16& cameraId, bool enabled,
+            const sp<IBinder>& clientBinder);
+
     // OK = supports api of that version, -EOPNOTSUPP = does not support
     virtual status_t    supportsCameraApi(
             int cameraId, int apiVersion);
@@ -408,6 +416,32 @@
                             int32_t cameraId,
                             const StatusVector *rejectSourceStates = NULL);
 
+    // flashlight control
+    sp<CameraFlashlight> mFlashlight;
+    // guard mTorchStatusMap and mTorchClientMap
+    Mutex                mTorchStatusMutex;
+    // camera id -> torch status
+    KeyedVector<String16, ICameraServiceListener::TorchStatus> mTorchStatusMap;
+    // camera id -> torch client binder
+    // only store the last client that turns on each camera's torch mode
+    KeyedVector<String16, sp<IBinder> > mTorchClientMap;
+
+    // check and handle if torch client's process has died
+    void handleTorchClientBinderDied(const wp<IBinder> &who);
+
+    // handle torch mode status change and invoke callbacks. mTorchStatusMutex
+    // should be locked.
+    void onTorchStatusChangedLocked(const String16& cameraId,
+            ICameraServiceListener::TorchStatus newStatus);
+
+    // get a camera's torch status. mTorchStatusMutex should be locked.
+    ICameraServiceListener::TorchStatus getTorchStatusLocked(
+            const String16 &cameraId) const;
+
+    // set a camera's torch status. mTorchStatusMutex should be locked.
+    status_t setTorchStatusLocked(const String16 &cameraId,
+            ICameraServiceListener::TorchStatus status);
+
     // IBinder::DeathRecipient implementation
     virtual void        binderDied(const wp<IBinder> &who);
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4ac5166..5dbdeb2 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1959,7 +1959,7 @@
             return width * height * 2;
         case HAL_PIXEL_FORMAT_RGBA_8888:
             return width * height * 4;
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             return width * height * 2;
         default:
             ALOGE("%s: Unknown preview format: %x",
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 4f4cfb0..87e0132 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -182,9 +182,9 @@
                 supportedPreviewFormats +=
                     CameraParameters::PIXEL_FORMAT_YUV420SP;
                 break;
-            // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+            // Not advertizing JPEG, RAW16, etc, for preview formats
             case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-            case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            case HAL_PIXEL_FORMAT_RAW16:
             case HAL_PIXEL_FORMAT_BLOB:
                 addComma = false;
                 break;
@@ -2253,7 +2253,7 @@
         case HAL_PIXEL_FORMAT_RGBA_8888:   // RGBA8888
             fmt = CameraParameters::PIXEL_FORMAT_RGBA8888;
             break;
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             ALOGW("Raw sensor preview format requested.");
             fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
             break;
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index bbf47e8..85a4df9 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -66,6 +66,12 @@
         return -EINVAL;
     }
 
+    // Only override static_camera_characteristics for API2 devices
+    int apiVersion = mModule->common.module_api_version;
+    if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
+        return mModule->get_camera_info(cameraId, info);
+    }
+
     camera_info &wrappedInfo = mCameraInfo[cameraId];
     if (!mCameraInfoCached[cameraId]) {
         camera_info rawInfo;
@@ -75,14 +81,7 @@
         }
         CameraMetadata &m = mCameraCharacteristics[cameraId];
         m = rawInfo.static_camera_characteristics;
-        int deviceVersion;
-        int apiVersion = mModule->common.module_api_version;
-        if (apiVersion >= CAMERA_MODULE_API_VERSION_2_0) {
-            deviceVersion = rawInfo.device_version;
-        } else {
-            deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
-        }
-        deriveCameraCharacteristicsKeys(deviceVersion, m);
+        deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
         wrappedInfo = rawInfo;
         wrappedInfo.static_camera_characteristics = m.getAndLock();
         mCameraInfoCached[cameraId] = true;