Merge "Fix tapping on more than one failure notification."
diff --git a/core/res/res/drawable-hdpi/ic_user_secure.png b/core/res/res/drawable-hdpi/ic_user_secure.png
new file mode 100644
index 0000000..60dcf2a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_user_secure.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_user_secure.png b/core/res/res/drawable-mdpi/ic_user_secure.png
new file mode 100644
index 0000000..0dea77a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_user_secure.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_user_secure.png b/core/res/res/drawable-xhdpi/ic_user_secure.png
new file mode 100644
index 0000000..a6ef51a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_user_secure.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_user_secure.png b/core/res/res/drawable-xxhdpi/ic_user_secure.png
new file mode 100644
index 0000000..e6154e5
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_user_secure.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_user_secure.png b/core/res/res/drawable-xxxhdpi/ic_user_secure.png
new file mode 100644
index 0000000..9a3959b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_user_secure.png
Binary files differ
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 73cd175..f75f023 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2522,6 +2522,7 @@
   <java-symbol type="string" name="user_encrypted_title" />
   <java-symbol type="string" name="user_encrypted_message" />
   <java-symbol type="string" name="user_encrypted_detail" />
+  <java-symbol type="drawable" name="ic_user_secure" />
 
   <java-symbol type="string" name="usb_mtp_launch_notification_title" />
   <java-symbol type="string" name="usb_mtp_launch_notification_description" />
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 04e0755..2184755 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -663,13 +663,7 @@
 }
 
 void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
-    TessellationCache::vertexBuffer_pair_t buffers;
-    renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform,
-            op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath,
-            &op.shadowMatrixXY, &op.shadowMatrixZ,
-            op.lightCenter, renderer.getLightInfo().lightRadius,
-            buffers);
-
+    TessellationCache::vertexBuffer_pair_t buffers = *(op.shadowTask->getResult());
     renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
 }
 
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 10c4698..55ea935 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -45,13 +45,11 @@
      * Position agnostic shadow lighting info. Used with all shadow ops in scene.
      */
     struct LightInfo {
-        LightInfo() : LightInfo(0, 0, 0) {}
-        LightInfo(float lightRadius, uint8_t ambientShadowAlpha,
+        LightInfo() : LightInfo(0, 0) {}
+        LightInfo(uint8_t ambientShadowAlpha,
                 uint8_t spotShadowAlpha)
-                : lightRadius(lightRadius)
-                , ambientShadowAlpha(ambientShadowAlpha)
+                : ambientShadowAlpha(ambientShadowAlpha)
                 , spotShadowAlpha(spotShadowAlpha) {}
-        float lightRadius;
         uint8_t ambientShadowAlpha;
         uint8_t spotShadowAlpha;
     };
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 87844f9..a542c26 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -63,16 +63,11 @@
     }
 }
 
-ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) {
-    transform = *snapshot.transform;
-
-    // Since the op doesn't have known bounds, we conservatively set the mapped bounds
-    // to the current clipRect, and clipSideFlags to Full.
-    clipState = snapshot.mutateClipArea().serializeClip(allocator);
-    LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
-    clippedBounds = clipState->rect;
-    clipSideFlags = OpClipSideFlags::Full;
-}
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot)
+        : transform(*snapshot.transform)
+        , clipState(snapshot.mutateClipArea().serializeClip(allocator))
+        , clippedBounds(clipState->rect)
+        , clipSideFlags(OpClipSideFlags::Full) {}
 
 ResolvedRenderState::ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect)
         : transform(Matrix4::identity())
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 4740e1f..57e5b9d 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -33,17 +33,11 @@
 
 FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
         uint32_t viewportWidth, uint32_t viewportHeight,
-        const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
-        : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightCenter,
-                Rect(0, 0, 0, 0)) {
-}
-
-
-FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
-        uint32_t viewportWidth, uint32_t viewportHeight,
-        const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
-        const Rect &contentDrawBounds)
-        : mCanvasState(*this) {
+        const std::vector< sp<RenderNode> >& nodes,
+        const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches* caches)
+        : mCanvasState(*this)
+        , mCaches(caches)
+        , mLightRadius(lightGeometry.radius) {
     ATRACE_NAME("prepare drawing commands");
 
     mLayerBuilders.reserve(layers.entries().size());
@@ -55,7 +49,7 @@
     mLayerStack.push_back(0);
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
             clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
-            lightCenter);
+            lightGeometry.center);
 
     // Render all layers to be updated, in order. Defer in reverse order, so that they'll be
     // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
@@ -367,13 +361,28 @@
         casterPath = frameAllocatedPath;
     }
 
-    ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
-            mCanvasState.getLocalClipBounds(),
-            mCanvasState.currentSnapshot()->getRelativeLightCenter());
-    BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
-            mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
-    if (CC_LIKELY(bakedOpState)) {
-        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
+
+    if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
+        Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
+        Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
+        node.applyViewPropertyTransforms(shadowMatrixXY, false);
+        node.applyViewPropertyTransforms(shadowMatrixZ, true);
+
+        LOG_ALWAYS_FATAL_IF(!mCaches, "Caches needed for shadows");
+        sp<TessellationCache::ShadowTask> task = mCaches->tessellationCache.getShadowTask(
+                mCanvasState.currentTransform(),
+                mCanvasState.getLocalClipBounds(),
+                casterAlpha >= 1.0f,
+                casterPath,
+                &shadowMatrixXY, &shadowMatrixZ,
+                mCanvasState.currentSnapshot()->getRelativeLightCenter(),
+                mLightRadius);
+        ShadowOp* shadowOp = mAllocator.create<ShadowOp>(task, casterAlpha);
+        BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
+                mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
+        if (CC_LIKELY(bakedOpState)) {
+            currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
+        }
     }
 }
 
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 01d52ce..f44306a 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -55,14 +55,24 @@
  */
 class FrameBuilder : public CanvasStateClient {
 public:
+    struct LightGeometry {
+        Vector3 center;
+        float radius;
+    };
+
+    // TODO: remove
     FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
             uint32_t viewportWidth, uint32_t viewportHeight,
-            const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
+            const std::vector< sp<RenderNode> >& nodes,
+            const LightGeometry& lightGeometry,
+            Caches* caches)
+            : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightGeometry, Rect(), caches) {}
 
     FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
             uint32_t viewportWidth, uint32_t viewportHeight,
-            const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
-            const Rect &contentDrawBounds);
+            const std::vector< sp<RenderNode> >& nodes,
+            const LightGeometry& lightGeometry,
+            const Rect &contentDrawBounds, Caches* caches);
 
     virtual ~FrameBuilder() {}
 
@@ -216,7 +226,11 @@
 
     CanvasState mCanvasState;
 
-    // contains ResolvedOps and Batches
+    Caches* mCaches = nullptr;
+
+    float mLightRadius;
+
+    // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches
     LinearAllocator mAllocator;
 };
 
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index d27064b..bb26e2e 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -22,6 +22,7 @@
 #include "Matrix.h"
 #include "Rect.h"
 #include "RenderNode.h"
+#include "TessellationCache.h"
 #include "utils/LinearAllocator.h"
 #include "Vector.h"
 
@@ -346,25 +347,13 @@
  * State construction handles these properties specially, ignoring matrix/bounds.
  */
 struct ShadowOp : RecordedOp {
-    ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
-            const Rect& localClipRect, const Vector3& lightCenter)
+    ShadowOp(sp<TessellationCache::ShadowTask>& shadowTask, float casterAlpha)
             : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
-            , shadowMatrixXY(casterOp.localMatrix)
-            , shadowMatrixZ(casterOp.localMatrix)
-            , casterAlpha(casterAlpha)
-            , casterPath(casterPath)
-            , localClipRect(localClipRect)
-            , lightCenter(lightCenter) {
-        const RenderNode& node = *casterOp.renderNode;
-        node.applyViewPropertyTransforms(shadowMatrixXY, false);
-        node.applyViewPropertyTransforms(shadowMatrixZ, true);
+            , shadowTask(shadowTask)
+            , casterAlpha(casterAlpha) {
     };
-    Matrix4 shadowMatrixXY;
-    Matrix4 shadowMatrixZ;
+    sp<TessellationCache::ShadowTask> shadowTask;
     const float casterAlpha;
-    const SkPath* casterPath;
-    const Rect localClipRect;
-    const Vector3 lightCenter;
 };
 
 struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 0835c29..461e819 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -160,45 +160,6 @@
 // Shadow tessellation task processing
 ///////////////////////////////////////////////////////////////////////////////
 
-class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
-public:
-    ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
-            const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
-            const Vector3& lightCenter, float lightRadius)
-        : drawTransform(*drawTransform)
-        , localClip(localClip)
-        , opaque(opaque)
-        , casterPerimeter(*casterPerimeter)
-        , transformXY(*transformXY)
-        , transformZ(*transformZ)
-        , lightCenter(lightCenter)
-        , lightRadius(lightRadius) {
-    }
-
-    ~ShadowTask() {
-        TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
-        delete bufferPair->getFirst();
-        delete bufferPair->getSecond();
-        delete bufferPair;
-    }
-
-    /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
-     * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
-     * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
-     *
-     * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
-     * before tearning down single-frame LinearAllocators.
-     */
-    const Matrix4 drawTransform;
-    const Rect localClip;
-    bool opaque;
-    const SkPath casterPerimeter;
-    const Matrix4 transformXY;
-    const Matrix4 transformZ;
-    const Vector3 lightCenter;
-    const float lightRadius;
-};
-
 static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) {
     // map z coordinate with true 3d matrix
     point.z = transformZ->mapZ(point);
@@ -288,7 +249,7 @@
     ~ShadowProcessor() {}
 
     virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) override {
-        ShadowTask* t = static_cast<ShadowTask*>(task.get());
+        TessellationCache::ShadowTask* t = static_cast<TessellationCache::ShadowTask*>(task.get());
         ATRACE_NAME("shadow tessellation");
 
         VertexBuffer* ambientBuffer = new VertexBuffer;
@@ -415,6 +376,29 @@
     outBuffers = *(task->getResult());
 }
 
+sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
+        const Matrix4* drawTransform, const Rect& localClip,
+        bool opaque, const SkPath* casterPerimeter,
+        const Matrix4* transformXY, const Matrix4* transformZ,
+        const Vector3& lightCenter, float lightRadius) {
+    ShadowDescription key(casterPerimeter, drawTransform);
+    ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
+    if (!task) {
+        precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
+                transformXY, transformZ, lightCenter, lightRadius);
+        task = static_cast<ShadowTask*>(mShadowCache.get(key));
+    }
+    LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
+    return task;
+}
+
+TessellationCache::ShadowTask::~ShadowTask() {
+    TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
+    delete bufferPair->getFirst();
+    delete bufferPair->getSecond();
+    delete bufferPair;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Tessellation precaching
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index 06e567e..977c2d9e 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -26,6 +26,7 @@
 #include "utils/Pair.h"
 
 #include <SkPaint.h>
+#include <SkPath.h>
 
 #include <utils/LruCache.h>
 #include <utils/Mutex.h>
@@ -33,7 +34,6 @@
 
 class SkBitmap;
 class SkCanvas;
-class SkPath;
 struct SkRect;
 
 namespace android {
@@ -89,6 +89,40 @@
         hash_t hash() const;
     };
 
+    class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
+    public:
+        ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+                const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
+                const Vector3& lightCenter, float lightRadius)
+            : drawTransform(*drawTransform)
+            , localClip(localClip)
+            , opaque(opaque)
+            , casterPerimeter(*casterPerimeter)
+            , transformXY(*transformXY)
+            , transformZ(*transformZ)
+            , lightCenter(lightCenter)
+            , lightRadius(lightRadius) {
+        }
+
+        ~ShadowTask();
+
+        /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
+         * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
+         * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
+         *
+         * These deep copies could be avoided, long term, by cancelling or flushing outstanding
+         * tasks before tearing down single-frame LinearAllocators.
+         */
+        const Matrix4 drawTransform;
+        const Rect localClip;
+        bool opaque;
+        const SkPath casterPerimeter;
+        const Matrix4 transformXY;
+        const Matrix4 transformZ;
+        const Vector3 lightCenter;
+        const float lightRadius;
+    };
+
     TessellationCache();
     ~TessellationCache();
 
@@ -133,17 +167,22 @@
     const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint,
             float width, float height, float rx, float ry);
 
+    // TODO: delete these when switching to HWUI_NEW_OPS
     void precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
             bool opaque, const SkPath* casterPerimeter,
             const Matrix4* transformXY, const Matrix4* transformZ,
             const Vector3& lightCenter, float lightRadius);
-
     void getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
             bool opaque, const SkPath* casterPerimeter,
             const Matrix4* transformXY, const Matrix4* transformZ,
             const Vector3& lightCenter, float lightRadius,
             vertexBuffer_pair_t& outBuffers);
 
+    sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip,
+            bool opaque, const SkPath* casterPerimeter,
+            const Matrix4* transformXY, const Matrix4* transformZ,
+            const Vector3& lightCenter, float lightRadius);
+
 private:
     class Buffer;
     class TessellationTask;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e7cf3ec..d411621 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -33,10 +33,6 @@
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
 
-#if HWUI_NEW_OPS
-#include "FrameBuilder.h"
-#endif
-
 #include <cutils/properties.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <private/hwui/DrawGlInfo.h>
@@ -152,7 +148,7 @@
 void CanvasContext::setup(int width, int height, float lightRadius,
         uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
 #if HWUI_NEW_OPS
-    mLightInfo.lightRadius = lightRadius;
+    mLightGeometry.radius = lightRadius;
     mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
     mLightInfo.spotShadowAlpha = spotShadowAlpha;
 #else
@@ -163,7 +159,7 @@
 
 void CanvasContext::setLightCenter(const Vector3& lightCenter) {
 #if HWUI_NEW_OPS
-    mLightCenter = lightCenter;
+    mLightGeometry.center = lightCenter;
 #else
     if (!mCanvas) return;
     mCanvas->setLightCenter(lightCenter);
@@ -345,7 +341,7 @@
 
 #if HWUI_NEW_OPS
     FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
-            mRenderNodes, mLightCenter, mContentDrawBounds);
+            mRenderNodes, mLightGeometry, mContentDrawBounds, &Caches::getInstance());
     mLayerUpdateQueue.clear();
     BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
             mOpaque, mLightInfo);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 270fb1f..63a7977 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -31,6 +31,7 @@
 #if HWUI_NEW_OPS
 #include "BakedOpDispatcher.h"
 #include "BakedOpRenderer.h"
+#include "FrameBuilder.h"
 #endif
 
 #include <cutils/compiler.h>
@@ -197,7 +198,7 @@
     OpenGLRenderer* mCanvas = nullptr;
 #if HWUI_NEW_OPS
     BakedOpRenderer::LightInfo mLightInfo;
-    Vector3 mLightCenter = { 0, 0, 0 };
+    FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };
 #endif
 
     bool mHaveNewSurface = false;
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index f9c2b67..7845eb4 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -37,7 +37,8 @@
 using namespace android::uirenderer::test;
 
 const LayerUpdateQueue sEmptyLayerUpdateQueue;
-const Vector3 sLightCenter = {100, 100, 100};
+const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
+const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
 static std::vector<sp<RenderNode>> createTestNodeList() {
     auto node = TestUtils::createNode(0, 0, 200, 200,
@@ -67,7 +68,7 @@
     StartBenchmarkTiming();
     for (int i = 0; i < iters; i++) {
         FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-                nodes, sLightCenter);
+                nodes, sLightGeometry, nullptr);
         MicroBench::DoNotOptimize(&frameBuilder);
     }
     StopBenchmarkTiming();
@@ -77,7 +78,6 @@
 void BM_FrameBuilder_deferAndRender::Run(int iters) {
     TestUtils::runOnRenderThread([this, iters](RenderThread& thread) {
         auto nodes = createTestNodeList();
-        BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 };
 
         RenderState& renderState = thread.renderState();
         Caches& caches = Caches::getInstance();
@@ -85,9 +85,9 @@
         StartBenchmarkTiming();
         for (int i = 0; i < iters; i++) {
             FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-                    nodes, sLightCenter);
+                    nodes, sLightGeometry, nullptr);
 
-            BakedOpRenderer renderer(caches, renderState, true, lightInfo);
+            BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
             frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
             MicroBench::DoNotOptimize(&renderer);
         }
@@ -119,7 +119,7 @@
     for (int i = 0; i < iters; i++) {
         FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
                 SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
-                nodes, sLightCenter);
+                nodes, sLightGeometry, nullptr);
         MicroBench::DoNotOptimize(&frameBuilder);
     }
     benchmark.StopBenchmarkTiming();
@@ -129,7 +129,6 @@
         int iters, const char* sceneName) {
     TestUtils::runOnRenderThread([&benchmark, iters, sceneName](RenderThread& thread) {
         auto nodes = getSyncedSceneNodes(sceneName);
-        BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 }; // TODO!
 
         RenderState& renderState = thread.renderState();
         Caches& caches = Caches::getInstance();
@@ -138,9 +137,9 @@
         for (int i = 0; i < iters; i++) {
             FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
                     SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
-                    nodes, sLightCenter);
+                    nodes, sLightGeometry, nullptr);
 
-            BakedOpRenderer renderer(caches, renderState, true, lightInfo);
+            BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
             frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
             MicroBench::DoNotOptimize(&renderer);
         }
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 618df14..f49dd3f 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -30,7 +30,8 @@
 namespace uirenderer {
 
 const LayerUpdateQueue sEmptyLayerUpdateQueue;
-const Vector3 sLightCenter = {100, 100, 100};
+const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
+
 
 /**
  * Virtual class implemented by each test to redirect static operation / state transitions to
@@ -132,7 +133,7 @@
         canvas.drawBitmap(bitmap, 10, 10, nullptr);
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
@@ -158,7 +159,7 @@
         canvas.drawPoint(50, 50, strokedPaint);
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SimpleStrokeTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex());
@@ -173,7 +174,7 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
 
     FailRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -208,7 +209,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SimpleBatchingTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2 * LOOPS, renderer.getIndex())
@@ -250,7 +251,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     ClippedMergingTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
@@ -278,7 +279,7 @@
         TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     TextMergingTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
@@ -309,7 +310,7 @@
         }
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     TextStrikethroughTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2 * LOOPS, renderer.getIndex())
@@ -343,7 +344,7 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     TextureLayerTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex());
@@ -388,7 +389,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(parent), sLightCenter);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
     RenderNodeTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
@@ -412,7 +413,7 @@
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
             SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
-            200, 200, TestUtils::createSyncedNodeList(node), sLightCenter);
+            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     ClippedTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
@@ -454,7 +455,7 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SaveLayerSimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
@@ -526,7 +527,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SaveLayerNestedTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex());
@@ -546,7 +547,7 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
 
     FailRenderer renderer;
     // should see no ops, even within the layer, since the layer should be rejected
@@ -589,7 +590,7 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SaveLayerUnclippedSimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
@@ -643,7 +644,7 @@
         canvas.restoreToCount(restoreTo);
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SaveLayerUnclippedMergedClearsTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex())
@@ -705,7 +706,7 @@
         canvas.restore();
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     SaveLayerUnclippedComplexTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(12, renderer.getIndex());
@@ -763,7 +764,7 @@
     layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
 
     FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedNodeList, sLightCenter);
+            syncedNodeList, sLightGeometry, nullptr);
     HwLayerSimpleTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(6, renderer.getIndex());
@@ -864,7 +865,7 @@
     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
 
     FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedList, sLightCenter);
+            syncedList, sLightGeometry, nullptr);
     HwLayerComplexTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(13, renderer.getIndex());
@@ -913,7 +914,7 @@
         drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
     });
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            TestUtils::createSyncedNodeList(parent), sLightCenter);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
     ZReorderTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex());
@@ -996,7 +997,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            TestUtils::createSyncedNodeList(parent), sLightCenter);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
     ProjectionReorderTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(3, renderer.getIndex());
@@ -1014,18 +1015,18 @@
     });
 }
 
-TEST(FrameBuilder, shadow) {
+RENDERTHREAD_TEST(FrameBuilder, shadow) {
     class ShadowTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
             EXPECT_EQ(0, mIndex++);
             EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
-            EXPECT_TRUE(op.casterPath->isRect(nullptr));
-            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
+            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
+            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
 
             Matrix4 expectedZ;
             expectedZ.loadTranslate(0, 0, 5);
-            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
+            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
         }
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
             EXPECT_EQ(1, mIndex++);
@@ -1039,13 +1040,13 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(parent), sLightCenter);
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, &Caches::getInstance());
     ShadowTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-TEST(FrameBuilder, shadowSaveLayer) {
+RENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
     class ShadowSaveLayerTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -1054,8 +1055,8 @@
         }
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
             EXPECT_EQ(1, mIndex++);
-            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
-            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
+            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
+            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
         }
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
             EXPECT_EQ(2, mIndex++);
@@ -1080,7 +1081,9 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
+            TestUtils::createSyncedNodeList(parent),
+            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
+            &Caches::getInstance());
     ShadowSaveLayerTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(5, renderer.getIndex());
@@ -1094,8 +1097,9 @@
         }
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
             EXPECT_EQ(1, mIndex++);
-            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
-            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
+            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
+            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
+            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
         }
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
             EXPECT_EQ(2, mIndex++);
@@ -1130,7 +1134,9 @@
     LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
     FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedList, (Vector3) { 100, 100, 100 });
+            syncedList,
+            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30},
+            &Caches::getInstance());
     ShadowHwLayerTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(5, renderer.getIndex());
@@ -1159,7 +1165,9 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(parent), sLightCenter);
+            TestUtils::createSyncedNodeList(parent),
+            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
+            &Caches::getInstance());
     ShadowLayeringTestRenderer renderer;
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
@@ -1187,7 +1195,7 @@
     });
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
+            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
     PropertyTestRenderer renderer(opValidateCallback);
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
@@ -1328,7 +1336,8 @@
     });
     auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
 
-    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            nodes, sLightGeometry, nullptr);
     SaveLayerAlphaClipTestRenderer renderer(outObservedData);
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 4a635fb..da786c7 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -27,7 +27,8 @@
 using namespace android::uirenderer;
 
 const LayerUpdateQueue sEmptyLayerUpdateQueue;
-const Vector3 sLightCenter = {100, 100, 100};
+const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
+const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
 RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
     auto node = TestUtils::createNode(0, 0, 200, 200,
@@ -36,12 +37,11 @@
         canvas.drawRect(0, 0, 200, 200, SkPaint());
         canvas.restore();
     });
-    BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128};
     RenderState& renderState = renderThread.renderState();
     Caches& caches = Caches::getInstance();
 
     FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            TestUtils::createSyncedNodeList(node), sLightCenter);
-    BakedOpRenderer renderer(caches, renderState, true, lightInfo);
+            TestUtils::createSyncedNodeList(node), sLightGeometery, nullptr);
+    BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index d3a35d9..c64953d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -92,7 +92,6 @@
         mList = (ListView) view.findViewById(android.R.id.list);
         mList.setOnItemClickListener(mItemListener);
         mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-
         return view;
     }
 
@@ -161,6 +160,7 @@
                 final RootInfo testRoot = ((RootItem) item).root;
                 if (Objects.equals(testRoot, root)) {
                     mList.setItemChecked(i, true);
+                    mList.setSelection(i);
                     return;
                 }
             }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index d0cd536..81607a9 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -200,7 +200,7 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
 
         Notification notification = new Notification.Builder(mContext)
-                .setSmallIcon(com.android.internal.R.drawable.ic_secure)
+                .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
                 .setWhen(0)
                 .setOngoing(true)
                 .setTicker(title)
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0f614ca..5f46567 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -930,6 +930,9 @@
     /** @return a specific user restriction that's in effect currently. */
     @Override
     public boolean hasUserRestriction(String restrictionKey, int userId) {
+        if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+            return false;
+        }
         Bundle restrictions = getEffectiveUserRestrictions(userId);
         return restrictions != null && restrictions.getBoolean(restrictionKey);
     }
@@ -946,6 +949,9 @@
     @Override
     public boolean hasBaseUserRestriction(String restrictionKey, int userId) {
         checkManageUsersPermission("hasBaseUserRestriction");
+        if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+            return false;
+        }
         synchronized (mRestrictionsLock) {
             Bundle bundle = mBaseUserRestrictions.get(userId);
             return (bundle != null && bundle.getBoolean(restrictionKey, false));
@@ -955,6 +961,9 @@
     @Override
     public void setUserRestriction(String key, boolean value, int userId) {
         checkManageUsersPermission("setUserRestriction");
+        if (!UserRestrictionsUtils.isValidRestriction(key)) {
+            return;
+        }
         synchronized (mRestrictionsLock) {
             // Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create
             // a copy.
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f11872e..f57f75f 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -36,6 +36,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
+import android.util.Slog;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -56,7 +57,15 @@
     private UserRestrictionsUtils() {
     }
 
-    public static final Set<String> USER_RESTRICTIONS = Sets.newArraySet(
+    private static Set<String> newSetWithUniqueCheck(String[] strings) {
+        final Set<String> ret = Sets.newArraySet(strings);
+
+        // Make sure there's no overlap.
+        Preconditions.checkState(ret.size() == strings.length);
+        return ret;
+    }
+
+    public static final Set<String> USER_RESTRICTIONS = newSetWithUniqueCheck(new String[] {
             UserManager.DISALLOW_CONFIG_WIFI,
             UserManager.DISALLOW_MODIFY_ACCOUNTS,
             UserManager.DISALLOW_INSTALL_APPS,
@@ -95,7 +104,7 @@
             UserManager.DISALLOW_DATA_ROAMING,
             UserManager.DISALLOW_SET_USER_ICON,
             UserManager.DISALLOW_SET_WALLPAPER
-    );
+    });
 
     /**
      * Set of user restriction which we don't want to persist.
@@ -141,6 +150,17 @@
             UserManager.DISALLOW_UNMUTE_MICROPHONE
     );
 
+    /**
+     * Throws {@link IllegalArgumentException} if the given restriction name is invalid.
+     */
+    public static boolean isValidRestriction(@NonNull String restriction) {
+        if (!USER_RESTRICTIONS.contains(restriction)) {
+            Slog.wtf(TAG, "Unknown restriction: " + restriction);
+            return false;
+        }
+        return true;
+    }
+
     public static void writeRestrictions(@NonNull XmlSerializer serializer,
             @Nullable Bundle restrictions, @NonNull String tag) throws IOException {
         if (restrictions == null) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cfe147e..39c21f1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3656,7 +3656,7 @@
             if (!(isProfileOwner(adminComponent, userHandle)
                     || isDeviceOwner(adminComponent, userHandle))) {
                 final boolean preN = getTargetSdk(admin.info.getPackageName(), userHandle)
-                        < android.os.Build.VERSION_CODES.N;
+                        <= android.os.Build.VERSION_CODES.M;
                 // As of N, password resetting to empty/null is not allowed anymore.
                 // TODO Should we allow DO/PO to set an empty password?
                 if (TextUtils.isEmpty(password)) {
@@ -6867,6 +6867,10 @@
     @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
         Preconditions.checkNotNull(who, "ComponentName is null");
+        if (!UserRestrictionsUtils.isValidRestriction(key)) {
+            return;
+        }
+
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
             ActiveAdmin activeAdmin =