Skip to content

Commit

Permalink
[M3][Color] Added content color api
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 484968589
  • Loading branch information
Material Design Team authored and hunterstich committed Oct 31, 2022
1 parent 567cc54 commit 8ca326a
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
Expand Up @@ -17,13 +17,22 @@
package com.google.android.material.color;

import android.app.Activity;
import android.graphics.Bitmap;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import com.google.android.material.color.DynamicColors.OnAppliedCallback;
import com.google.android.material.color.DynamicColors.Precondition;
import com.google.android.material.color.utilities.QuantizerCelebi;
import com.google.android.material.color.utilities.Score;
import com.google.errorprone.annotations.CanIgnoreReturnValue;

/** Wrapper class for specifying dynamic colors options when applying dynamic colors. */
/**
* Wrapper class for specifying dynamic colors options when applying dynamic colors. Clients have
* the options to provide a custom theme overlay, set the precondition that decides if dynamic
* colors should be applied, set the callback method and/or set the color source image to apply
* content-based dynamic colors.
*/
public class DynamicColorsOptions {

private static final Precondition ALWAYS_ALLOW =
Expand All @@ -43,11 +52,15 @@ public void onApplied(@NonNull Activity activity) {}
@StyleRes private final int themeOverlay;
@NonNull private final Precondition precondition;
@NonNull private final OnAppliedCallback onAppliedCallback;
@Nullable private Integer contentBasedSeedColor;

private DynamicColorsOptions(Builder builder) {
this.themeOverlay = builder.themeOverlay;
this.precondition = builder.precondition;
this.onAppliedCallback = builder.onAppliedCallback;
if (builder.contentBasedSource != null) {
this.contentBasedSeedColor = extractSeedColorFromImage(builder.contentBasedSource);
}
}

/** Returns the resource ID of the theme overlay that provides dynamic color definition. */
Expand All @@ -68,12 +81,19 @@ public OnAppliedCallback getOnAppliedCallback() {
return onAppliedCallback;
}

/** Returns the seed color extracted from the color source image. */
@Nullable
public Integer getContentBasedSeedColor() {
return contentBasedSeedColor;
}

/** Builder class for specifying options when applying dynamic colors. */
public static class Builder {

@StyleRes private int themeOverlay;
@NonNull private Precondition precondition = ALWAYS_ALLOW;
@NonNull private OnAppliedCallback onAppliedCallback = NO_OP_CALLBACK;
@Nullable private Bitmap contentBasedSource;

/** Sets the resource ID of the theme overlay that provides dynamic color definition. */
@NonNull
Expand All @@ -99,9 +119,28 @@ public Builder setOnAppliedCallback(@NonNull OnAppliedCallback onAppliedCallback
return this;
}

/**
* Sets the content based source image to extract the seed color from to generate Material color
* palette.
*/
@NonNull
@CanIgnoreReturnValue
public Builder setContentBasedSource(@NonNull Bitmap contentBasedSource) {
this.contentBasedSource = contentBasedSource;
return this;
}

@NonNull
public DynamicColorsOptions build() {
return new DynamicColorsOptions(this);
}
}

private static int extractSeedColorFromImage(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] bitmapPixels = new int[width * height];
bitmap.getPixels(bitmapPixels, /* offset= */ 0, width, /* x= */ 0, /* y= */ 0, width, height);
return Score.score(QuantizerCelebi.quantize(bitmapPixels, 128)).get(0);
}
}
30 changes: 30 additions & 0 deletions lib/java/com/google/android/material/color/res/values/colors.xml
Expand Up @@ -53,10 +53,40 @@
<!-- 32% opacity black -->
<color name="mtrl_scrim_color">#52000000</color>

<!-- TODO(b/255278466): Move color resources to versioned sub-folders.-->
<!-- XML color harmonization palette, values to be replaced at runtime. -->
<color name="material_harmonized_color_error">#FFFFFF</color>
<color name="material_harmonized_color_on_error">#FFFFFF</color>
<color name="material_harmonized_color_error_container">#FFFFFF</color>
<color name="material_harmonized_color_on_error_container">#FFFFFF</color>

<!-- TODO(b/255278466): Move color resources to versioned sub-folders.-->
<!-- XML personalized color (e.g. content color) palette, values to be replaced at runtime. -->
<color name="material_personalized_color_primary">#FFFFFF</color>
<color name="material_personalized_color_on_primary">#FFFFFF</color>
<color name="material_personalized_color_primary_inverse">#FFFFFF</color>
<color name="material_personalized_color_primary_container">#FFFFFF</color>
<color name="material_personalized_color_on_primary_container">#FFFFFF</color>
<color name="material_personalized_color_secondary">#FFFFFF</color>
<color name="material_personalized_color_on_secondary">#FFFFFF</color>
<color name="material_personalized_color_secondary_container">#FFFFFF</color>
<color name="material_personalized_color_on_secondary_container">#FFFFFF</color>
<color name="material_personalized_color_tertiary">#FFFFFF</color>
<color name="material_personalized_color_on_tertiary">#FFFFFF</color>
<color name="material_personalized_color_tertiary_container">#FFFFFF</color>
<color name="material_personalized_color_on_tertiary_container">#FFFFFF</color>
<color name="material_personalized_color_background">#FFFFFF</color>
<color name="material_personalized_color_on_background">#FFFFFF</color>
<color name="material_personalized_color_surface">#FFFFFF</color>
<color name="material_personalized_color_on_surface">#FFFFFF</color>
<color name="material_personalized_color_surface_variant">#FFFFFF</color>
<color name="material_personalized_color_on_surface_variant">#FFFFFF</color>
<color name="material_personalized_color_surface_inverse">#FFFFFF</color>
<color name="material_personalized_color_on_surface_inverse">#FFFFFF</color>
<color name="material_personalized_color_surface_outline">#FFFFFF</color>
<color name="material_personalized_color_error">#FFFFFF</color>
<color name="material_personalized_color_on_error">#FFFFFF</color>
<color name="material_personalized_color_error_container">#FFFFFF</color>
<color name="material_personalized_color_on_error_container">#FFFFFF</color>

</resources>
Expand Up @@ -23,7 +23,41 @@
<item name="colorOnErrorContainer">@color/material_harmonized_color_on_error_container</item>
</style>

<!-- Used to provide an empty theme overlay placeholder for harmonization. -->
<!-- Used to provide an empty theme overlay placeholder for harmonization. Do not use this theme overlay directly, as the color resources will be replaced at runtime. -->
<style name="ThemeOverlay.Material3.HarmonizedColors.Empty" parent="" />

<!-- Used to provide an empty theme overlay placeholder for personalized colors, e.g. content color. Do not use this theme overlay directly, as the color resources will be replaced at runtime. -->
<style name="ThemeOverlay.Material3.PersonalizedColors" parent="">
<!-- Color palettes -->
<item name="colorPrimary">@color/material_personalized_color_primary</item>
<item name="colorOnPrimary">@color/material_personalized_color_on_primary</item>
<item name="colorPrimaryInverse">@color/material_personalized_color_primary_inverse</item>
<item name="colorPrimaryContainer">@color/material_personalized_color_primary_container</item>
<item name="colorOnPrimaryContainer">@color/material_personalized_color_on_primary_container</item>
<item name="colorSecondary">@color/material_personalized_color_secondary</item>
<item name="colorOnSecondary">@color/material_personalized_color_on_secondary</item>
<item name="colorSecondaryContainer">@color/material_personalized_color_secondary_container</item>
<item name="colorOnSecondaryContainer">@color/material_personalized_color_on_secondary_container</item>
<item name="colorTertiary">@color/material_personalized_color_tertiary</item>
<item name="colorOnTertiary">@color/material_personalized_color_on_tertiary</item>
<item name="colorTertiaryContainer">@color/material_personalized_color_tertiary_container</item>
<item name="colorOnTertiaryContainer">@color/material_personalized_color_on_tertiary_container</item>
<item name="android:colorBackground">@color/material_personalized_color_background</item>
<item name="colorOnBackground">@color/material_personalized_color_on_background</item>
<item name="colorSurface">@color/material_personalized_color_surface</item>
<item name="colorOnSurface">@color/material_personalized_color_on_surface</item>
<item name="colorSurfaceVariant">@color/material_personalized_color_surface_variant</item>
<item name="colorOnSurfaceVariant">@color/material_personalized_color_on_surface_variant</item>
<item name="colorSurfaceInverse">@color/material_personalized_color_surface_inverse</item>
<item name="colorOnSurfaceInverse">@color/material_personalized_color_on_surface_inverse</item>
<item name="colorOutline">@color/material_personalized_color_surface_outline</item>
<item name="colorError">@color/material_personalized_color_error</item>
<item name="colorOnError">@color/material_personalized_color_on_error</item>
<item name="colorErrorContainer">@color/material_personalized_color_error_container</item>
<item name="colorOnErrorContainer">@color/material_personalized_color_on_error_container</item>

<!-- Default Framework Text Colors. -->
<!-- TODO(b/254612063): Add default framework colors when the material color utilities library provides the color values for non-Material roles.-->
</style>

</resources>

0 comments on commit 8ca326a

Please sign in to comment.