Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 306c8de5 authored by John Reck's avatar John Reck
Browse files

Revert "feat(force invert): detect the polarity of an app to dec..."

Revert submission 30679429-forcedark-colorarea-detection

Reason for revert: Triggered a performance regression

Bug: 410295655

Reverted changes: /q/submissionid:30679429-forcedark-colorarea-detection

Change-Id: I8cbf0af2fd567b1a125cb3e5abe9617cf3eb9df6
parent 6e4b7658
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -135,10 +135,10 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange;
import static com.android.window.flags.Flags.fixViewRootCallTrace;
import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.fixViewRootCallTrace;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -190,6 +190,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RenderNode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.hardware.SyncFence;
@@ -293,6 +294,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneFallbackEventHandler;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
@@ -2086,12 +2088,21 @@ public final class ViewRootImpl implements ViewParent,
                // preference for dark mode in configuration.uiMode. Instead, we assume that both
                // force invert and the system's dark theme are enabled.
                if (shouldApplyForceInvertDark()) {
                    // We will use HWUI color area detection to determine if it should actually be
                    // inverted. Checking light theme simply gives the developer a way to "opt-out"
                    // of force invert.
                    // TODO: b/368725782 - Use hwui color area detection instead of / in
                    //  addition to these heuristics.
                    final boolean isLightTheme =
                            a.getBoolean(R.styleable.Theme_isLightTheme, false);
                    if (isLightTheme) {
                    final boolean isBackgroundColorLight;
                    if (mView != null && mView.getBackground()
                            instanceof ColorDrawable colorDrawable) {
                        isBackgroundColorLight =
                                !ContrastColorUtil.isColorDarkLab(colorDrawable.getColor());
                    } else {
                        // Treat unknown as light, so that only isLightTheme is used to determine
                        // force dark treatment.
                        isBackgroundColorLight = true;
                    }
                    if (isLightTheme && isBackgroundColorLight) {
                        return ForceDarkType.FORCE_INVERT_COLOR_DARK;
                    } else {
                        return ForceDarkType.NONE;
+2 −3
Original line number Diff line number Diff line
@@ -1548,7 +1548,7 @@ public class ViewRootImplTest {

    @Test
    @EnableFlags(FLAG_FORCE_INVERT_COLOR)
    public void determineForceDarkType_isLightThemeAndNotLightBackground_returnsForceInvertColorDark()
    public void determineForceDarkType_isLightThemeAndNotLightBackground_returnsNone()
            throws Exception {
        // Set up configurations for force invert color
        waitForSystemNightModeActivated(true);
@@ -1557,8 +1557,7 @@ public class ViewRootImplTest {
        setUpViewAttributes(/* isLightTheme= */ true, /* isLightBackground = */ false);

        TestUtils.waitUntil("Waiting for ForceDarkType to be ready",
                () -> (mViewRootImpl.determineForceDarkType()
                        == ForceDarkType.FORCE_INVERT_COLOR_DARK));
                () -> (mViewRootImpl.determineForceDarkType() == ForceDarkType.NONE));
    }

    @Test
+0 −1
Original line number Diff line number Diff line
@@ -616,7 +616,6 @@ cc_defaults {
        "Animator.cpp",
        "AnimatorManager.cpp",
        "CanvasTransform.cpp",
        "ColorArea.cpp",
        "DamageAccumulator.cpp",
        "DeviceInfo.cpp",
        "FrameInfo.cpp",

libs/hwui/ColorArea.cpp

deleted100644 → 0
+0 −111
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 "ColorArea.h"

#include "utils/MathUtils.h"

namespace android::uirenderer {

constexpr static int kMinimumAlphaToConsiderArea = 200;

void ColorArea::addArea(const SkRect& rect, const SkPaint* paint) {
    addArea(rect.width(), rect.height(), paint);
}

void ColorArea::addArea(int32_t width, int32_t height, const SkPaint* paint) {
    if (!paint) return;
    // HWUI doesn't draw anything with negative width or height
    if (width <= 0 || height <= 0) return;

    uint64_t area = width * height;
    addArea(area, *paint);
}

void ColorArea::addArea(uint64_t area, const SkPaint& paint) {
    if (paint.getStyle() == SkPaint::Style::kStroke_Style) return;
    if (CC_UNLIKELY(paint.nothingToDraw())) return;

    if (paint.getShader()) {
        // TODO(b/409395389): check if the shader is a gradient, and then slice up area into
        //  sections, determining polarity for each color stop of the gradient.
        return;
    }

    addArea(area, paint.getColor());
}

void ColorArea::addArea(uint64_t area, SkColor color) {
    if (CC_UNLIKELY(SkColorGetA(color) < kMinimumAlphaToConsiderArea)) return;

    // TODO(b/381930266): optimize by detecting common black/white/grey colors and avoid converting
    //  also maybe cache colors or something?
    Lab lab = sRGBToLab(color);
    // TODO(b/372558459): add a case for a middle L that is grey, and don't count it?
    addArea(area, lab.L > 50 ? Light : Dark);
}

void ColorArea::addArea(uint64_t area, Polarity polarity) {
    // HWUI doesn't draw anything with negative width or height
    if (area <= 0) return;

    if (polarity == Light) {
        mLight += area;
    } else if (polarity == Dark) {
        mDark += area;
    }
}

Polarity ColorArea::getPolarity() const {
    if (mLight == mDark) {  // also covers the case if it was just reset()
        return Polarity::Unknown;
    }
    if (mLight > mDark) {
        return Polarity::Light;
    } else {
        return Polarity::Dark;
    }
}

void ColorArea::reset() {
    mParentHeight = -1;
    mParentWidth = -1;
    mLight = 0;
    mDark = 0;
}

void ColorArea::merge(const ColorArea& source) {
    mLight += source.mLight;
    mDark += source.mDark;
}

int ColorArea::getParentWidth() const {
    return mParentWidth;
}

void ColorArea::setParentWidth(int width) {
    mParentWidth = width;
}

int ColorArea::getParentHeight() const {
    return mParentHeight;
}

void ColorArea::setParentHeight(int height) {
    mParentHeight = height;
}

}  // namespace android::uirenderer

libs/hwui/ColorArea.h

deleted100644 → 0
+0 −112
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.
 */

#pragma once

#include <SkCanvas.h>
#include <SkPaintFilterCanvas.h>

#include "utils/Color.h"
#include "utils/Macros.h"

namespace android::uirenderer {

/**
 * The result of counting the color area.
 */
enum Polarity {
    /** The result is too close to make a definite determination */
    Unknown = 0,
    /** Majority light fills */
    Light,
    /** Majority dark fills */
    Dark
};

/**
 * Tracks the app's overall polarity (i.e. dark or light theme) by counting the areas of backgrounds
 * and their colors. This is used to determine if we should force invert the app, for instance if
 * the user prefers dark theme but this app is mainly light.
 *
 * The idea is that we count the fill colors of any background-type draw calls: drawRect(),
 * drawColor(), etc. If the area of light fills drawn to the screen is greater than the area of dark
 * fills drawn to the screen, we can reasonably guess that the app is light theme, and vice-versa.
 */
class ColorArea {
public:
    ColorArea() {}
    ~ColorArea() {}

    /**
     * Counts the given area of a draw call that is reasonably expected to draw a background:
     * drawRect, drawColor, etc.
     *
     * @param area the total area of the draw call's fill (approximate)
     * @param paint the paint used to fill the area. If the paint is not a fill, the area will not
     *              be added.
     */
    void addArea(uint64_t area, const SkPaint& paint);

    /**
     * See [addArea(uint64_t, SkPaint&)]
     */
    void addArea(const SkRect& rect, const SkPaint* paint);

    /**
     * See [addArea(uint64_t, SkPaint&)]
     */
    void addArea(int32_t width, int32_t height, const SkPaint* paint);

    /**
     * See [addArea(uint64_t, SkPaint&)]
     */
    void addArea(uint64_t area, SkColor color);

    /**
     * Prefer [addArea(uint64_t, SkPaint&)], unless the area you're measuring doesn't have a paint
     * with measurable colors.
     *
     * @param area the total area of the draw call's fill (approximate)
     * @param polarity whether the color of the given area is light or dark
     */
    void addArea(uint64_t area, Polarity polarity);

    /**
     * Adds the source's area to this area. This is so you can sum up the areas of a bunch of child
     * nodes.
     */
    void merge(const ColorArea& source);

    /** Resets the object back to the initial state */
    void reset();

    int getParentWidth() const;
    void setParentWidth(int width);
    int getParentHeight() const;
    void setParentHeight(int height);

    /** Returns the best guess of the polarity of this area */
    Polarity getPolarity() const;

private:
    int mParentWidth = -1;
    int mParentHeight = -1;

    uint64_t mLight = 0;
    uint64_t mDark = 0;
};

}  // namespace android::uirenderer
Loading