diff --git a/catalog/java/io/material/catalog/assets/res/drawable/ic_content_copy_24px.xml b/catalog/java/io/material/catalog/assets/res/drawable/ic_content_copy_24px.xml
new file mode 100644
index 00000000000..000645ca631
--- /dev/null
+++ b/catalog/java/io/material/catalog/assets/res/drawable/ic_content_copy_24px.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/catalog/java/io/material/catalog/color/ColorAdapterItem.java b/catalog/java/io/material/catalog/color/ColorAdapterItem.java
new file mode 100644
index 00000000000..61ee51ecd42
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorAdapterItem.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+/** Interface for the items in {@link ColorsAdapter}. */
+public interface ColorAdapterItem {}
diff --git a/catalog/java/io/material/catalog/color/ColorDynamicDemoFragment.java b/catalog/java/io/material/catalog/color/ColorDynamicDemoFragment.java
new file mode 100644
index 00000000000..02e3c8ad740
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorDynamicDemoFragment.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import io.material.catalog.R;
+
+import androidx.annotation.ArrayRes;
+import androidx.annotation.LayoutRes;
+
+/** A fragment that displays the Dynamic Palette demo for the Catalog app. */
+public class ColorDynamicDemoFragment extends ColorPaletteDemoFragment {
+
+ @LayoutRes
+ @Override
+ protected int getColorsLayoutResId() {
+ return R.layout.cat_colors_palette_fragment;
+ }
+
+ @ArrayRes
+ @Override
+ protected int getColorsArrayResId() {
+ return R.array.cat_dynamic_colors;
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorHeaderItem.java b/catalog/java/io/material/catalog/color/ColorHeaderItem.java
new file mode 100644
index 00000000000..c2304562130
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorHeaderItem.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import android.content.Context;
+import androidx.annotation.ColorRes;
+import androidx.annotation.NonNull;
+import java.util.List;
+
+/** A class for the headers in the color palette. */
+public class ColorHeaderItem implements ColorAdapterItem {
+
+ private static final String COLOR_600 = "600";
+
+ @ColorRes private final int backgroundColor;
+ private final String name;
+
+ ColorHeaderItem(Context context, List colors) {
+ ColorItem sample = colors.get(0);
+ for (ColorItem color : colors) {
+ if (color.getColorResName().contains(COLOR_600)) {
+ sample = color;
+ break;
+ }
+ }
+ MaterialColorSpec materialColor = MaterialColorSpec.create(context, sample.getColorRes());
+ backgroundColor = materialColor.getResourceId();
+ name = materialColor.getName();
+ }
+
+ @ColorRes
+ int getBackgroundColorRes() {
+ return backgroundColor;
+ }
+
+ /** Returns the raw name of the color. */
+ @NonNull
+ public String getName() {
+ return name;
+ }
+
+ /** Returns the display name for the header, e.g. Blue. */
+ @NonNull
+ public String getDisplayName() {
+ String name = getName();
+ String headerColor = name.replace('_', ' ');
+ return Character.toUpperCase(headerColor.charAt(0)) + headerColor.substring(1);
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorItem.java b/catalog/java/io/material/catalog/color/ColorItem.java
new file mode 100644
index 00000000000..7864e6cc5b3
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorItem.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import android.content.Context;
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+import androidx.annotation.NonNull;
+
+/** A class for the items in the color palette. */
+public class ColorItem implements ColorAdapterItem {
+
+ private final MaterialColorSpec colorSpec;
+
+ ColorItem(Context context, @ColorRes int colorRes) {
+ colorSpec = MaterialColorSpec.create(context, colorRes);
+ }
+
+ /** Returns the resource ID of the color. */
+ @NonNull
+ @ColorRes
+ public int getColorRes() {
+ return colorSpec.getResourceId();
+ }
+
+ /** Returns the resource name of the color, e.g. system_accent1_100. */
+ @NonNull
+ public String getColorResName() {
+ return colorSpec.getResourceName();
+ }
+
+ /** Returns the int value of the color. */
+ @ColorInt
+ int getColorValue() {
+ return colorSpec.getValue();
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorMainDemoFragment.java b/catalog/java/io/material/catalog/color/ColorMainDemoFragment.java
new file mode 100644
index 00000000000..7b000f309a4
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorMainDemoFragment.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import io.material.catalog.R;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import io.material.catalog.feature.DemoFragment;
+
+/** A placeholder fragment that displays the main Color demo for the Catalog app. */
+public class ColorMainDemoFragment extends DemoFragment {
+
+ @Nullable
+ @Override
+ public View onCreateDemoView(
+ @NonNull LayoutInflater layoutInflater,
+ @Nullable ViewGroup viewGroup,
+ @Nullable Bundle bundle) {
+ return layoutInflater.inflate(
+ R.layout.cat_colors_fragment, viewGroup, false /* attachToRoot */);
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorPaletteDemoFragment.java b/catalog/java/io/material/catalog/color/ColorPaletteDemoFragment.java
new file mode 100644
index 00000000000..42c4bacd651
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorPaletteDemoFragment.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import io.material.catalog.R;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Bundle;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.annotation.ArrayRes;
+import androidx.annotation.ColorInt;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import io.material.catalog.feature.DemoFragment;
+
+/** A fragment that displays the Color Palette demo for the Catalog app. */
+public abstract class ColorPaletteDemoFragment extends DemoFragment {
+
+ private static final int GREY_10 = 0xFF202124;
+
+ private ColorsAdapter adapter;
+
+ @Nullable
+ @Override
+ public View onCreateDemoView(
+ @NonNull LayoutInflater layoutInflater,
+ @Nullable ViewGroup viewGroup,
+ @Nullable Bundle bundle) {
+ View view = layoutInflater.inflate(getColorsLayoutResId(), viewGroup, false /* attachToRoot */);
+
+ RecyclerView recyclerView = (RecyclerView) view;
+ recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ adapter = new ColorsAdapter(getContext(), getColorsArrayResId());
+ recyclerView.setAdapter(adapter);
+ recyclerView.addItemDecoration(new ColorSectionsItemDecoration(getContext(), adapter));
+
+ return view;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.cat_colors_menu, menu);
+ super.onCreateOptionsMenu(menu, menuInflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem menuItem) {
+ if (menuItem.getItemId() == R.id.copy_colors) {
+ Context context = requireContext();
+ ClipboardManager clipboard =
+ (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("Colors", generateColorsText(adapter));
+ clipboard.setPrimaryClip(clip);
+ Toast.makeText(context, "Copied colors to clipboard.", Toast.LENGTH_LONG).show();
+ return true;
+ }
+ return super.onOptionsItemSelected(menuItem);
+ }
+
+ @LayoutRes
+ protected abstract int getColorsLayoutResId();
+
+ /**
+ * Returns an array of array resources containing a list of colors resource. Each group of colors
+ * will be displayed in a list.
+ */
+ @ArrayRes
+ protected abstract int getColorsArrayResId();
+
+ /** View holder class for the header of the color palette. */
+ static class ColorHeaderViewHolder extends ViewHolder {
+
+ private final TextView header;
+
+ ColorHeaderViewHolder(ViewGroup parent) {
+ super(
+ LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.cat_colors_palette_header, parent, false));
+
+ header = (TextView) itemView;
+ }
+
+ void bind(ColorHeaderItem headerItem) {
+ header.setText(headerItem.getDisplayName());
+ header.setBackgroundResource(headerItem.getBackgroundColorRes());
+ }
+ }
+
+ /** View holder class for the items of the color palette. */
+ static class ColorViewHolder extends ViewHolder {
+
+ private final Context context;
+ private final TextView nameView;
+ private final TextView descriptionView;
+
+ ColorViewHolder(ViewGroup parent) {
+ super(
+ LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.cat_colors_palette_item, parent, false));
+
+ nameView = itemView.findViewById(R.id.name);
+ descriptionView = itemView.findViewById(R.id.description);
+ context = itemView.getContext();
+ }
+
+ void bind(ColorItem colorItem) {
+ int value = ContextCompat.getColor(context, colorItem.getColorRes());
+ String colorResName = colorItem.getColorResName();
+ String resQualifier =
+ colorResName.startsWith(MaterialColorSpec.SYSTEM_PREFIX) ? "@android:color/" : "@color/";
+
+ nameView.setText(
+ context.getResources().getString(R.string.cat_color_res, resQualifier, colorResName));
+ descriptionView.setText(String.format("#%06x", value & 0xFFFFFF));
+
+ int textColor = getTextColor(colorItem);
+ nameView.setTextColor(textColor);
+ descriptionView.setTextColor(textColor);
+
+ itemView.setBackgroundResource(colorItem.getColorRes());
+ }
+
+ @ColorInt
+ private int getTextColor(ColorItem colorItem) {
+ if (colorItem.getColorValue() < MaterialColorSpec.TEXT_COLOR_SWITCH_VALUE) {
+ // Use dark grey if color value is less than TEXT_COLOR_SWITCH_VALUE.
+ return GREY_10;
+ } else {
+ return Color.WHITE;
+ }
+ }
+ }
+
+ private String generateColorsText(@NonNull ColorsAdapter adapter) {
+ StringBuilder colorsText = new StringBuilder();
+ for (ColorAdapterItem item : adapter.getItems()) {
+ if (item instanceof ColorHeaderItem) {
+ if (colorsText.length() > 0) {
+ colorsText.append("\n");
+ }
+ colorsText.append(((ColorHeaderItem) item).getDisplayName()).append("\n");
+ } else if (item instanceof ColorItem) {
+ ColorItem colorItem = (ColorItem) item;
+ int value = ContextCompat.getColor(getContext(), colorItem.getColorRes());
+ String colorResName = colorItem.getColorResName();
+ String resQualifier =
+ colorResName.startsWith(MaterialColorSpec.SYSTEM_PREFIX)
+ ? "@android:color/"
+ : "@color/";
+ colorsText.append(String.format("#%06x", value & 0xFFFFFF)).append("\n");
+ colorsText.append(resQualifier).append(colorResName).append("\n");
+ }
+ }
+ return colorsText.toString();
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorSectionsItemDecoration.java b/catalog/java/io/material/catalog/color/ColorSectionsItemDecoration.java
new file mode 100644
index 00000000000..7d479e6a4f0
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorSectionsItemDecoration.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import io.material.catalog.R;
+
+import android.content.Context;
+import android.graphics.Rect;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
+import androidx.recyclerview.widget.RecyclerView.State;
+import android.view.View;
+import androidx.annotation.NonNull;
+
+/**
+ * Allows the application to add a special drawing and layout offset to specific item views from the
+ * adapter's data set.
+ */
+public class ColorSectionsItemDecoration extends ItemDecoration {
+
+ private final int space;
+ private final ColorsAdapter adapter;
+
+ public ColorSectionsItemDecoration(@NonNull Context context, @NonNull ColorsAdapter adapter) {
+ this.space = context.getResources().getDimensionPixelSize(R.dimen.cat_colors_header_space);
+ this.adapter = adapter;
+ }
+
+ @NonNull
+ @Override
+ public void getItemOffsets(
+ @NonNull Rect rect,
+ @NonNull View view,
+ @NonNull RecyclerView recyclerView,
+ @NonNull State state) {
+ super.getItemOffsets(rect, view, recyclerView, state);
+
+ // Add space above each header except the first.
+ int position = recyclerView.getChildAdapterPosition(view);
+ if (position != 0 && adapter.getItemViewType(position) == ColorsAdapter.VIEW_TYPE_HEADER) {
+ rect.set(0, space, 0, 0);
+ }
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorsAdapter.java b/catalog/java/io/material/catalog/color/ColorsAdapter.java
new file mode 100644
index 00000000000..dc44dcaaeed
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/ColorsAdapter.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import android.view.ViewGroup;
+import androidx.annotation.ArrayRes;
+import androidx.annotation.NonNull;
+import io.material.catalog.color.ColorPaletteDemoFragment.ColorHeaderViewHolder;
+import io.material.catalog.color.ColorPaletteDemoFragment.ColorViewHolder;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Adapter class for the colors palette. */
+public class ColorsAdapter extends Adapter {
+
+ // The header indicator of a color.
+ public static final int VIEW_TYPE_HEADER = 0;
+
+ private static final int VIEW_TYPE_COLOR = 1;
+ private final List items = new ArrayList<>();
+ private final Context context;
+
+ public ColorsAdapter(@NonNull Context context, @NonNull @ArrayRes int colorItems) {
+ this.context = context;
+ TypedArray colorsArray = context.getResources().obtainTypedArray(colorItems);
+
+ for (int i = 0; i < colorsArray.length(); i++) {
+ List colors = getColorsFromArrayResource(colorsArray.getResourceId(i, 0));
+ items.add(new ColorHeaderItem(context, colors));
+ items.addAll(colors);
+ }
+
+ colorsArray.recycle();
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ switch (viewType) {
+ case VIEW_TYPE_HEADER:
+ return new ColorHeaderViewHolder(parent);
+ case VIEW_TYPE_COLOR:
+ return new ColorViewHolder(parent);
+ default:
+ // The default case should never be reached.
+ return null;
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
+ switch (getItemViewType(position)) {
+ case VIEW_TYPE_HEADER:
+ ColorHeaderItem header = (ColorHeaderItem) items.get(position);
+ ((ColorHeaderViewHolder) viewHolder).bind(header);
+ break;
+ case VIEW_TYPE_COLOR:
+ ColorItem item = (ColorItem) items.get(position);
+ ((ColorViewHolder) viewHolder).bind(item);
+ break;
+ default: // fall out
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return (items.get(position) instanceof ColorHeaderItem) ? VIEW_TYPE_HEADER : VIEW_TYPE_COLOR;
+ }
+
+ @Override
+ public int getItemCount() {
+ return items.size();
+ }
+
+ /** Returns the list of {@link ColorAdapterItem}s in the adapter. */
+ @NonNull
+ public List getItems() {
+ return items;
+ }
+
+ private List getColorsFromArrayResource(@ArrayRes int arrayRes) {
+ List colors = new ArrayList<>();
+ TypedArray colorsArray = context.getResources().obtainTypedArray(arrayRes);
+
+ for (int i = 0; i < colorsArray.length(); i++) {
+ int color = colorsArray.getResourceId(i, 0);
+ colors.add(new ColorItem(context, color));
+ }
+ colorsArray.recycle();
+ return colors;
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/ColorsFragment.java b/catalog/java/io/material/catalog/color/ColorsFragment.java
index 094a2603414..f2f7a3b8c89 100644
--- a/catalog/java/io/material/catalog/color/ColorsFragment.java
+++ b/catalog/java/io/material/catalog/color/ColorsFragment.java
@@ -20,6 +20,7 @@
import androidx.fragment.app.Fragment;
import androidx.annotation.NonNull;
+import com.google.android.material.color.DynamicColors;
import dagger.Provides;
import dagger.android.ContributesAndroidInjector;
import dagger.multibindings.IntoSet;
@@ -28,6 +29,8 @@
import io.material.catalog.feature.Demo;
import io.material.catalog.feature.DemoLandingFragment;
import io.material.catalog.feature.FeatureDemo;
+import java.util.ArrayList;
+import java.util.List;
/** A landing fragment that links to color demos for the Catalog app. */
public class ColorsFragment extends DemoLandingFragment {
@@ -48,11 +51,34 @@ public Demo getMainDemo() {
return new Demo() {
@Override
public Fragment createFragment() {
- return new ColorHarmonizationDemoFragment();
+ return new ColorMainDemoFragment();
}
};
}
+ @NonNull
+ @Override
+ public List getAdditionalDemos() {
+ List additionalDemos = new ArrayList<>();
+ if (DynamicColors.isDynamicColorAvailable()) {
+ additionalDemos.add(
+ new Demo(R.string.cat_color_dynamic_palette) {
+ @Override
+ public Fragment createFragment() {
+ return new ColorDynamicDemoFragment();
+ }
+ });
+ }
+ additionalDemos.add(
+ new Demo(R.string.cat_color_harmonization) {
+ @Override
+ public Fragment createFragment() {
+ return new ColorHarmonizationDemoFragment();
+ }
+ });
+ return additionalDemos;
+ }
+
/** The Dagger module for {@link ColorsFragment} dependencies. */
@dagger.Module
public abstract static class Module {
diff --git a/catalog/java/io/material/catalog/color/MaterialColorSpec.java b/catalog/java/io/material/catalog/color/MaterialColorSpec.java
new file mode 100644
index 00000000000..055e8933cc1
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/MaterialColorSpec.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2021 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 io.material.catalog.color;
+
+import android.content.Context;
+import androidx.annotation.ColorRes;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents a color value as defined in the Material Spec. These are all defined by color name +
+ * color value. ie. blue500.
+ */
+public final class MaterialColorSpec {
+ public static final String SYSTEM_PREFIX = "system_";
+ static final int TEXT_COLOR_SWITCH_VALUE = 400;
+
+ @ColorRes private final int resourceId;
+ private final String resourceName;
+ private final String name;
+ private final int value;
+
+ MaterialColorSpec(int resourceId, String resourceName, String name, int value) {
+ this.resourceId = resourceId;
+ this.resourceName = resourceName;
+ this.name = name;
+ this.value = value;
+ }
+
+ @ColorRes
+ int getResourceId() {
+ return resourceId;
+ }
+
+ String getResourceName() {
+ return resourceName;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ int getValue() {
+ return value;
+ }
+
+ static MaterialColorSpec create(Context context, @ColorRes int colorRes) {
+ String resName = context.getResources().getResourceEntryName(colorRes);
+ String name;
+ String value;
+ if (resName.startsWith(SYSTEM_PREFIX)) {
+ // Split the resource name into the color name and value, ie. system_accent1_500 to
+ // system_accent1 and 500.
+ int splitIndex = resName.lastIndexOf("_");
+ name = resName.substring(0, splitIndex);
+ value = resName.substring(splitIndex + 1);
+ } else {
+ // Get the name of the color an value without prefixes
+ // String trimmedResName = resName;
+ int splitIndex = resName.lastIndexOf("_");
+ String trimmedResName = resName.substring(splitIndex + 1);
+ // Split the resource name into the color name and value, ie. blue500 to blue and 500.
+ List parts = Arrays.asList(trimmedResName.split("(?<=\\D)(?=\\d)", -1));
+ name = parts.get(0);
+ value = parts.get(1);
+ }
+ return new MaterialColorSpec(colorRes, resName, name, Integer.parseInt(value));
+ }
+}
diff --git a/catalog/java/io/material/catalog/color/res/layout/cat_colors_fragment.xml b/catalog/java/io/material/catalog/color/res/layout/cat_colors_fragment.xml
new file mode 100644
index 00000000000..2de79543291
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/layout/cat_colors_fragment.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_fragment.xml b/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_fragment.xml
new file mode 100644
index 00000000000..f622e682328
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_fragment.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_header.xml b/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_header.xml
new file mode 100644
index 00000000000..9f650906e82
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_header.xml
@@ -0,0 +1,27 @@
+
+
+
+
diff --git a/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_item.xml b/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_item.xml
new file mode 100644
index 00000000000..225c5fad77e
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/layout/cat_colors_palette_item.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
diff --git a/catalog/java/io/material/catalog/color/res/menu/cat_colors_menu.xml b/catalog/java/io/material/catalog/color/res/menu/cat_colors_menu.xml
new file mode 100644
index 00000000000..9f2b6248597
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/menu/cat_colors_menu.xml
@@ -0,0 +1,26 @@
+
+
+
+
diff --git a/catalog/java/io/material/catalog/color/res/values-v31/arrays.xml b/catalog/java/io/material/catalog/color/res/values-v31/arrays.xml
new file mode 100644
index 00000000000..424692fc7b6
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/values-v31/arrays.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+ - @array/m3_colors_accent1_array
+ - @array/m3_colors_accent2_array
+ - @array/m3_colors_accent3_array
+ - @array/m3_colors_neutral1_array
+ - @array/m3_colors_neutral2_array
+
+
+
+ - @android:color/system_accent1_1000
+ - @android:color/system_accent1_900
+ - @android:color/system_accent1_800
+ - @android:color/system_accent1_700
+ - @android:color/system_accent1_600
+ - @android:color/system_accent1_500
+ - @android:color/system_accent1_400
+ - @android:color/system_accent1_300
+ - @android:color/system_accent1_200
+ - @android:color/system_accent1_100
+ - @android:color/system_accent1_50
+ - @android:color/system_accent1_10
+ - @android:color/system_accent1_0
+
+
+
+ - @android:color/system_accent2_1000
+ - @android:color/system_accent2_900
+ - @android:color/system_accent2_800
+ - @android:color/system_accent2_700
+ - @android:color/system_accent2_600
+ - @android:color/system_accent2_500
+ - @android:color/system_accent2_400
+ - @android:color/system_accent2_300
+ - @android:color/system_accent2_200
+ - @android:color/system_accent2_100
+ - @android:color/system_accent2_50
+ - @android:color/system_accent2_10
+ - @android:color/system_accent2_0
+
+
+
+ - @android:color/system_accent3_1000
+ - @android:color/system_accent3_900
+ - @android:color/system_accent3_800
+ - @android:color/system_accent3_700
+ - @android:color/system_accent3_600
+ - @android:color/system_accent3_500
+ - @android:color/system_accent3_400
+ - @android:color/system_accent3_300
+ - @android:color/system_accent3_200
+ - @android:color/system_accent3_100
+ - @android:color/system_accent3_50
+ - @android:color/system_accent3_10
+ - @android:color/system_accent3_0
+
+
+
+ - @android:color/system_neutral1_1000
+ - @android:color/system_neutral1_900
+ - @android:color/system_neutral1_800
+ - @android:color/system_neutral1_700
+ - @android:color/system_neutral1_600
+ - @android:color/system_neutral1_500
+ - @android:color/system_neutral1_400
+ - @android:color/system_neutral1_300
+ - @android:color/system_neutral1_200
+ - @android:color/system_neutral1_100
+ - @android:color/system_neutral1_50
+ - @android:color/system_neutral1_10
+ - @android:color/system_neutral1_0
+
+
+
+ - @android:color/system_neutral2_1000
+ - @android:color/system_neutral2_900
+ - @android:color/system_neutral2_800
+ - @android:color/system_neutral2_700
+ - @android:color/system_neutral2_600
+ - @android:color/system_neutral2_500
+ - @android:color/system_neutral2_400
+ - @android:color/system_neutral2_300
+ - @android:color/system_neutral2_200
+ - @android:color/system_neutral2_100
+ - @android:color/system_neutral2_50
+ - @android:color/system_neutral2_10
+ - @android:color/system_neutral2_0
+
+
diff --git a/catalog/java/io/material/catalog/color/res/values/colors.xml b/catalog/java/io/material/catalog/color/res/values/colors.xml
index 373f082b70d..5e6cd3284b8 100644
--- a/catalog/java/io/material/catalog/color/res/values/colors.xml
+++ b/catalog/java/io/material/catalog/color/res/values/colors.xml
@@ -19,5 +19,7 @@
#ffd93025
#ff1e8e3e
#ffd9e6f9
+ #ff202124
+
diff --git a/catalog/java/io/material/catalog/color/res/values/dimens.xml b/catalog/java/io/material/catalog/color/res/values/dimens.xml
new file mode 100644
index 00000000000..1351a61eb0b
--- /dev/null
+++ b/catalog/java/io/material/catalog/color/res/values/dimens.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 32dp
+
diff --git a/catalog/java/io/material/catalog/color/res/values/strings.xml b/catalog/java/io/material/catalog/color/res/values/strings.xml
index 8e71bec494e..ad2b3e0f5ba 100644
--- a/catalog/java/io/material/catalog/color/res/values/strings.xml
+++ b/catalog/java/io/material/catalog/color/res/values/strings.xml
@@ -28,4 +28,11 @@
Unelevated button
Color hex value: %1$s
+ Color Harmonization Demo
+ Dynamic Palette Demo
+
+ Copy colors
+
+ %1$s%2$s
+