Merge "Camera3Device: Validate template ID" into nyc-dev
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index fad57ba..c78fc5d 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -79,7 +79,7 @@
     return mBuffer;
 }
 
-status_t CameraMetadata::unlock(const camera_metadata_t *buffer) {
+status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
     if (!mLocked) {
         ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
         return INVALID_OPERATION;
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index ebd473d..40dbeef 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -49,6 +49,7 @@
     libcamera_client \
     libstagefright_foundation \
     libcutils \
+    libcamera_metadata
 
 LOCAL_CLANG := true
 
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
index 18718d3..85fe75b 100644
--- a/camera/ndk/NdkCameraMetadata.cpp
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -39,6 +39,18 @@
 }
 
 EXPORT
+camera_status_t ACameraMetadata_getAllTags(
+        const ACameraMetadata* acm, /*out*/int32_t* numTags, /*out*/const uint32_t** tags) {
+    ATRACE_CALL();
+    if (acm == nullptr || numTags == nullptr || tags == nullptr) {
+        ALOGE("%s: invalid argument! metadata %p, numTags %p, tags %p",
+               __FUNCTION__, acm, numTags, tags);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return acm->getTags(numTags, tags);
+}
+
+EXPORT
 ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) {
     ATRACE_CALL();
     if (src == nullptr) {
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index 4fee09c..77b9a33 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -87,6 +87,18 @@
     return req->settings->getConstEntry(tag, entry);
 }
 
+EXPORT
+camera_status_t ACaptureRequest_getAllTags(
+        const ACaptureRequest* req, /*out*/int32_t* numTags, /*out*/const uint32_t** tags) {
+    ATRACE_CALL();
+    if (req == nullptr || numTags == nullptr || tags == nullptr) {
+        ALOGE("%s: invalid argument! request %p, numTags %p, tags %p",
+               __FUNCTION__, req, numTags, tags);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return req->settings->getTags(numTags, tags);
+}
+
 #define SET_ENTRY(NAME,NDK_TYPE)                                                        \
 EXPORT                                                                                  \
 camera_status_t ACaptureRequest_setEntry_##NAME(                                        \
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 880befe..6bca692 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -76,8 +76,8 @@
     mHandler = new CallbackHandler();
     mCbLooper->registerHandler(mHandler);
 
-    CameraMetadata metadata = mChars->mData;
-    camera_metadata_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+    const CameraMetadata& metadata = mChars->getInternalData();
+    camera_metadata_ro_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
     if (entry.count != 1) {
         ALOGW("%s: bad count %zu for partial result count", __FUNCTION__, entry.count);
         mPartialResultCount = 1;
@@ -279,7 +279,7 @@
         const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
     camera_status_t ret;
     sp<CaptureRequest> req(new CaptureRequest());
-    req->mMetadata = request->settings->mData;
+    req->mMetadata = request->settings->getInternalData();
     req->mIsReprocess = false; // NDK does not support reprocessing yet
 
     for (auto outputTarget : request->targets->mOutputs) {
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index fbc8d19..8366ade 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -162,6 +162,8 @@
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
 
+    Mutex::Autolock _l(mLock);
+
     camera_metadata_ro_entry rawEntry = mData.find(tag);
     if (rawEntry.count == 0) {
         ALOGE("%s: cannot find metadata tag %d", __FUNCTION__, tag);
@@ -204,6 +206,38 @@
     return updateImpl<camera_metadata_rational_t>(tag, count, data);
 }
 
+camera_status_t
+ACameraMetadata::getTags(/*out*/int32_t* numTags,
+                         /*out*/const uint32_t** tags) const {
+    Mutex::Autolock _l(mLock);
+    if (mTags.size() == 0) {
+        size_t entry_count = mData.entryCount();
+        mTags.setCapacity(entry_count);
+        const camera_metadata_t* rawMetadata = mData.getAndLock();
+        for (size_t i = 0; i < entry_count; i++) {
+            camera_metadata_ro_entry_t entry;
+            int ret = get_camera_metadata_ro_entry(rawMetadata, i, &entry);
+            if (ret != 0) {
+                ALOGE("%s: error reading metadata index %zu", __FUNCTION__, i);
+                return ACAMERA_ERROR_UNKNOWN;
+            }
+            // Hide system key from users
+            if (sSystemTags.count(entry.tag) == 0) {
+                mTags.push_back(entry.tag);
+            }
+        }
+        mData.unlock(rawMetadata);
+    }
+
+    *numTags = mTags.size();
+    *tags = mTags.array();
+    return ACAMERA_OK;
+}
+
+const CameraMetadata&
+ACameraMetadata::getInternalData() {
+    return mData;
+}
 
 // TODO: some of key below should be hidden from user
 // ex: ACAMERA_REQUEST_ID and ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
@@ -286,6 +320,49 @@
     }
 }
 
+// System tags that should be hidden from users
+std::unordered_set<uint32_t> ACameraMetadata::sSystemTags ({
+    ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
+    ANDROID_CONTROL_AE_PRECAPTURE_ID,
+    ANDROID_CONTROL_AF_TRIGGER_ID,
+    ANDROID_DEMOSAIC_MODE,
+    ANDROID_EDGE_STRENGTH,
+    ANDROID_FLASH_FIRING_POWER,
+    ANDROID_FLASH_FIRING_TIME,
+    ANDROID_FLASH_COLOR_TEMPERATURE,
+    ANDROID_FLASH_MAX_ENERGY,
+    ANDROID_FLASH_INFO_CHARGE_DURATION,
+    ANDROID_JPEG_MAX_SIZE,
+    ANDROID_JPEG_SIZE,
+    ANDROID_NOISE_REDUCTION_STRENGTH,
+    ANDROID_QUIRKS_METERING_CROP_REGION,
+    ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO,
+    ANDROID_QUIRKS_USE_ZSL_FORMAT,
+    ANDROID_REQUEST_INPUT_STREAMS,
+    ANDROID_REQUEST_METADATA_MODE,
+    ANDROID_REQUEST_OUTPUT_STREAMS,
+    ANDROID_REQUEST_TYPE,
+    ANDROID_REQUEST_MAX_NUM_REPROCESS_STREAMS,
+    ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
+    ANDROID_SCALER_AVAILABLE_RAW_SIZES,
+    ANDROID_SENSOR_BASE_GAIN_FACTOR,
+    ANDROID_SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS,
+    ANDROID_SENSOR_TEMPERATURE,
+    ANDROID_SENSOR_PROFILE_HUE_SAT_MAP,
+    ANDROID_SENSOR_PROFILE_TONE_CURVE,
+    ANDROID_SENSOR_OPAQUE_RAW_SIZE,
+    ANDROID_SHADING_STRENGTH,
+    ANDROID_STATISTICS_HISTOGRAM_MODE,
+    ANDROID_STATISTICS_SHARPNESS_MAP_MODE,
+    ANDROID_STATISTICS_HISTOGRAM,
+    ANDROID_STATISTICS_SHARPNESS_MAP,
+    ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT,
+    ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
+    ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
+    ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
+    ANDROID_DEPTH_MAX_DEPTH_SAMPLES,
+});
+
 /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
  * End generated code
  *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index 442e1dd..ab651a1 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -16,8 +16,12 @@
 #ifndef _ACAMERA_METADATA_H
 #define _ACAMERA_METADATA_H
 
+#include <unordered_set>
+
 #include <sys/types.h>
+#include <utils/Mutex.h>
 #include <utils/RefBase.h>
+#include <utils/Vector.h>
 #include <camera/CameraMetadata.h>
 
 #include "NdkCameraMetadata.h"
@@ -51,12 +55,17 @@
     camera_status_t update(uint32_t tag, uint32_t count, const int64_t* data);
     camera_status_t update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data);
 
+    camera_status_t getTags(/*out*/int32_t* numTags,
+                            /*out*/const uint32_t** tags) const;
+
     bool isNdkSupportedCapability(const int32_t capability);
-    inline bool isVendorTag(const uint32_t tag);
-    bool isCaptureRequestTag(const uint32_t tag);
+    static inline bool isVendorTag(const uint32_t tag);
+    static bool isCaptureRequestTag(const uint32_t tag);
     void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
     void filterStreamConfigurations(); // Hide input streams, translate hal format to NDK formats
 
+    const CameraMetadata& getInternalData();
+
     template<typename INTERNAL_T, typename NDK_T>
     camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
         if (mType != ACM_REQUEST) {
@@ -68,18 +77,27 @@
             return ACAMERA_ERROR_INVALID_PARAMETER;
         }
 
+        Mutex::Autolock _l(mLock);
+
         // Here we have to use reinterpret_cast because the NDK data type is
         // exact copy of internal data type but they do not inherit from each other
         status_t ret = mData.update(tag, reinterpret_cast<const INTERNAL_T*>(data), count);
         if (ret == OK) {
+            mTags.clear();
             return ACAMERA_OK;
         } else {
             return ACAMERA_ERROR_INVALID_PARAMETER;
         }
     }
 
-    CameraMetadata mData;
+  private:
+    // guard access of public APIs: get/update/getTags
+    mutable Mutex    mLock;
+    CameraMetadata   mData;
+    mutable Vector<uint32_t> mTags; // updated in getTags, cleared by update
     const ACAMERA_METADATA_TYPE mType;
+
+    static std::unordered_set<uint32_t> sSystemTags;
 };
 
 #endif // _ACAMERA_METADATA_H
diff --git a/include/camera/CameraMetadata.h b/include/camera/CameraMetadata.h
index db400de..28f47a1 100644
--- a/include/camera/CameraMetadata.h
+++ b/include/camera/CameraMetadata.h
@@ -64,7 +64,7 @@
      * from getAndLock must be provided to guarantee that the right object is
      * being unlocked.
      */
-    status_t unlock(const camera_metadata_t *buffer);
+    status_t unlock(const camera_metadata_t *buffer) const;
 
     /**
      * Release a raw metadata buffer to the caller. After this call,
diff --git a/include/camera/ndk/NdkCameraMetadata.h b/include/camera/ndk/NdkCameraMetadata.h
index 56412ad..9b56a9d 100644
--- a/include/camera/ndk/NdkCameraMetadata.h
+++ b/include/camera/ndk/NdkCameraMetadata.h
@@ -93,7 +93,13 @@
 camera_status_t ACameraMetadata_getConstEntry(
         const ACameraMetadata*, uint32_t tag, ACameraMetadata_const_entry* entry);
 
-// TODO: need an API to list all tags in the metadata. Same for ACaptureRequest
+/*
+ * List all the entry tags in this metadata.
+ * The memory of tags is managed by ACameraMetadata itself and must NOT be free/delete
+ * by application. Do NOT access tags after calling ACameraMetadata_free
+ */
+camera_status_t ACameraMetadata_getAllTags(
+        const ACameraMetadata*, /*out*/int32_t* numTags, /*out*/const uint32_t** tags);
 
 /**
  * Copy a metadata. Duplicates a metadata structure.
diff --git a/include/camera/ndk/NdkCaptureRequest.h b/include/camera/ndk/NdkCaptureRequest.h
index 566d78f..d9fb164 100644
--- a/include/camera/ndk/NdkCaptureRequest.h
+++ b/include/camera/ndk/NdkCaptureRequest.h
@@ -54,6 +54,19 @@
  */
 camera_status_t ACaptureRequest_getConstEntry(
         const ACaptureRequest*, uint32_t tag, ACameraMetadata_const_entry* entry);
+
+/*
+ * List all the entry tags in this capture request.
+ * The memory of tags is managed by ACaptureRequest itself and must NOT be free/delete
+ * by application. Calling ACaptureRequest_setEntry_* API will invalidate previous
+ * output of ACaptureRequest_getAllTags. Do not access tags after calling
+ * ACaptureRequest_setEntry_*. To get new list of tags after updating capture request,
+ * application must call ACaptureRequest_getAllTags again.
+ * Do NOT access tags after calling ACaptureRequest_free.
+ */
+camera_status_t ACaptureRequest_getAllTags(
+        const ACaptureRequest*, /*out*/int32_t* numTags, /*out*/const uint32_t** tags);
+
 /*
  * Set an entry of corresponding type.
  * The entry tag's type must match corresponding set API or an
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index b0bc2d0..b034c8e 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -596,7 +596,13 @@
     size_t                  mFrameSize;         // app-level frame size == AudioFlinger frame size
     uint32_t                mLatency;           // in ms
     audio_channel_mask_t    mChannelMask;
-    audio_input_flags_t     mFlags;
+
+    audio_input_flags_t     mFlags;                 // same as mOrigFlags, except for bits that may
+                                                    // be denied by client or server, such as
+                                                    // AUDIO_INPUT_FLAG_FAST.  mLock must be
+                                                    // held to read or write those bits reliably.
+    audio_input_flags_t     mOrigFlags;             // as specified in constructor or set(), const
+
     int                     mSessionId;
     transfer_type           mTransfer;
 
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index e0fb603..69dc062 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -949,9 +949,11 @@
 
     uint32_t                mUnderrunCountOffset;   // updated when restoring tracks
 
-    audio_output_flags_t    mFlags;
-        // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
-        // mLock must be held to read or write those bits reliably.
+    audio_output_flags_t    mFlags;                 // same as mOrigFlags, except for bits that may
+                                                    // be denied by client or server, such as
+                                                    // AUDIO_OUTPUT_FLAG_FAST.  mLock must be
+                                                    // held to read or write those bits reliably.
+    audio_output_flags_t    mOrigFlags;             // as specified in constructor or set(), const
 
     bool                    mDoNotReconnect;
 
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 3de0d21..2d28432 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -20,9 +20,12 @@
 
 #include <stdint.h>
 
+#define STRINGIFY_ENUMS
+
 #include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
 #include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ColorUtils.h>
 #include <media/hardware/HardwareAPI.h>
 
 #include <utils/NativeHandle.h>
@@ -34,7 +37,7 @@
 struct ABuffer;
 struct PersistentSurface;
 
-struct CodecBase : public AHandler {
+struct CodecBase : public AHandler, /* static */ ColorUtils {
     enum {
         kWhatFillThisBuffer      = 'fill',
         kWhatDrainThisBuffer     = 'drai',
@@ -97,113 +100,6 @@
      * Codec-related defines
      */
 
-    /**********************************************************************************************/
-
-    /*
-     * Media-platform color constants. MediaCodec uses (an extended version of) platform-defined
-     * constants that are derived from HAL_DATASPACE, since these are directly exposed to the user.
-     * We extend the values to maintain the richer set of information defined inside media
-     * containers and bitstreams that are not supported by the platform. We also expect vendors
-     * to extend some of these values with vendor-specific values. These are separated into a
-     * vendor-extension section so they won't collide with future platform values.
-     */
-
-    enum ColorStandard : uint32_t {
-        kColorStandardUnspecified =
-                HAL_DATASPACE_STANDARD_UNSPECIFIED >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT709 =     HAL_DATASPACE_STANDARD_BT709 >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT601_625 = HAL_DATASPACE_STANDARD_BT601_625 >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT601_625_Unadjusted =
-                HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT601_525 = HAL_DATASPACE_STANDARD_BT601_525 >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT601_525_Unadjusted =
-                HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT2020 =    HAL_DATASPACE_STANDARD_BT2020 >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT2020Constant =
-                HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardBT470M =    HAL_DATASPACE_STANDARD_BT470M >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardFilm =      HAL_DATASPACE_STANDARD_FILM >> HAL_DATASPACE_STANDARD_SHIFT,
-        kColorStandardMax =       HAL_DATASPACE_STANDARD_MASK >> HAL_DATASPACE_STANDARD_SHIFT,
-
-        /* This marks a section of color-standard values that are not supported by graphics HAL,
-           but track defined color primaries-matrix coefficient combinations in media.
-           These are stable for a given release. */
-        kColorStandardExtendedStart = kColorStandardMax + 1,
-
-        /* This marks a section of color-standard values that are not supported by graphics HAL
-           nor using media defined color primaries or matrix coefficients. These may differ per
-           device. */
-        kColorStandardVendorStart = 0x10000,
-    };
-
-    enum ColorTransfer : uint32_t  {
-        kColorTransferUnspecified =
-                HAL_DATASPACE_TRANSFER_UNSPECIFIED >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferLinear =      HAL_DATASPACE_TRANSFER_LINEAR >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferSRGB =        HAL_DATASPACE_TRANSFER_SRGB >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferSMPTE_170M =
-                HAL_DATASPACE_TRANSFER_SMPTE_170M >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferGamma22 =     HAL_DATASPACE_TRANSFER_GAMMA2_2 >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferGamma28 =     HAL_DATASPACE_TRANSFER_GAMMA2_8 >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferST2084 =      HAL_DATASPACE_TRANSFER_ST2084 >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferHLG =         HAL_DATASPACE_TRANSFER_HLG >> HAL_DATASPACE_TRANSFER_SHIFT,
-        kColorTransferMax =         HAL_DATASPACE_TRANSFER_MASK >> HAL_DATASPACE_TRANSFER_SHIFT,
-
-        /* This marks a section of color-transfer values that are not supported by graphics HAL,
-           but track media-defined color-transfer. These are stable for a given release. */
-        kColorTransferExtendedStart = kColorTransferMax + 1,
-
-        /* This marks a section of color-transfer values that are not supported by graphics HAL
-           nor defined by media. These may differ per device. */
-        kColorTransferVendorStart = 0x10000,
-    };
-
-    enum ColorRange : uint32_t  {
-        kColorRangeUnspecified = HAL_DATASPACE_RANGE_UNSPECIFIED >> HAL_DATASPACE_RANGE_SHIFT,
-        kColorRangeFull =        HAL_DATASPACE_RANGE_FULL >> HAL_DATASPACE_RANGE_SHIFT,
-        kColorRangeLimited =     HAL_DATASPACE_RANGE_LIMITED >> HAL_DATASPACE_RANGE_SHIFT,
-        kColorRangeMax =         HAL_DATASPACE_RANGE_MASK >> HAL_DATASPACE_RANGE_SHIFT,
-
-        /* This marks a section of color-transfer values that are not supported by graphics HAL,
-           but track media-defined color-transfer. These are stable for a given release. */
-        kColorRangeExtendedStart = kColorRangeMax + 1,
-
-        /* This marks a section of color-transfer values that are not supported by graphics HAL
-           nor defined by media. These may differ per device. */
-        kColorRangeVendorStart = 0x10000,
-    };
-
-    /*
-     * Static utilities for codec support
-     */
-
-    // using int32_t for media range/standard/transfers to denote extended ranges
-    static int32_t wrapColorAspectsIntoColorStandard(
-            ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs);
-    static int32_t wrapColorAspectsIntoColorRange(ColorAspects::Range range);
-    static int32_t wrapColorAspectsIntoColorTransfer(ColorAspects::Transfer transfer);
-
-    static status_t unwrapColorAspectsFromColorRange(
-            int32_t range, ColorAspects::Range *aspect);
-    static status_t unwrapColorAspectsFromColorTransfer(
-            int32_t transfer, ColorAspects::Transfer *aspect);
-    static status_t unwrapColorAspectsFromColorStandard(
-            int32_t standard,
-            ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs);
-
-    static status_t convertPlatformColorAspectsToCodecAspects(
-            int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects);
-    static status_t convertCodecColorAspectsToPlatformAspects(
-            const ColorAspects &aspects,
-            int32_t *range, int32_t *standard, int32_t *transfer);
-
-    // updates unspecified range, standard and transfer values to their defaults
-    static void setDefaultPlatformColorAspectsIfNeeded(
-            int32_t &range, int32_t &standard, int32_t &transfer,
-            int32_t width, int32_t height);
-    static void setDefaultCodecColorAspectsIfNeeded(
-            ColorAspects &aspects, int32_t width, int32_t height);
-
 protected:
     CodecBase();
     virtual ~CodecBase();
diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h
index 65f415a..564b3f7 100644
--- a/include/media/stagefright/foundation/ADebug.h
+++ b/include/media/stagefright/foundation/ADebug.h
@@ -24,8 +24,9 @@
 #include <media/stagefright/foundation/AString.h>
 #include <utils/Log.h>
 
-inline static const char *asString(android::status_t i, const char *def = "??") {
-    using namespace android;
+namespace android {
+
+inline static const char *asString(status_t i, const char *def = "??") {
     switch (i) {
         case NO_ERROR:              return "NO_ERROR";
         case UNKNOWN_ERROR:         return "UNKNOWN_ERROR";
@@ -49,8 +50,6 @@
     }
 }
 
-namespace android {
-
 #define LITERAL_TO_STRING_INTERNAL(x)    #x
 #define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
 
diff --git a/include/media/stagefright/foundation/ColorUtils.h b/include/media/stagefright/foundation/ColorUtils.h
new file mode 100644
index 0000000..b95c80b
--- /dev/null
+++ b/include/media/stagefright/foundation/ColorUtils.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 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 COLOR_UTILS_H_
+
+#define COLOR_UTILS_H_
+
+#include <stdint.h>
+
+#define STRINGIFY_ENUMS
+
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/hardware/VideoAPI.h>
+#include <system/graphics.h>
+
+namespace android {
+
+struct ColorUtils {
+    /*
+     * Media-platform color constants. MediaCodec uses (an extended version of) platform-defined
+     * constants that are derived from HAL_DATASPACE, since these are directly exposed to the user.
+     * We extend the values to maintain the richer set of information defined inside media
+     * containers and bitstreams that are not supported by the platform. We also expect vendors
+     * to extend some of these values with vendor-specific values. These are separated into a
+     * vendor-extension section so they won't collide with future platform values.
+     */
+
+#define GET_HAL_ENUM(class, name) HAL_DATASPACE_##class##name
+#define GET_HAL_BITFIELD(class, name) (GET_HAL_ENUM(class, _##name) >> GET_HAL_ENUM(class, _SHIFT))
+
+    enum ColorStandard : uint32_t {
+        kColorStandardUnspecified =          GET_HAL_BITFIELD(STANDARD, UNSPECIFIED),
+        kColorStandardBT709 =                GET_HAL_BITFIELD(STANDARD, BT709),
+        kColorStandardBT601_625 =            GET_HAL_BITFIELD(STANDARD, BT601_625),
+        kColorStandardBT601_625_Unadjusted = GET_HAL_BITFIELD(STANDARD, BT601_625_UNADJUSTED),
+        kColorStandardBT601_525 =            GET_HAL_BITFIELD(STANDARD, BT601_525),
+        kColorStandardBT601_525_Unadjusted = GET_HAL_BITFIELD(STANDARD, BT601_525_UNADJUSTED),
+        kColorStandardBT2020 =               GET_HAL_BITFIELD(STANDARD, BT2020),
+        kColorStandardBT2020Constant =       GET_HAL_BITFIELD(STANDARD, BT2020_CONSTANT_LUMINANCE),
+        kColorStandardBT470M =               GET_HAL_BITFIELD(STANDARD, BT470M),
+        kColorStandardFilm =                 GET_HAL_BITFIELD(STANDARD, FILM),
+        kColorStandardMax =                  GET_HAL_BITFIELD(STANDARD, MASK),
+
+        /* This marks a section of color-standard values that are not supported by graphics HAL,
+           but track defined color primaries-matrix coefficient combinations in media.
+           These are stable for a given release. */
+        kColorStandardExtendedStart = kColorStandardMax + 1,
+
+        /* This marks a section of color-standard values that are not supported by graphics HAL
+           nor using media defined color primaries or matrix coefficients. These may differ per
+           device. */
+        kColorStandardVendorStart = 0x10000,
+    };
+
+    enum ColorTransfer : uint32_t  {
+        kColorTransferUnspecified = GET_HAL_BITFIELD(TRANSFER, UNSPECIFIED),
+        kColorTransferLinear =      GET_HAL_BITFIELD(TRANSFER, LINEAR),
+        kColorTransferSRGB =        GET_HAL_BITFIELD(TRANSFER, SRGB),
+        kColorTransferSMPTE_170M =  GET_HAL_BITFIELD(TRANSFER, SMPTE_170M),
+        kColorTransferGamma22 =     GET_HAL_BITFIELD(TRANSFER, GAMMA2_2),
+        kColorTransferGamma28 =     GET_HAL_BITFIELD(TRANSFER, GAMMA2_8),
+        kColorTransferST2084 =      GET_HAL_BITFIELD(TRANSFER, ST2084),
+        kColorTransferHLG =         GET_HAL_BITFIELD(TRANSFER, HLG),
+        kColorTransferMax =         GET_HAL_BITFIELD(TRANSFER, MASK),
+
+        /* This marks a section of color-transfer values that are not supported by graphics HAL,
+           but track media-defined color-transfer. These are stable for a given release. */
+        kColorTransferExtendedStart = kColorTransferMax + 1,
+
+        /* This marks a section of color-transfer values that are not supported by graphics HAL
+           nor defined by media. These may differ per device. */
+        kColorTransferVendorStart = 0x10000,
+    };
+
+    enum ColorRange : uint32_t  {
+        kColorRangeUnspecified = GET_HAL_BITFIELD(RANGE, UNSPECIFIED),
+        kColorRangeFull =        GET_HAL_BITFIELD(RANGE, FULL),
+        kColorRangeLimited =     GET_HAL_BITFIELD(RANGE, LIMITED),
+        kColorRangeMax =         GET_HAL_BITFIELD(RANGE, MASK),
+
+        /* This marks a section of color-transfer values that are not supported by graphics HAL,
+           but track media-defined color-transfer. These are stable for a given release. */
+        kColorRangeExtendedStart = kColorRangeMax + 1,
+
+        /* This marks a section of color-transfer values that are not supported by graphics HAL
+           nor defined by media. These may differ per device. */
+        kColorRangeVendorStart = 0x10000,
+    };
+
+#undef GET_HAL_BITFIELD
+#undef GET_HAL_ENUM
+
+    /*
+     * Static utilities for codec support
+     */
+
+    // using int32_t for media range/standard/transfers to denote extended ranges
+    // wrap methods change invalid aspects to the Unspecified value
+    static int32_t wrapColorAspectsIntoColorStandard(
+            ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs);
+    static int32_t wrapColorAspectsIntoColorRange(ColorAspects::Range range);
+    static int32_t wrapColorAspectsIntoColorTransfer(ColorAspects::Transfer transfer);
+
+    // unwrap methods change invalid aspects to the Other value
+    static status_t unwrapColorAspectsFromColorRange(
+            int32_t range, ColorAspects::Range *aspect);
+    static status_t unwrapColorAspectsFromColorTransfer(
+            int32_t transfer, ColorAspects::Transfer *aspect);
+    static status_t unwrapColorAspectsFromColorStandard(
+            int32_t standard,
+            ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs);
+
+    static status_t convertPlatformColorAspectsToCodecAspects(
+            int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects);
+    static status_t convertCodecColorAspectsToPlatformAspects(
+            const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer);
+
+    // updates unspecified range, standard and transfer values to their defaults
+    static void setDefaultPlatformColorAspectsIfNeeded(
+            int32_t &range, int32_t &standard, int32_t &transfer, int32_t width, int32_t height);
+    static void setDefaultCodecColorAspectsIfNeeded(
+            ColorAspects &aspects, int32_t width, int32_t height);
+};
+
+inline static const char *asString(android::ColorUtils::ColorStandard i, const char *def = "??") {
+    using namespace android;
+    switch (i) {
+        case ColorUtils::kColorStandardUnspecified:          return "Unspecified";
+        case ColorUtils::kColorStandardBT709:                return "BT709";
+        case ColorUtils::kColorStandardBT601_625:            return "BT601_625";
+        case ColorUtils::kColorStandardBT601_625_Unadjusted: return "BT601_625_Unadjusted";
+        case ColorUtils::kColorStandardBT601_525:            return "BT601_525";
+        case ColorUtils::kColorStandardBT601_525_Unadjusted: return "BT601_525_Unadjusted";
+        case ColorUtils::kColorStandardBT2020:               return "BT2020";
+        case ColorUtils::kColorStandardBT2020Constant:       return "BT2020Constant";
+        case ColorUtils::kColorStandardBT470M:               return "BT470M";
+        case ColorUtils::kColorStandardFilm:                 return "Film";
+        default:                                            return def;
+    }
+}
+
+inline static const char *asString(android::ColorUtils::ColorTransfer i, const char *def = "??") {
+    using namespace android;
+    switch (i) {
+        case ColorUtils::kColorTransferUnspecified: return "Unspecified";
+        case ColorUtils::kColorTransferLinear:      return "Linear";
+        case ColorUtils::kColorTransferSRGB:        return "SRGB";
+        case ColorUtils::kColorTransferSMPTE_170M:  return "SMPTE_170M";
+        case ColorUtils::kColorTransferGamma22:     return "Gamma22";
+        case ColorUtils::kColorTransferGamma28:     return "Gamma28";
+        case ColorUtils::kColorTransferST2084:      return "ST2084";
+        case ColorUtils::kColorTransferHLG:         return "HLG";
+        default:                                   return def;
+    }
+}
+
+inline static const char *asString(android::ColorUtils::ColorRange i, const char *def = "??") {
+    using namespace android;
+    switch (i) {
+        case ColorUtils::kColorRangeUnspecified: return "Unspecified";
+        case ColorUtils::kColorRangeFull:        return "Full";
+        case ColorUtils::kColorRangeLimited:     return "Limited";
+        default:                                return def;
+    }
+}
+
+}  // namespace android
+
+#endif  // COLOR_UTILS_H_
+
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index fef20d9..9eb5ec7 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -246,7 +246,7 @@
         mClientPid = pid;
     }
 
-    mFlags = flags;
+    mOrigFlags = mFlags = flags;
     mCbf = cbf;
 
     if (cbf != NULL) {
@@ -518,6 +518,9 @@
     }
     audio_io_handle_t input;
 
+    // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
+    // After fast request is denied, we will request again if IAudioRecord is re-created.
+
     status_t status;
     status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                         (audio_session_t)mSessionId,
@@ -569,7 +572,6 @@
             ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, "
                 "track %u Hz, input %u Hz",
                 mTransfer, mSampleRate, afSampleRate);
-            // once denied, do not request again if IAudioRecord is re-created
             mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
         }
     }
@@ -669,8 +671,7 @@
             ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu", frameCount);
             mAwaitBoost = true;
         } else {
-            ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
-            // once denied, do not request again if IAudioRecord is re-created
+            ALOGW("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
             mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
         }
     }
@@ -1140,6 +1141,8 @@
     ALOGW("dead IAudioRecord, creating a new one from %s()", from);
     ++mSequence;
 
+    mFlags = mOrigFlags;
+
     // if the new IAudioRecord is created, openRecord_l() will modify the
     // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
     // It will also delete the strong references on previous IAudioRecord and IMemory
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 8e02900..423273d 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -455,7 +455,7 @@
         mClientPid = pid;
     }
     mAuxEffectId = 0;
-    mFlags = flags;
+    mOrigFlags = mFlags = flags;
     mCbf = cbf;
 
     if (cbf != NULL) {
@@ -1153,6 +1153,9 @@
     audio_stream_type_t streamType = mStreamType;
     audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
 
+    // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
+    // After fast request is denied, we will request again if IAudioTrack is re-created.
+
     status_t status;
     status = AudioSystem::getOutputForAttr(attr, &output,
                                            (audio_session_t)mSessionId, &streamType, mClientUid,
@@ -1211,7 +1214,6 @@
             ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, "
                 "track %u Hz, output %u Hz",
                 mTransfer, mSampleRate, mAfSampleRate);
-            // once denied, do not request again if IAudioTrack is re-created
             mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
         }
     }
@@ -1353,31 +1355,10 @@
                 mAwaitBoost = true;
             }
         } else {
-            ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
-            // once denied, do not request again if IAudioTrack is re-created
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
             mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
         }
     }
-    if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-        if (trackFlags & IAudioFlinger::TRACK_OFFLOAD) {
-            ALOGV("AUDIO_OUTPUT_FLAG_OFFLOAD successful");
-        } else {
-            ALOGW("AUDIO_OUTPUT_FLAG_OFFLOAD denied by server");
-            mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
-            // FIXME This is a warning, not an error, so don't return error status
-            //return NO_INIT;
-        }
-    }
-    if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (trackFlags & IAudioFlinger::TRACK_DIRECT) {
-            ALOGV("AUDIO_OUTPUT_FLAG_DIRECT successful");
-        } else {
-            ALOGW("AUDIO_OUTPUT_FLAG_DIRECT denied by server");
-            mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_DIRECT);
-            // FIXME This is a warning, not an error, so don't return error status
-            //return NO_INIT;
-        }
-    }
 
     // Make sure that application is notified with sufficient margin before underrun.
     // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
@@ -2089,6 +2070,8 @@
         mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
     }
 
+    mFlags = mOrigFlags;
+
     // If a new IAudioTrack is successfully created, createTrack_l() will modify the
     // following member variables: mAudioTrack, mCblkMemory and mCblk.
     // It will also delete the strong references on previous IAudioTrack and IMemory.
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index c9de2b0..f729d4d 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -20,8 +20,6 @@
 #include <inttypes.h>
 
 #include <media/stagefright/CodecBase.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALookup.h>
 
 namespace android {
 
@@ -37,277 +35,4 @@
 CodecBase::PortDescription::~PortDescription() {
 }
 
-/***************************************** COLOR SUPPORT *****************************************/
-
-// shortcut names for brevity in the following tables
-typedef ColorAspects CA;
-typedef CodecBase CB;
-
-ALookup<CB::ColorRange, CA::Range> sRanges{
-    {
-        { CB::kColorRangeLimited, CA::RangeLimited },
-        { CB::kColorRangeFull, CA::RangeFull },
-        { CB::kColorRangeUnspecified, CA::RangeUnspecified },
-    }
-};
-
-ALookup<CB::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandards {
-    {
-        { CB::kColorStandardUnspecified,    { CA::PrimariesUnspecified, CA::MatrixUnspecified } },
-        { CB::kColorStandardBT709,          { CA::PrimariesBT709_5, CA::MatrixBT709_5 } },
-        { CB::kColorStandardBT601_625,      { CA::PrimariesBT601_6_625, CA::MatrixBT601_6 } },
-        { CB::kColorStandardBT601_625_Unadjusted,
-                                            // this is a really close match
-                                            { CA::PrimariesBT601_6_625, CA::MatrixBT709_5 } },
-        { CB::kColorStandardBT601_525,      { CA::PrimariesBT601_6_525, CA::MatrixBT601_6 } },
-        { CB::kColorStandardBT601_525_Unadjusted,
-                                            { CA::PrimariesBT601_6_525, CA::MatrixSMPTE240M } },
-        { CB::kColorStandardBT2020,         { CA::PrimariesBT2020, CA::MatrixBT2020 } },
-        { CB::kColorStandardBT2020Constant, { CA::PrimariesBT2020, CA::MatrixBT2020Constant } },
-        { CB::kColorStandardBT470M,         { CA::PrimariesBT470_6M, CA::MatrixBT470_6M } },
-        // NOTE: there is no close match to the matrix used by standard film, chose closest
-        { CB::kColorStandardFilm,           { CA::PrimariesGenericFilm, CA::MatrixBT2020 } },
-    }
-};
-
-ALookup<CB::ColorTransfer, CA::Transfer> sTransfers{
-    {
-        { CB::kColorTransferUnspecified,    CA::TransferUnspecified },
-        { CB::kColorTransferLinear,         CA::TransferLinear },
-        { CB::kColorTransferSRGB,           CA::TransferSRGB },
-        { CB::kColorTransferSMPTE_170M,     CA::TransferSMPTE170M },
-        { CB::kColorTransferGamma22,        CA::TransferGamma22 },
-        { CB::kColorTransferGamma28,        CA::TransferGamma28 },
-        { CB::kColorTransferST2084,         CA::TransferST2084 },
-        { CB::kColorTransferHLG,            CA::TransferHLG },
-    }
-};
-
-static bool isValid(ColorAspects::Primaries p) {
-    return p <= ColorAspects::PrimariesOther;
-}
-
-static bool isDefined(ColorAspects::Primaries p) {
-    return p <= ColorAspects::PrimariesBT2020;
-}
-
-static bool isValid(ColorAspects::MatrixCoeffs c) {
-    return c <= ColorAspects::MatrixOther;
-}
-
-static bool isDefined(ColorAspects::MatrixCoeffs c) {
-    return c <= ColorAspects::MatrixBT2020Constant;
-}
-
-//static
-int32_t CodecBase::wrapColorAspectsIntoColorStandard(
-        ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs) {
-    ColorStandard res;
-    if (sStandards.map(std::make_pair(primaries, coeffs), &res)) {
-        return res;
-    } else if (!isValid(primaries) || !isValid(coeffs)) {
-        return kColorStandardUnspecified;
-    }
-
-    // check platform media limits
-    uint32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
-    if (isDefined(primaries) && isDefined(coeffs)) {
-        return kColorStandardExtendedStart + primaries + coeffs * numPrimaries;
-    } else {
-        return kColorStandardVendorStart + primaries + coeffs * 0x100;
-    }
-}
-
-//static
-status_t CodecBase::unwrapColorAspectsFromColorStandard(
-        int32_t standard,
-        ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs) {
-    std::pair<ColorAspects::Primaries, ColorAspects::MatrixCoeffs> res;
-    if (sStandards.map((ColorStandard)standard, &res)) {
-        *primaries = res.first;
-        *coeffs = res.second;
-        return OK;
-    }
-
-    int32_t start = kColorStandardExtendedStart;
-    int32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
-    int32_t numCoeffs = ColorAspects::MatrixBT2020Constant + 1;
-    if (standard >= (int32_t)kColorStandardVendorStart) {
-        start = kColorStandardVendorStart;
-        numPrimaries = ColorAspects::PrimariesOther + 1; // 0x100
-        numCoeffs = ColorAspects::MatrixOther + 1; // 0x100;
-    }
-    if (standard >= start && standard < start + numPrimaries * numCoeffs) {
-        int32_t product = standard - start;
-        *primaries = (ColorAspects::Primaries)(product % numPrimaries);
-        *coeffs = (ColorAspects::MatrixCoeffs)(product / numPrimaries);
-        return OK;
-    }
-    *primaries = ColorAspects::PrimariesOther;
-    *coeffs = ColorAspects::MatrixOther;
-    return BAD_VALUE;
-}
-
-static bool isValid(ColorAspects::Range r) {
-    return r <= ColorAspects::RangeOther;
-}
-
-static bool isDefined(ColorAspects::Range r) {
-    return r <= ColorAspects::RangeLimited;
-}
-
-//  static
-int32_t CodecBase::wrapColorAspectsIntoColorRange(ColorAspects::Range range) {
-    ColorRange res;
-    if (sRanges.map(range, &res)) {
-        return res;
-    } else if (!isValid(range)) {
-        return kColorRangeUnspecified;
-    } else {
-        CHECK(!isDefined(range));
-        // all platform values are in sRanges
-        return kColorRangeVendorStart + range;
-    }
-}
-
-//static
-status_t CodecBase::unwrapColorAspectsFromColorRange(
-        int32_t range, ColorAspects::Range *aspect) {
-    if (sRanges.map((ColorRange)range, aspect)) {
-        return OK;
-    }
-
-    int32_t start = kColorRangeVendorStart;
-    int32_t numRanges = ColorAspects::RangeOther + 1; // 0x100
-    if (range >= start && range < start + numRanges) {
-        *aspect = (ColorAspects::Range)(range - start);
-        return OK;
-    }
-    *aspect = ColorAspects::RangeOther;
-    return BAD_VALUE;
-}
-
-static bool isValid(ColorAspects::Transfer t) {
-    return t <= ColorAspects::TransferOther;
-}
-
-static bool isDefined(ColorAspects::Transfer t) {
-    return t <= ColorAspects::TransferHLG
-            || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428);
-}
-
-//  static
-int32_t CodecBase::wrapColorAspectsIntoColorTransfer(
-        ColorAspects::Transfer transfer) {
-    ColorTransfer res;
-    if (sTransfers.map(transfer, &res)) {
-        return res;
-    } else if (!isValid(transfer)) {
-        return kColorTransferUnspecified;
-    } else if (isDefined(transfer)) {
-        return kColorTransferExtendedStart + transfer;
-    } else {
-        // all platform values are in sRanges
-        return kColorTransferVendorStart + transfer;
-    }
-}
-
-//static
-status_t CodecBase::unwrapColorAspectsFromColorTransfer(
-        int32_t transfer, ColorAspects::Transfer *aspect) {
-    if (sTransfers.map((ColorTransfer)transfer, aspect)) {
-        return OK;
-    }
-
-    int32_t start = kColorTransferExtendedStart;
-    int32_t numTransfers = ColorAspects::TransferST428 + 1;
-    if (transfer >= (int32_t)kColorTransferVendorStart) {
-        start = kColorTransferVendorStart;
-        numTransfers = ColorAspects::TransferOther + 1; // 0x100
-    }
-    if (transfer >= start && transfer < start + numTransfers) {
-        *aspect = (ColorAspects::Transfer)(transfer - start);
-        return OK;
-    }
-    *aspect = ColorAspects::TransferOther;
-    return BAD_VALUE;
-}
-
-// static
-status_t CodecBase::convertPlatformColorAspectsToCodecAspects(
-    int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects) {
-    status_t res1 = unwrapColorAspectsFromColorRange(range, &aspects.mRange);
-    status_t res2 = unwrapColorAspectsFromColorStandard(
-            standard, &aspects.mPrimaries, &aspects.mMatrixCoeffs);
-    status_t res3 = unwrapColorAspectsFromColorTransfer(transfer, &aspects.mTransfer);
-    return res1 != OK ? res1 : (res2 != OK ? res2 : res3);
-}
-
-// static
-status_t CodecBase::convertCodecColorAspectsToPlatformAspects(
-    const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer) {
-    *range = wrapColorAspectsIntoColorRange(aspects.mRange);
-    *standard = wrapColorAspectsIntoColorStandard(aspects.mPrimaries, aspects.mMatrixCoeffs);
-    *transfer = wrapColorAspectsIntoColorTransfer(aspects.mTransfer);
-    if (isValid(aspects.mRange) && isValid(aspects.mPrimaries)
-            && isValid(aspects.mMatrixCoeffs) && isValid(aspects.mTransfer)) {
-        return OK;
-    } else {
-        return BAD_VALUE;
-    }
-}
-
-// static
-void CodecBase::setDefaultPlatformColorAspectsIfNeeded(
-        int32_t &range, int32_t &standard, int32_t &transfer,
-        int32_t width, int32_t height) {
-    if (range == CodecBase::kColorRangeUnspecified) {
-        range = CodecBase::kColorRangeLimited;
-    }
-
-    if (standard == CodecBase::kColorStandardUnspecified) {
-        // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601
-        // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between.
-        if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
-            standard = CodecBase::kColorStandardBT2020;
-        } else if ((width <= 720 && height > 480) || (height <= 720 && width > 480)) {
-            standard = CodecBase::kColorStandardBT601_625;
-        } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) {
-            standard = CodecBase::kColorStandardBT601_525;
-        } else {
-            standard = CodecBase::kColorStandardBT709;
-        }
-    }
-
-    if (transfer == CodecBase::kColorTransferUnspecified) {
-        transfer = CodecBase::kColorTransferSMPTE_170M;
-    }
-}
-
-// static
-void CodecBase::setDefaultCodecColorAspectsIfNeeded(
-        ColorAspects &aspects, int32_t width, int32_t height) {
-    // reuse other method to get default aspects
-    int32_t range = 0, standard = 0, transfer = 0;
-    setDefaultPlatformColorAspectsIfNeeded(range, standard, transfer, width, height);
-    ColorAspects defaultAspects;
-    memset(&defaultAspects, 0, sizeof(defaultAspects));
-    convertPlatformColorAspectsToCodecAspects(range, standard, transfer, defaultAspects);
-
-    if (aspects.mRange == ColorAspects::RangeUnspecified) {
-        aspects.mRange = defaultAspects.mRange;
-    }
-    if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
-        aspects.mPrimaries = defaultAspects.mPrimaries;
-    }
-    if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
-        aspects.mMatrixCoeffs = defaultAspects.mMatrixCoeffs;
-    }
-    if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
-        aspects.mTransfer = defaultAspects.mTransfer;
-    }
-}
-
-/**************************************************************************************************/
-
 }  // namespace android
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index bdfddc7..5f9a1c0 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -286,6 +286,7 @@
                 }
                 if (queue->mPulling && err == OK) {
                     msg->post(); // if simply paused, keep pulling source
+                    break;
                 } else if (err == ERROR_END_OF_STREAM) {
                     ALOGV("stream ended, mbuf %p", mbuf);
                 } else if (err != OK) {
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 711601f..3c3ed59 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -15,6 +15,7 @@
     AString.cpp                   \
     AStringUtils.cpp              \
     AWakeLock.cpp                 \
+    ColorUtils.cpp                \
     MediaBuffer.cpp               \
     MediaBufferGroup.cpp          \
     MetaData.cpp                  \
diff --git a/media/libstagefright/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
new file mode 100644
index 0000000..2b86b0e
--- /dev/null
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2016 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_NDEBUG 0
+#define LOG_TAG "ColorUtils"
+
+#include <inttypes.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALookup.h>
+#include <media/stagefright/foundation/ColorUtils.h>
+
+namespace android {
+
+// shortcut names for brevity in the following tables
+typedef ColorAspects CA;
+typedef ColorUtils CU;
+
+ALookup<CU::ColorRange, CA::Range> sRanges{
+    {
+        { CU::kColorRangeLimited, CA::RangeLimited },
+        { CU::kColorRangeFull, CA::RangeFull },
+        { CU::kColorRangeUnspecified, CA::RangeUnspecified },
+    }
+};
+
+ALookup<CU::ColorStandard, std::pair<CA::Primaries, CA::MatrixCoeffs>> sStandards {
+    {
+        { CU::kColorStandardUnspecified,    { CA::PrimariesUnspecified, CA::MatrixUnspecified } },
+        { CU::kColorStandardBT709,          { CA::PrimariesBT709_5, CA::MatrixBT709_5 } },
+        { CU::kColorStandardBT601_625,      { CA::PrimariesBT601_6_625, CA::MatrixBT601_6 } },
+        { CU::kColorStandardBT601_625_Unadjusted,
+                                            // this is a really close match
+                                            { CA::PrimariesBT601_6_625, CA::MatrixBT709_5 } },
+        { CU::kColorStandardBT601_525,      { CA::PrimariesBT601_6_525, CA::MatrixBT601_6 } },
+        { CU::kColorStandardBT601_525_Unadjusted,
+                                            { CA::PrimariesBT601_6_525, CA::MatrixSMPTE240M } },
+        { CU::kColorStandardBT2020,         { CA::PrimariesBT2020, CA::MatrixBT2020 } },
+        { CU::kColorStandardBT2020Constant, { CA::PrimariesBT2020, CA::MatrixBT2020Constant } },
+        { CU::kColorStandardBT470M,         { CA::PrimariesBT470_6M, CA::MatrixBT470_6M } },
+        // NOTE: there is no close match to the matrix used by standard film, chose closest
+        { CU::kColorStandardFilm,           { CA::PrimariesGenericFilm, CA::MatrixBT2020 } },
+    }
+};
+
+ALookup<CU::ColorTransfer, CA::Transfer> sTransfers{
+    {
+        { CU::kColorTransferUnspecified,    CA::TransferUnspecified },
+        { CU::kColorTransferLinear,         CA::TransferLinear },
+        { CU::kColorTransferSRGB,           CA::TransferSRGB },
+        { CU::kColorTransferSMPTE_170M,     CA::TransferSMPTE170M },
+        { CU::kColorTransferGamma22,        CA::TransferGamma22 },
+        { CU::kColorTransferGamma28,        CA::TransferGamma28 },
+        { CU::kColorTransferST2084,         CA::TransferST2084 },
+        { CU::kColorTransferHLG,            CA::TransferHLG },
+    }
+};
+
+static bool isValid(ColorAspects::Primaries p) {
+    return p <= ColorAspects::PrimariesOther;
+}
+
+static bool isDefined(ColorAspects::Primaries p) {
+    return p <= ColorAspects::PrimariesBT2020;
+}
+
+static bool isValid(ColorAspects::MatrixCoeffs c) {
+    return c <= ColorAspects::MatrixOther;
+}
+
+static bool isDefined(ColorAspects::MatrixCoeffs c) {
+    return c <= ColorAspects::MatrixBT2020Constant;
+}
+
+//static
+int32_t ColorUtils::wrapColorAspectsIntoColorStandard(
+        ColorAspects::Primaries primaries, ColorAspects::MatrixCoeffs coeffs) {
+    ColorStandard res;
+    if (sStandards.map(std::make_pair(primaries, coeffs), &res)) {
+        return res;
+    } else if (!isValid(primaries) || !isValid(coeffs)) {
+        return kColorStandardUnspecified;
+    }
+
+    // check platform media limits
+    uint32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
+    if (isDefined(primaries) && isDefined(coeffs)) {
+        return kColorStandardExtendedStart + primaries + coeffs * numPrimaries;
+    } else {
+        return kColorStandardVendorStart + primaries + coeffs * 0x100;
+    }
+}
+
+//static
+status_t ColorUtils::unwrapColorAspectsFromColorStandard(
+        int32_t standard,
+        ColorAspects::Primaries *primaries, ColorAspects::MatrixCoeffs *coeffs) {
+    std::pair<ColorAspects::Primaries, ColorAspects::MatrixCoeffs> res;
+    if (sStandards.map((ColorStandard)standard, &res)) {
+        *primaries = res.first;
+        *coeffs = res.second;
+        return OK;
+    }
+
+    int32_t start = kColorStandardExtendedStart;
+    int32_t numPrimaries = ColorAspects::PrimariesBT2020 + 1;
+    int32_t numCoeffs = ColorAspects::MatrixBT2020Constant + 1;
+    if (standard >= (int32_t)kColorStandardVendorStart) {
+        start = kColorStandardVendorStart;
+        numPrimaries = ColorAspects::PrimariesOther + 1; // 0x100
+        numCoeffs = ColorAspects::MatrixOther + 1; // 0x100;
+    }
+    if (standard >= start && standard < start + numPrimaries * numCoeffs) {
+        int32_t product = standard - start;
+        *primaries = (ColorAspects::Primaries)(product % numPrimaries);
+        *coeffs = (ColorAspects::MatrixCoeffs)(product / numPrimaries);
+        return OK;
+    }
+    *primaries = ColorAspects::PrimariesOther;
+    *coeffs = ColorAspects::MatrixOther;
+    return BAD_VALUE;
+}
+
+static bool isValid(ColorAspects::Range r) {
+    return r <= ColorAspects::RangeOther;
+}
+
+static bool isDefined(ColorAspects::Range r) {
+    return r <= ColorAspects::RangeLimited;
+}
+
+//  static
+int32_t ColorUtils::wrapColorAspectsIntoColorRange(ColorAspects::Range range) {
+    ColorRange res;
+    if (sRanges.map(range, &res)) {
+        return res;
+    } else if (!isValid(range)) {
+        return kColorRangeUnspecified;
+    } else {
+        CHECK(!isDefined(range));
+        // all platform values are in sRanges
+        return kColorRangeVendorStart + range;
+    }
+}
+
+//static
+status_t ColorUtils::unwrapColorAspectsFromColorRange(
+        int32_t range, ColorAspects::Range *aspect) {
+    if (sRanges.map((ColorRange)range, aspect)) {
+        return OK;
+    }
+
+    int32_t start = kColorRangeVendorStart;
+    int32_t numRanges = ColorAspects::RangeOther + 1; // 0x100
+    if (range >= start && range < start + numRanges) {
+        *aspect = (ColorAspects::Range)(range - start);
+        return OK;
+    }
+    *aspect = ColorAspects::RangeOther;
+    return BAD_VALUE;
+}
+
+static bool isValid(ColorAspects::Transfer t) {
+    return t <= ColorAspects::TransferOther;
+}
+
+static bool isDefined(ColorAspects::Transfer t) {
+    return t <= ColorAspects::TransferHLG
+            || (t >= ColorAspects::TransferSMPTE240M && t <= ColorAspects::TransferST428);
+}
+
+//  static
+int32_t ColorUtils::wrapColorAspectsIntoColorTransfer(
+        ColorAspects::Transfer transfer) {
+    ColorTransfer res;
+    if (sTransfers.map(transfer, &res)) {
+        return res;
+    } else if (!isValid(transfer)) {
+        return kColorTransferUnspecified;
+    } else if (isDefined(transfer)) {
+        return kColorTransferExtendedStart + transfer;
+    } else {
+        // all platform values are in sRanges
+        return kColorTransferVendorStart + transfer;
+    }
+}
+
+//static
+status_t ColorUtils::unwrapColorAspectsFromColorTransfer(
+        int32_t transfer, ColorAspects::Transfer *aspect) {
+    if (sTransfers.map((ColorTransfer)transfer, aspect)) {
+        return OK;
+    }
+
+    int32_t start = kColorTransferExtendedStart;
+    int32_t numTransfers = ColorAspects::TransferST428 + 1;
+    if (transfer >= (int32_t)kColorTransferVendorStart) {
+        start = kColorTransferVendorStart;
+        numTransfers = ColorAspects::TransferOther + 1; // 0x100
+    }
+    if (transfer >= start && transfer < start + numTransfers) {
+        *aspect = (ColorAspects::Transfer)(transfer - start);
+        return OK;
+    }
+    *aspect = ColorAspects::TransferOther;
+    return BAD_VALUE;
+}
+
+// static
+status_t ColorUtils::convertPlatformColorAspectsToCodecAspects(
+    int32_t range, int32_t standard, int32_t transfer, ColorAspects &aspects) {
+    status_t res1 = unwrapColorAspectsFromColorRange(range, &aspects.mRange);
+    status_t res2 = unwrapColorAspectsFromColorStandard(
+            standard, &aspects.mPrimaries, &aspects.mMatrixCoeffs);
+    status_t res3 = unwrapColorAspectsFromColorTransfer(transfer, &aspects.mTransfer);
+    return res1 != OK ? res1 : (res2 != OK ? res2 : res3);
+}
+
+// static
+status_t ColorUtils::convertCodecColorAspectsToPlatformAspects(
+    const ColorAspects &aspects, int32_t *range, int32_t *standard, int32_t *transfer) {
+    *range = wrapColorAspectsIntoColorRange(aspects.mRange);
+    *standard = wrapColorAspectsIntoColorStandard(aspects.mPrimaries, aspects.mMatrixCoeffs);
+    *transfer = wrapColorAspectsIntoColorTransfer(aspects.mTransfer);
+    if (isValid(aspects.mRange) && isValid(aspects.mPrimaries)
+            && isValid(aspects.mMatrixCoeffs) && isValid(aspects.mTransfer)) {
+        return OK;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+// static
+void ColorUtils::setDefaultPlatformColorAspectsIfNeeded(
+        int32_t &range, int32_t &standard, int32_t &transfer,
+        int32_t width, int32_t height) {
+    if (range == ColorUtils::kColorRangeUnspecified) {
+        range = ColorUtils::kColorRangeLimited;
+    }
+
+    if (standard == ColorUtils::kColorStandardUnspecified) {
+        // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601
+        // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between.
+        if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
+            standard = ColorUtils::kColorStandardBT2020;
+        } else if ((width <= 720 && height > 480) || (height <= 720 && width > 480)) {
+            standard = ColorUtils::kColorStandardBT601_625;
+        } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) {
+            standard = ColorUtils::kColorStandardBT601_525;
+        } else {
+            standard = ColorUtils::kColorStandardBT709;
+        }
+    }
+
+    if (transfer == ColorUtils::kColorTransferUnspecified) {
+        transfer = ColorUtils::kColorTransferSMPTE_170M;
+    }
+}
+
+// static
+void ColorUtils::setDefaultCodecColorAspectsIfNeeded(
+        ColorAspects &aspects, int32_t width, int32_t height) {
+    ColorAspects::MatrixCoeffs coeffs;
+    ColorAspects::Primaries primaries;
+
+    // Default to BT2020, BT709 or BT601 based on size. Allow 2.35:1 aspect ratio. Limit BT601
+    // to PAL or smaller, BT2020 to 4K or larger, leaving BT709 for all resolutions in between.
+    if (width >= 3840 || height >= 3840 || width * (int64_t)height >= 3840 * 1634) {
+        primaries = ColorAspects::PrimariesBT2020;
+        coeffs = ColorAspects::MatrixBT2020;
+    } else if ((width <= 720 && height > 480 && height <= 576)
+            || (height <= 720 && width > 480 && width <= 576)) {
+        primaries = ColorAspects::PrimariesBT601_6_625;
+        coeffs = ColorAspects::MatrixBT601_6;
+    } else if ((width <= 720 && height <= 480) || (height <= 720 && width <= 480)) {
+        primaries = ColorAspects::PrimariesBT601_6_525;
+        coeffs = ColorAspects::MatrixBT601_6;
+    } else {
+        primaries = ColorAspects::PrimariesBT709_5;
+        coeffs = ColorAspects::MatrixBT709_5;
+    }
+
+    if (aspects.mRange == ColorAspects::RangeUnspecified) {
+        aspects.mRange = ColorAspects::RangeLimited;
+    }
+
+    if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+        aspects.mPrimaries = primaries;
+    }
+    if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+        aspects.mMatrixCoeffs = coeffs;
+    }
+    if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
+        aspects.mTransfer = ColorAspects::TransferSMPTE170M;
+    }
+}
+
+}  // namespace android
+
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index ed807c6..7f8ed1f 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -142,6 +142,8 @@
 {
     const SwAudioOutputCollection &outputs = mPolicyEngine->mApmObserver->getOutputs();
 
+    //FIXME: getStrategyForUsage() should return STRATEGY_ACCESSIBILITY and getDeviceForStrategy()
+    // should be implemented accordingly for STRATEGY_ACCESSIBILITY
     if (usage == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY &&
             (outputs.isStreamActive(AUDIO_STREAM_RING) ||
              outputs.isStreamActive(AUDIO_STREAM_ALARM))) {
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 43664e6..f8ba3f2 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -195,18 +195,9 @@
 
 routing_strategy Engine::getStrategyForUsage(audio_usage_t usage)
 {
-    const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
-
     // usage to strategy mapping
     switch (usage) {
     case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
-        if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
-                outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
-            return STRATEGY_SONIFICATION;
-        }
-        if (isInCall()) {
-            return STRATEGY_PHONE;
-        }
         return STRATEGY_ACCESSIBILITY;
 
     case AUDIO_USAGE_MEDIA:
@@ -245,6 +236,17 @@
 
     const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();
 
+    return getDeviceForStrategyInt(strategy, (DeviceVector&)availableOutputDevices,
+                                   availableInputDevices, outputs);
+}
+
+
+
+audio_devices_t Engine::getDeviceForStrategyInt(routing_strategy strategy,
+                                                DeviceVector &availableOutputDevices,
+                                                const DeviceVector &availableInputDevices,
+                                                const SwAudioOutputCollection &outputs) const
+{
     uint32_t device = AUDIO_DEVICE_NONE;
     uint32_t availableOutputDevicesType = availableOutputDevices.types();
 
@@ -260,14 +262,16 @@
 
     case STRATEGY_SONIFICATION_RESPECTFUL:
         if (isInCall()) {
-            device = getDeviceForStrategy(STRATEGY_SONIFICATION);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
         } else if (outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
                 SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
             // while media is playing on a remote device, use the the sonification behavior.
             // Note that we test this usecase before testing if media is playing because
             //   the isStreamActive() method only informs about the activity of a stream, not
             //   if it's for local playback. Note also that we use the same delay between both tests
-            device = getDeviceForStrategy(STRATEGY_SONIFICATION);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
             //user "safe" speaker if available instead of normal speaker to avoid triggering
             //other acoustic safety mechanisms for notification
             if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
@@ -275,12 +279,15 @@
                 device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
                 device &= ~AUDIO_DEVICE_OUT_SPEAKER;
             }
-        } else if (outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+        } else if (outputs.isStreamActive(
+                                AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
             // while media is playing (or has recently played), use the same device
-            device = getDeviceForStrategy(STRATEGY_MEDIA);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
         } else {
             // when media is not playing anymore, fall back on the sonification behavior
-            device = getDeviceForStrategy(STRATEGY_SONIFICATION);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
             //user "safe" speaker if available instead of normal speaker to avoid triggering
             //other acoustic safety mechanisms for notification
             if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
@@ -294,7 +301,8 @@
     case STRATEGY_DTMF:
         if (!isInCall()) {
             // when off call, DTMF strategy follows the same rules as MEDIA strategy
-            device = getDeviceForStrategy(STRATEGY_MEDIA);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         // when in call, DTMF and PHONE strategies follow the same rules
@@ -321,8 +329,8 @@
                 availableOutputDevicesType = availPrimaryOutputDevices;
             }
         }
-        // for phone strategy, we first consider the forced use and then the available devices by order
-        // of priority
+        // for phone strategy, we first consider the forced use and then the available devices by
+        // order of priority
         switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
         case AUDIO_POLICY_FORCE_BT_SCO:
             if (!isInCall() || strategy != STRATEGY_DTMF) {
@@ -350,6 +358,8 @@
             if (device) break;
             device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
             if (device) break;
+            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
+            if (device) break;
             device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
             if (device) break;
             if (!isInCall()) {
@@ -391,8 +401,6 @@
                 device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
                 if (device) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
-            if (device) break;
             device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
             if (device) break;
             device = mApmObserver->getDefaultOutputDevice()->type();
@@ -408,7 +416,8 @@
         // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
         // handleIncallSonification().
         if (isInCall()) {
-            device = getDeviceForStrategy(STRATEGY_PHONE);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         // FALL THROUGH
@@ -429,7 +438,6 @@
         // The second device used for sonification is the same as the device used by media strategy
         // FALL THROUGH
 
-    // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now
     case STRATEGY_ACCESSIBILITY:
         if (strategy == STRATEGY_ACCESSIBILITY) {
             // do not route accessibility prompts to a digital output currently configured with a
@@ -443,20 +451,35 @@
                     availableOutputDevicesType = availableOutputDevices.types() & ~devices;
                 }
             }
+            availableOutputDevices =
+                    availableOutputDevices.getDevicesFromType(availableOutputDevicesType);
+            if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
+                    outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
+                return getDeviceForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
+            }
+            if (isInCall()) {
+                return getDeviceForStrategyInt(
+                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
+            }
         }
+        // For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
         // FALL THROUGH
 
+    // FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
     case STRATEGY_REROUTING:
     case STRATEGY_MEDIA: {
         uint32_t device2 = AUDIO_DEVICE_NONE;
         if (strategy != STRATEGY_SONIFICATION) {
             // no sonification on remote submix (e.g. WFD)
-            if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
+            if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                                                 String8("0")) != 0) {
                 device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
             }
         }
         if (isInCall() && (strategy == STRATEGY_MEDIA)) {
-            device = getDeviceForStrategy(STRATEGY_PHONE);
+            device = getDeviceForStrategyInt(
+                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         if ((device2 == AUDIO_DEVICE_NONE) &&
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 8b6eaf6..ed93d1c 100755
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -125,6 +125,10 @@
     routing_strategy getStrategyForStream(audio_stream_type_t stream);
     routing_strategy getStrategyForUsage(audio_usage_t usage);
     audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
+    audio_devices_t getDeviceForStrategyInt(routing_strategy strategy,
+                                            DeviceVector &availableOutputDevices,
+                                            const DeviceVector &availableInputDevices,
+                                            const SwAudioOutputCollection &outputs) const;
     audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
     audio_mode_t mPhoneState;  /**< current phone state. */
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a7b90f4..21107a1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1794,8 +1794,15 @@
 {
     ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
     mVolumeCurves->initStreamVolume(stream, indexMin, indexMax);
-    if (stream == AUDIO_STREAM_MUSIC) {
-        mVolumeCurves->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);
+
+    // initialize other private stream volumes which follow this one
+    routing_strategy strategy = getStrategy(stream);
+    for (int curStream = 0; curStream < AUDIO_STREAM_CNT; curStream++) {
+        routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
+        if (!strategiesMatchForvolume(strategy, curStrategy)) {
+            continue;
+        }
+        mVolumeCurves->initStreamVolume((audio_stream_type_t)curStream, indexMin, indexMax);
     }
 }
 
@@ -1823,38 +1830,43 @@
     if (device == AUDIO_DEVICE_OUT_DEFAULT) {
         mVolumeCurves->clearCurrentVolumeIndex(stream);
     }
-    mVolumeCurves->addCurrentVolumeIndex(stream, device, index);
+
+    // update other private stream volumes which follow this one
+    routing_strategy strategy = getStrategy(stream);
+    for (int curStream = 0; curStream < AUDIO_STREAM_CNT; curStream++) {
+        routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
+        if (!strategiesMatchForvolume(strategy, curStrategy)) {
+            continue;
+        }
+        mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
+    }
 
     // update volume on all outputs whose current device is also selected by the same
     // strategy as the device specified by the caller
-    audio_devices_t selectedDevices = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
-    // it is possible that the requested device is not selected by the strategy (e.g an explicit
-    // audio patch is active causing getDevicesForStream() to return this device. We must make
-    // sure that the device passed is part of the devices considered when applying volume below.
-    selectedDevices |= device;
-
-    //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
-    audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
-    if (stream == AUDIO_STREAM_MUSIC) {
-        mVolumeCurves->addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
-        accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
-    }
-
     status_t status = NO_ERROR;
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
         audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
-        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & selectedDevices) != 0)) {
-            status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);
-            if (volStatus != NO_ERROR) {
-                status = volStatus;
+        for (int curStream = 0; curStream < AUDIO_STREAM_CNT; curStream++) {
+            routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
+            if (!strategiesMatchForvolume(strategy, curStrategy)) {
+                continue;
             }
-        }
-        if ((accessibilityDevice != AUDIO_DEVICE_NONE) &&
-                ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & accessibilityDevice) != 0)))
-        {
-            status_t volStatus = checkAndSetVolume(AUDIO_STREAM_ACCESSIBILITY,
-                                                   index, desc, curDevice);
+            audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, true /*fromCache*/);
+            // it is possible that the requested device is not selected by the strategy
+            // (e.g an explicit audio patch is active causing getDevicesForStream()
+            // to return this device. We must make sure that the device passed is part of the
+            // devices considered when applying volume below.
+            curStreamDevice |= device;
+
+            if (((device == AUDIO_DEVICE_OUT_DEFAULT) ||
+                    ((curDevice & curStreamDevice) != 0))) {
+                status_t volStatus =
+                        checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice);
+                if (volStatus != NO_ERROR) {
+                    status = volStatus;
+                }
+            }
         }
     }
     return status;
@@ -1957,7 +1969,17 @@
 
 bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
 {
-    return mOutputs.isStreamActive(stream, inPastMs);
+    bool active = false;
+    routing_strategy strategy = getStrategy(stream);
+    for (int curStream = 0; curStream < AUDIO_STREAM_CNT && !active; curStream++) {
+        routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
+        if (!strategiesMatchForvolume(strategy, curStrategy)) {
+            continue;
+        }
+        active = mOutputs.isStreamActive((audio_stream_type_t)curStream, inPastMs);
+    }
+
+    return active;
 }
 
 bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
@@ -2838,7 +2860,7 @@
     disconnectAudioSource(sourceDesc);
 
     routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
-    audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+    audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
     sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
 
     audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
@@ -2971,7 +2993,7 @@
     }
     removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
 
-    audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+    audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
     sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
     if (swOutputDesc != 0) {
         stopSource(swOutputDesc, stream, false);
@@ -4170,10 +4192,10 @@
     //      use device for strategy phone
     // 3: the strategy for enforced audible is active but not enforced on the output:
     //      use the device for strategy enforced audible
-    // 4: the strategy accessibility is active on the output:
-    //      use device for strategy accessibility
-    // 5: the strategy sonification is active on the output:
+    // 4: the strategy sonification is active on the output:
     //      use device for strategy sonification
+    // 5: the strategy accessibility is active on the output:
+    //      use device for strategy accessibility
     // 6: the strategy "respectful" sonification is active on the output:
     //      use device for strategy "respectful" sonification
     // 7: the strategy media is active on the output:
@@ -4190,10 +4212,10 @@
         device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
         device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
-    } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
-        device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)) {
         device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+    } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
+        device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) {
         device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
     } else if (isStrategyActive(outputDesc, STRATEGY_MEDIA)) {
@@ -4229,6 +4251,13 @@
     return device;
 }
 
+bool AudioPolicyManager::strategiesMatchForvolume(routing_strategy strategy1,
+                                                  routing_strategy strategy2) {
+    return ((strategy1 == strategy2) ||
+            ((strategy1 == STRATEGY_ACCESSIBILITY) && (strategy2 == STRATEGY_MEDIA)) ||
+            ((strategy1 == STRATEGY_MEDIA) && (strategy2 == STRATEGY_ACCESSIBILITY)));
+}
+
 uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
     return (uint32_t)getStrategy(stream);
 }
@@ -4240,16 +4269,22 @@
     if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_PUBLIC_CNT) {
         return AUDIO_DEVICE_NONE;
     }
-    audio_devices_t devices;
+    audio_devices_t devices = AUDIO_DEVICE_NONE;
     routing_strategy strategy = getStrategy(stream);
-    devices = getDeviceForStrategy(strategy, true /*fromCache*/);
-    SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(devices, mOutputs);
-    for (size_t i = 0; i < outputs.size(); i++) {
-        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
-        if (isStrategyActive(outputDesc, strategy)) {
-            devices = outputDesc->device();
-            break;
+    for (int curStrategy = 0; curStrategy < NUM_STRATEGIES; curStrategy++) {
+        if (!strategiesMatchForvolume(strategy, (routing_strategy)curStrategy)) {
+            continue;
         }
+        audio_devices_t curDevices =
+                getDeviceForStrategy((routing_strategy)curStrategy, true /*fromCache*/);
+        SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(curDevices, mOutputs);
+        for (size_t i = 0; i < outputs.size(); i++) {
+            sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
+            if (isStrategyActive(outputDesc, (routing_strategy)curStrategy)) {
+                curDevices |= outputDesc->device();
+            }
+        }
+        devices |= curDevices;
     }
 
     /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
@@ -4361,15 +4396,8 @@
     // the device = the device from the descriptor in the RouteMap, and exit.
     for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
         sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
-        routing_strategy strat = getStrategy(route->mStreamType);
-        // Special case for accessibility strategy which must follow any strategy it is
-        // currently remapped to
-        bool strategyMatch = (strat == strategy) ||
-                             ((strategy == STRATEGY_ACCESSIBILITY) &&
-                              ((mEngine->getStrategyForUsage(
-                                      AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY) == strat) ||
-                               (strat == STRATEGY_MEDIA)));
-        if (strategyMatch && route->isActive()) {
+        routing_strategy routeStrategy = getStrategy(route->mStreamType);
+        if ((routeStrategy == strategy) && route->isActive()) {
             return route->mDeviceDescriptor->type();
         }
     }
@@ -5007,15 +5035,6 @@
     case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
         return AUDIO_STREAM_MUSIC;
     case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
-        if (isStreamActive(AUDIO_STREAM_ALARM)) {
-            return AUDIO_STREAM_ALARM;
-        }
-        if (isStreamActive(AUDIO_STREAM_RING)) {
-            return AUDIO_STREAM_RING;
-        }
-        if (isInCall()) {
-            return AUDIO_STREAM_VOICE_CALL;
-        }
         return AUDIO_STREAM_ACCESSIBILITY;
     case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
         return AUDIO_STREAM_SYSTEM;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 38700fc..d6e48ab 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -506,6 +506,9 @@
         void clearAudioSources(uid_t uid);
 
 
+        static bool strategiesMatchForvolume(routing_strategy strategy1,
+                                             routing_strategy strategy2);
+
         uid_t mUidCached;
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index dfbe200..9f8eac6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -534,9 +534,11 @@
         mOutputStreams[i]->dump(fd,args);
     }
 
-    lines = String8("    Camera3 Buffer Manager:\n");
-    write(fd, lines.string(), lines.size());
-    mBufferManager->dump(fd, args);
+    if (mBufferManager != NULL) {
+        lines = String8("    Camera3 Buffer Manager:\n");
+        write(fd, lines.string(), lines.size());
+        mBufferManager->dump(fd, args);
+    }
 
     lines = String8("    In-flight requests:\n");
     if (mInFlightMap.size() == 0) {
diff --git a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy b/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
index 75fb9c8..4be96d5 100644
--- a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
+++ b/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
@@ -39,6 +39,7 @@
 sched_get_priority_min: 1
 statfs64: 1
 sched_setscheduler: 1
+fstatat64: 1
 
 # for attaching to debuggerd on process crash
 sigaction: 1