Skip to content

Commit

Permalink
[M3][Color] Add dynamic contrast support
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 544727089
  • Loading branch information
Material Design Team authored and raajkumars committed Jul 5, 2023
1 parent ad6afbf commit 862a7e1
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 1 deletion.
36 changes: 36 additions & 0 deletions lib/java/com/google/android/material/color/DynamicColors.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
import android.app.Application.ActivityLifecycleCallbacks;
import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextThemeWrapper;
import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.NonNull;
Expand All @@ -44,6 +46,7 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

/** Utility for applying dynamic colors to application/activities. */
public class DynamicColors {
Expand Down Expand Up @@ -138,6 +141,12 @@ public boolean isSupported() {

private static final int USE_DEFAULT_THEME_OVERLAY = 0;
private static final int UPDATED_NEUTRAL_PALETTE_CHROMA = 6;
private static final String TAG = DynamicColors.class.getSimpleName();

private static final String SYSTEM_OUTLINE_VARIANT_DARK_RESOURCE_ENTRY_NAME =
"system_outline_variant_dark";

private static final int SYSTEM_OUTLINE_VARIANT_DARK_RESOURCE_ID = 0x010600c1;

private DynamicColors() {}

Expand Down Expand Up @@ -446,6 +455,11 @@ public static boolean isDynamicColorAvailable() {
}

private static int getDefaultThemeOverlay(@NonNull Context context) {
// TODO(b/289112889): Remove workaround and roll forward cl/528599594 as soon as U public
// release.
if (isDynamicContrastAvailable(context)) {
return R.style.ThemeOverlay_Material3_DynamicColors_Contrast_DayNight;
}
TypedArray dynamicColorAttributes =
context.obtainStyledAttributes(DYNAMIC_COLOR_THEME_OVERLAY_ATTRIBUTE);
final int theme = dynamicColorAttributes.getResourceId(0, 0);
Expand Down Expand Up @@ -568,4 +582,26 @@ private static float getSystemContrast(Context context) {
? 0
: uiModeManager.getContrast();
}

private static boolean isDynamicContrastAvailable(Context context) {
if (VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE && areSystemColorRolesDefined(context)) {
return true;
}
return false;
}

// TODO(b/289112889): Remove workaround and roll forward cl/528599594 as soon as U public release.
//
// This is to check and make sure the last material resource defined in the android block of
// resources matches the resource name from app's context.
private static boolean areSystemColorRolesDefined(Context context) {
try {
return Objects.equals(
context.getResources().getResourceEntryName(SYSTEM_OUTLINE_VARIANT_DARK_RESOURCE_ID),
SYSTEM_OUTLINE_VARIANT_DARK_RESOURCE_ENTRY_NAME);
} catch (NotFoundException e) {
Log.i(TAG, SYSTEM_OUTLINE_VARIANT_DARK_RESOURCE_ENTRY_NAME + " resource not found.", e);
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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.
-->
<!-- Material3 alternative to textColorHighlight for dynamic dark theme -->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="NewApi">
<item android:alpha="@dimen/material_emphasis_medium" android:color="@android:color/system_primary_dark" />
</selector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 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.
-->
<!-- Material3 alternative to textColorHighlight for dynamic light theme -->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="NewApi">
<item android:alpha="@dimen/material_emphasis_medium" android:color="@android:color/system_primary_light" />
</selector>
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@
-->
<resources>
<style name="ThemeOverlay.Material3.DynamicColors.DayNight" parent="ThemeOverlay.Material3.DynamicColors.Dark" />

<style name="ThemeOverlay.Material3.DynamicColors.Contrast.DayNight" parent="ThemeOverlay.Material3.DynamicColors.Contrast.Dark" />
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<!--
Material 3 theme overlay.
-->
Expand Down Expand Up @@ -174,4 +174,118 @@
-->
<style name="ThemeOverlay.MaterialComponents.Dark.ActionBar" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>

<style name="ThemeOverlay.Material3.DynamicColors.Contrast.Light" parent=""
tools:ignore="NewApi">
<!-- Color palettes -->
<item name="colorPrimary">@android:color/system_primary_light</item>
<item name="colorOnPrimary">@android:color/system_on_primary_light</item>
<item name="colorPrimaryInverse">@android:color/system_primary_dark</item>
<item name="colorPrimaryContainer">@android:color/system_primary_container_light</item>
<item name="colorOnPrimaryContainer">@android:color/system_on_primary_container_light</item>
<item name="colorPrimaryFixed">@android:color/system_primary_fixed</item>
<item name="colorPrimaryFixedDim">@android:color/system_primary_fixed_dim</item>
<item name="colorOnPrimaryFixed">@android:color/system_on_primary_fixed</item>
<item name="colorOnPrimaryFixedVariant">@android:color/system_on_primary_fixed_variant</item>
<item name="colorSecondary">@android:color/system_secondary_light</item>
<item name="colorOnSecondary">@android:color/system_on_secondary_light</item>
<item name="colorSecondaryContainer">@android:color/system_secondary_container_light</item>
<item name="colorOnSecondaryContainer">@android:color/system_on_secondary_container_light</item>
<item name="colorSecondaryFixed">@android:color/system_secondary_fixed</item>
<item name="colorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</item>
<item name="colorOnSecondaryFixed">@android:color/system_on_secondary_fixed</item>
<item name="colorOnSecondaryFixedVariant">@android:color/system_on_secondary_fixed_variant</item>
<item name="colorTertiary">@android:color/system_tertiary_light</item>
<item name="colorOnTertiary">@android:color/system_on_tertiary_light</item>
<item name="colorTertiaryContainer">@android:color/system_tertiary_container_light</item>
<item name="colorOnTertiaryContainer">@android:color/system_on_tertiary_container_light</item>
<item name="colorTertiaryFixed">@android:color/system_tertiary_fixed</item>
<item name="colorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</item>
<item name="colorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</item>
<item name="colorOnTertiaryFixedVariant">@android:color/system_on_tertiary_fixed_variant</item>
<item name="android:colorBackground">@android:color/system_background_light</item>
<item name="colorOnBackground">@android:color/system_on_background_light</item>
<item name="colorSurface">@android:color/system_surface_light</item>
<item name="colorOnSurface">@android:color/system_on_surface_light</item>
<item name="colorSurfaceVariant">@android:color/system_surface_variant_light</item>
<item name="colorOnSurfaceVariant">@android:color/system_on_surface_variant_light</item>
<item name="colorSurfaceInverse">@android:color/system_surface_dark</item>
<item name="colorOnSurfaceInverse">@android:color/system_on_surface_dark</item>
<item name="colorSurfaceBright">@android:color/system_surface_bright_light</item>
<item name="colorSurfaceDim">@android:color/system_surface_dim_light</item>
<item name="colorSurfaceContainer">@android:color/system_surface_container_light</item>
<item name="colorSurfaceContainerLow">@android:color/system_surface_container_low_light</item>
<item name="colorSurfaceContainerHigh">@android:color/system_surface_container_high_light</item>
<item name="colorSurfaceContainerLowest">@android:color/system_surface_container_lowest_light</item>
<item name="colorSurfaceContainerHighest">@android:color/system_surface_container_highest_light</item>
<item name="colorOutline">@android:color/system_outline_light</item>
<item name="colorOutlineVariant">@android:color/system_outline_variant_light</item>
<item name="colorError">@android:color/system_error_light</item>
<item name="colorOnError">@android:color/system_error_container_light</item>
<item name="colorErrorContainer">@android:color/system_on_error_light</item>
<item name="colorOnErrorContainer">@android:color/system_on_error_container_light</item>

<!-- Default Framework Text Colors. -->
<!-- textColorHighlight and textColorHighlightInverse are using system color resource directly in the CSL for contrast support, as they use the primary color palette. -->
<item name="android:textColorHighlight">@color/m3_dynamic_contrast_highlighted_text</item>
<item name="android:textColorHighlightInverse">@color/m3_dynamic_contrast_dark_highlighted_text</item>
</style>

<style name="ThemeOverlay.Material3.DynamicColors.Contrast.Dark" parent=""
tools:ignore="NewApi">
<!-- Color palettes -->
<item name="colorPrimary">@android:color/system_primary_dark</item>
<item name="colorOnPrimary">@android:color/system_on_primary_dark</item>
<item name="colorPrimaryInverse">@android:color/system_primary_light</item>
<item name="colorPrimaryContainer">@android:color/system_primary_container_dark</item>
<item name="colorOnPrimaryContainer">@android:color/system_on_primary_container_dark</item>
<item name="colorPrimaryFixed">@android:color/system_primary_fixed</item>
<item name="colorPrimaryFixedDim">@android:color/system_primary_fixed_dim</item>
<item name="colorOnPrimaryFixed">@android:color/system_on_primary_fixed</item>
<item name="colorOnPrimaryFixedVariant">@android:color/system_on_primary_fixed_variant</item>
<item name="colorSecondary">@android:color/system_secondary_dark</item>
<item name="colorOnSecondary">@android:color/system_on_secondary_dark</item>
<item name="colorSecondaryContainer">@android:color/system_secondary_container_dark</item>
<item name="colorOnSecondaryContainer">@android:color/system_on_secondary_container_dark</item>
<item name="colorSecondaryFixed">@android:color/system_secondary_fixed</item>
<item name="colorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</item>
<item name="colorOnSecondaryFixed">@android:color/system_on_secondary_fixed</item>
<item name="colorOnSecondaryFixedVariant">@android:color/system_on_secondary_fixed_variant</item>
<item name="colorTertiary">@android:color/system_tertiary_dark</item>
<item name="colorOnTertiary">@android:color/system_on_tertiary_dark</item>
<item name="colorTertiaryContainer">@android:color/system_tertiary_container_dark</item>
<item name="colorOnTertiaryContainer">@android:color/system_on_tertiary_container_dark</item>
<item name="colorTertiaryFixed">@android:color/system_tertiary_fixed</item>
<item name="colorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</item>
<item name="colorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</item>
<item name="colorOnTertiaryFixedVariant">@android:color/system_on_tertiary_fixed_variant</item>
<item name="android:colorBackground">@android:color/system_background_dark</item>
<item name="colorOnBackground">@android:color/system_on_background_dark</item>
<item name="colorSurface">@android:color/system_surface_dark</item>
<item name="colorOnSurface">@android:color/system_on_surface_dark</item>
<item name="colorSurfaceVariant">@android:color/system_surface_variant_dark</item>
<item name="colorOnSurfaceVariant">@android:color/system_on_surface_variant_dark</item>
<item name="colorSurfaceInverse">@android:color/system_surface_light</item>
<item name="colorOnSurfaceInverse">@android:color/system_on_surface_light</item>
<item name="colorSurfaceBright">@android:color/system_surface_bright_dark</item>
<item name="colorSurfaceDim">@android:color/system_surface_dim_dark</item>
<item name="colorSurfaceContainer">@android:color/system_surface_container_dark</item>
<item name="colorSurfaceContainerLow">@android:color/system_surface_container_low_dark</item>
<item name="colorSurfaceContainerHigh">@android:color/system_surface_container_high_dark</item>
<item name="colorSurfaceContainerLowest">@android:color/system_surface_container_lowest_dark</item>
<item name="colorSurfaceContainerHighest">@android:color/system_surface_container_highest_dark</item>
<item name="colorOutline">@android:color/system_outline_dark</item>
<item name="colorOutlineVariant">@android:color/system_outline_variant_dark</item>
<item name="colorError">@android:color/system_error_dark</item>
<item name="colorOnError">@android:color/system_on_error_dark</item>
<item name="colorErrorContainer">@android:color/system_error_container_dark</item>
<item name="colorOnErrorContainer">@android:color/system_on_error_container_dark</item>

<!-- Default Framework Text Colors. -->
<!-- textColorHighlight and textColorHighlightInverse are using system color resource directly in the CSL for contrast support, as they use the primary color palette. -->
<item name="android:textColorHighlight">@color/m3_dynamic_contrast_dark_highlighted_text</item>
<item name="android:textColorHighlightInverse">@color/m3_dynamic_contrast_highlighted_text</item>
</style>

<style name="ThemeOverlay.Material3.DynamicColors.Contrast.DayNight" parent="ThemeOverlay.Material3.DynamicColors.Contrast.Light" />

</resources>

0 comments on commit 862a7e1

Please sign in to comment.