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

Commit 74de87be authored by Hai Zhang's avatar Hai Zhang
Browse files

Add ExpressiveDesignEnabledProvider to allow activity control it

We need something to pass the information from activity to widgets
about whether expressive design should be enabled.

- Intent extras are usually passed in by external clients so it's not
a great option for passing this internal decision.

- Theme attributes also unfortunately has a chicken-and-egg problem
because we may need to set theme based on whether expressive design is
enabled, and that overwrites theme attributes previously set.

So it's more straightforward to just provide an optional interface for
activities to directly control whether expressive design should be
enabled for it.

This change also removes the field expressiveThemeState which isn't
really usedful, because currently tryInit() is always unconditionally
called in isExpressiveTheme(), and we are making the value different
for different activities now so there can't be one cache for all the
activities.

Bug: 406933786
Flag: com.android.settingslib.widget.theme.flags.is_expressive_design_enabled
Test: presubmit
Change-Id: Icbe1969b91f5ce733776d8710956badd00f51b90
parent 2dc4c5fb
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
/*
* Copyright (C) 2025 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.
*/

package com.android.settingslib.widget

/**
 * Optional interface that can be implemented by activities to provide whether expressive design
 * should be enabled if all other conditions are met.
 */
interface ExpressiveDesignEnabledProvider {
    fun isExpressiveDesignEnabled(): Boolean
}
+30 −28
Original line number Diff line number Diff line
@@ -16,49 +16,51 @@

package com.android.settingslib.widget

import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.os.Build
import com.android.settingslib.widget.theme.flags.Flags

object SettingsThemeHelper {
    private const val IS_EXPRESSIVE_DESIGN_ENABLED = "is_expressive_design_enabled"
    private const val RO_BUILD_CHARACTERISTICS = "ro.build.characteristics"
    private var expressiveThemeState: ExpressiveThemeState = ExpressiveThemeState.UNKNOWN

    enum class ExpressiveThemeState {
        UNKNOWN,
        ENABLED,
        DISABLED,
    @JvmStatic
    fun isTablet(context: Context): Boolean {
        val result = getPropString(context, RO_BUILD_CHARACTERISTICS, "").split(',')
        return result.contains("tablet")
    }

    @JvmStatic
    fun isExpressiveTheme(context: Context): Boolean {
        tryInit(context)
        if (expressiveThemeState == ExpressiveThemeState.UNKNOWN) {
            throw Exception(
                "need to call com.android.settingslib.widget.SettingsThemeHelper.init(Context) first."
            )
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.BAKLAVA) {
            return false
        }

        return expressiveThemeState == ExpressiveThemeState.ENABLED
        // Enable if overridden by system property
        if (getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false)) {
            return true;
        }

    @JvmStatic
    fun isTablet(context: Context): Boolean {
        val result = getPropString(context, RO_BUILD_CHARACTERISTICS, "").split(',')
        return result.contains("tablet")
        // Disable if feature flag is disabled.
        if (!Flags.isExpressiveDesignEnabled()) {
            return false;
        }
        // Allow the activity to override.
        val activity = getActivityFromContext(context)
        if (activity is ExpressiveDesignEnabledProvider) {
            return activity.isExpressiveDesignEnabled()
        }
        return true
    }

    private fun tryInit(context: Context) {
        expressiveThemeState =
            if (
                (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM) &&
                        (getPropBoolean(context, IS_EXPRESSIVE_DESIGN_ENABLED, false) ||
                                Flags.isExpressiveDesignEnabled())
            ) {
                ExpressiveThemeState.ENABLED
            } else {
                ExpressiveThemeState.DISABLED
    private fun getActivityFromContext(context: Context): Activity? {
        var currentContext = context
        while (true) {
            when (currentContext) {
                is Activity -> return currentContext
                is ContextWrapper -> currentContext = currentContext.baseContext
                else -> return null
            }
        }
    }