Wire-up default force-dark based off of isLightTheme

Bug: 102591313
Test: Compared settings in light & dark UI modes with
force_dark set to true. Observed that force_dark fixes
were not present when UI mode was set to dark, indicating
force_dark was appropriately globally-disabled

Change-Id: I5882829bb5871829fc8fc9911682f52a6ba5f445
diff --git a/api/current.txt b/api/current.txt
index 52257c0..51717f1 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -772,6 +772,7 @@
     field public static final int isFeatureSplit = 16844123; // 0x101055b
     field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
+    field public static final int isLightTheme = 16844175; // 0x101058f
     field public static final int isModifier = 16843334; // 0x1010246
     field public static final int isRepeatable = 16843336; // 0x1010248
     field public static final int isScrollContainer = 16843342; // 0x101024e
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 6737839..20f5f9a 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -976,6 +976,25 @@
         }
     }
 
+    /** The root of everything */
+    public @NonNull RenderNode getRootNode() {
+        return mRootNode;
+    }
+
+    private boolean mForceDark = false;
+
+    /**
+     * Whether or not the force-dark feature should be used for this renderer.
+     */
+    public boolean setForceDark(boolean enable) {
+        if (mForceDark != enable) {
+            mForceDark = enable;
+            nSetForceDark(mNativeProxy, enable);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
      * TODO: deduplicate against ThreadedRenderer.
@@ -1255,4 +1274,5 @@
     private static native void nSetIsolatedProcess(boolean enabled);
     private static native void nSetContextPriority(int priority);
     private static native void nAllocateBuffers(long nativeProxy, Surface window);
+    private static native void nSetForceDark(long nativeProxy, boolean enabled);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f4be9f2..312b06d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15255,6 +15255,10 @@
      * a value of 'true' will not override any 'false' value in its parent chain nor will
      * it prevent any 'false' in any of its children.
      *
+     * The default behavior of force dark is also influenced by the Theme's
+     * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute.
+     * If a theme is isLightTheme="false", then force dark is globally disabled for that theme.
+     *
      * @param allow Whether or not to allow force dark.
      *
      * @hide
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9be9ed0..4aa0175 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -43,6 +43,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
@@ -1073,6 +1074,7 @@
                 mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
                         attrs.getTitle().toString());
                 mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
+                updateForceDarkMode();
                 if (mAttachInfo.mThreadedRenderer != null) {
                     mAttachInfo.mHardwareAccelerated =
                             mAttachInfo.mHardwareAccelerationRequested = true;
@@ -1081,6 +1083,27 @@
         }
     }
 
+    private int getNightMode() {
+        return mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+    }
+
+    private void updateForceDarkMode() {
+        if (mAttachInfo.mThreadedRenderer == null) return;
+
+        boolean nightMode = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
+        TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
+        boolean isLightTheme = a.getBoolean(R.styleable.Theme_isLightTheme, false);
+        a.recycle();
+
+        boolean changed = mAttachInfo.mThreadedRenderer.setForceDark(nightMode);
+        changed |= mAttachInfo.mThreadedRenderer.getRootNode().setAllowForceDark(isLightTheme);
+
+        if (changed) {
+            // TODO: Don't require regenerating all display lists to apply this setting
+            invalidateWorld(mView);
+        }
+    }
+
     @UnsupportedAppUsage
     public View getView() {
         return mView;
@@ -4073,6 +4096,8 @@
             mForceNextWindowRelayout = true;
             requestLayout();
         }
+
+        updateForceDarkMode();
     }
 
     /**
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 3c59bd1..7a5b604 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1064,6 +1064,12 @@
     proxy->allocateBuffers(surface);
 }
 
+static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jboolean enable) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setForceDark(enable);
+}
+
 // ----------------------------------------------------------------------------
 // FrameMetricsObserver
 // ----------------------------------------------------------------------------
@@ -1177,6 +1183,7 @@
     { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
     { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
     { "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
+    { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
 };
 
 static JavaVM* mJvm = nullptr;
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cc99a4e..cdaff18 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2912,6 +2912,7 @@
         <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
         <public name="usesNonSdkApi" />
         <public name="minimumUiTimeout" />
+        <public name="isLightTheme" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b4">
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 11dad2e..494e513 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -229,6 +229,7 @@
         "ResourceCache.cpp",
         "SkiaCanvas.cpp",
         "Snapshot.cpp",
+        "TreeInfo.cpp",
         "VectorDrawable.cpp",
         "protos/graphicsstats.proto",
     ],
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 17bec19..a699e2f 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -61,6 +61,7 @@
 bool Properties::disableVsync = false;
 bool Properties::skpCaptureEnabled = false;
 bool Properties::forceDarkMode = false;
+bool Properties::enableForceDarkSupport = false;
 bool Properties::enableRTAnimations = true;
 
 bool Properties::runningInEmulator = false;
@@ -149,6 +150,9 @@
 
     forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false);
 
+    // TODO: make this on by default
+    enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, false);
+
     return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
            (prevDebugStencilClip != debugStencilClip);
 }
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index ea017a7..542bc71 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -192,6 +192,8 @@
 
 #define PROPERTY_FORCE_DARK "debug.hwui.force_dark"
 
+#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled"
+
 ///////////////////////////////////////////////////////////////////////////////
 // Misc
 ///////////////////////////////////////////////////////////////////////////////
@@ -266,6 +268,7 @@
 
     static bool skpCaptureEnabled;
     static bool forceDarkMode;
+    static bool enableForceDarkSupport;
 
     // For experimentation b/68769804
     ANDROID_API static bool enableRTAnimations;
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
new file mode 100644
index 0000000..808a12a
--- /dev/null
+++ b/libs/hwui/TreeInfo.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TreeInfo.h"
+
+#include "renderthread/CanvasContext.h"
+
+namespace android::uirenderer {
+
+TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
+        : mode(mode)
+        , prepareTextures(mode == MODE_FULL)
+        , canvasContext(canvasContext)
+        , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {}
+
+}  // namespace android::uirenderer
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index caa5762..a0d9605 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include "utils/Macros.h"
 #include "Properties.h"
+#include "utils/Macros.h"
 
 #include <utils/Timers.h>
 
@@ -40,7 +40,7 @@
     virtual void onError(const std::string& message) = 0;
 
 protected:
-    virtual ~ErrorHandler() {}
+    virtual ~ErrorHandler() = default;
 };
 
 class TreeObserver {
@@ -52,7 +52,7 @@
     virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
 
 protected:
-    virtual ~TreeObserver() {}
+    virtual ~TreeObserver() = default;
 };
 
 // This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
@@ -71,8 +71,7 @@
         MODE_RT_ONLY,
     };
 
-    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
-            : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {}
+    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext);
 
     TraversalMode mode;
     // TODO: Remove this? Currently this is used to signal to stop preparing
@@ -94,7 +93,7 @@
 
     bool updateWindowPositions = false;
 
-    int disableForceDark = Properties::forceDarkMode ? 0 : 1;
+    int disableForceDark;
 
     struct Out {
         bool hasFunctors = false;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2315cb9..2307ee4 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -182,6 +182,23 @@
         mFrameCompleteCallbacks.push_back(std::move(func));
     }
 
+    void setForceDark(bool enable) {
+        mUseForceDark = enable;
+    }
+
+    bool useForceDark() {
+        // The force-dark override has the highest priority, followed by the disable setting
+        // for the feature as a whole, followed last by whether or not this context has had
+        // force dark set (typically automatically done via UIMode)
+        if (Properties::forceDarkMode) {
+            return true;
+        }
+        if (!Properties::enableForceDarkSupport) {
+            return false;
+        }
+        return mUseForceDark;
+    }
+
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                   IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -228,6 +245,7 @@
 
     bool mOpaque;
     bool mWideColorGamut = false;
+    bool mUseForceDark = false;
     LightInfo mLightInfo;
     LightGeometry mLightGeometry = {{0, 0, 0}, 0};
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 6106e24..54219b5 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -298,6 +298,12 @@
     });
 }
 
+void RenderProxy::setForceDark(bool enable) {
+    mRenderThread.queue().post([this, enable]() {
+        mContext->setForceDark(enable);
+    });
+}
+
 int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
                                  SkBitmap* bitmap) {
     auto& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d22f56e..d29fcc4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -119,7 +119,7 @@
 
     ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
     ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
-    ANDROID_API long getDroppedFrameReportCount();
+    ANDROID_API void setForceDark(bool enable);
 
     ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
                                            int bottom, SkBitmap* bitmap);