diff options
author | Setup Wizard Team <android-setup-team-eng@google.com> | 2019-03-14 09:55:53 +0800 |
---|---|---|
committer | pastychang <pastychang@google.com> | 2019-03-14 10:40:06 +0800 |
commit | 82e3d14f503c6e75c53a0ce218afaffbfe47e31e (patch) | |
tree | df4354c7df1a47c0b9515f502223b4bcf1bd2b90 /main | |
parent | 1d8468829fcf4c6f94a7453a9b1c978e89f98eb0 (diff) | |
download | setupdesign-82e3d14f503c6e75c53a0ce218afaffbfe47e31e.tar.gz |
Import updated Android Setupdesign Library 238357199
Test: mm
PiperOrigin-RevId: 238357199
Change-Id: Ic3f1ca113eb1ab8aacc5cfcad5e3ec389f542788
Diffstat (limited to 'main')
28 files changed, 763 insertions, 149 deletions
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml index 9227caf..e59c74a 100644 --- a/main/AndroidManifest.xml +++ b/main/AndroidManifest.xml @@ -15,5 +15,7 @@ limitations under the License. --> -<manifest package="com.google.android.setupdesign"/> - +<manifest package="com.google.android.setupdesign"> + <!-- Set in the BUILD or gradle file --> + <uses-sdk /> +</manifest> diff --git a/main/res/drawable/sud_ic_expand_less.xml b/main/res/drawable-anydpi-v21/sud_ic_expand_less.xml index 6188b7e..6188b7e 100644 --- a/main/res/drawable/sud_ic_expand_less.xml +++ b/main/res/drawable-anydpi-v21/sud_ic_expand_less.xml diff --git a/main/res/drawable/sud_ic_expand_more.xml b/main/res/drawable-anydpi-v21/sud_ic_expand_more.xml index fcfe034..fcfe034 100644 --- a/main/res/drawable/sud_ic_expand_more.xml +++ b/main/res/drawable-anydpi-v21/sud_ic_expand_more.xml diff --git a/main/res/drawable-hdpi/sud_ic_expand_less.png b/main/res/drawable-hdpi/sud_ic_expand_less.png Binary files differnew file mode 100755 index 0000000..84e2e2d --- /dev/null +++ b/main/res/drawable-hdpi/sud_ic_expand_less.png diff --git a/main/res/drawable-hdpi/sud_ic_expand_more.png b/main/res/drawable-hdpi/sud_ic_expand_more.png Binary files differnew file mode 100755 index 0000000..2e30187 --- /dev/null +++ b/main/res/drawable-hdpi/sud_ic_expand_more.png diff --git a/main/res/drawable-mdpi/sud_ic_expand_less.png b/main/res/drawable-mdpi/sud_ic_expand_less.png Binary files differnew file mode 100755 index 0000000..82b75cf --- /dev/null +++ b/main/res/drawable-mdpi/sud_ic_expand_less.png diff --git a/main/res/drawable-mdpi/sud_ic_expand_more.png b/main/res/drawable-mdpi/sud_ic_expand_more.png Binary files differnew file mode 100755 index 0000000..3376379 --- /dev/null +++ b/main/res/drawable-mdpi/sud_ic_expand_more.png diff --git a/main/res/drawable-xhdpi/sud_ic_expand_less.png b/main/res/drawable-xhdpi/sud_ic_expand_less.png Binary files differnew file mode 100755 index 0000000..344f346 --- /dev/null +++ b/main/res/drawable-xhdpi/sud_ic_expand_less.png diff --git a/main/res/drawable-xhdpi/sud_ic_expand_more.png b/main/res/drawable-xhdpi/sud_ic_expand_more.png Binary files differnew file mode 100755 index 0000000..0310461 --- /dev/null +++ b/main/res/drawable-xhdpi/sud_ic_expand_more.png diff --git a/main/res/drawable-xxhdpi/sud_ic_expand_less.png b/main/res/drawable-xxhdpi/sud_ic_expand_less.png Binary files differnew file mode 100755 index 0000000..9075a97 --- /dev/null +++ b/main/res/drawable-xxhdpi/sud_ic_expand_less.png diff --git a/main/res/drawable-xxhdpi/sud_ic_expand_more.png b/main/res/drawable-xxhdpi/sud_ic_expand_more.png Binary files differnew file mode 100755 index 0000000..a3062f4 --- /dev/null +++ b/main/res/drawable-xxhdpi/sud_ic_expand_more.png diff --git a/main/res/layout/sud_glif_header.xml b/main/res/layout/sud_glif_header.xml index df5ffeb..478438c 100644 --- a/main/res/layout/sud_glif_header.xml +++ b/main/res/layout/sud_glif_header.xml @@ -22,7 +22,7 @@ android:orientation="vertical"> <ImageView - android:id="@+id/suc_layout_icon" + android:id="@+id/sud_layout_icon" style="?attr/sudGlifIconStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/main/res/layout/sud_items_progress_bar.xml b/main/res/layout/sud_items_progress_bar.xml new file mode 100644 index 0000000..302f9d4 --- /dev/null +++ b/main/res/layout/sud_items_progress_bar.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2019 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. +--> + +<com.google.android.setupdesign.view.FillContentLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/progress_circle_container"> + + <ProgressBar + android:id="@+id/progress_circle" + style="@style/SudFourColorIndeterminateProgressBar" + android:layout_gravity="top|center_horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + +</com.google.android.setupdesign.view.FillContentLayout> diff --git a/main/res/values-v21/styles.xml b/main/res/values-v21/styles.xml index 3613533..ee68651 100644 --- a/main/res/values-v21/styles.xml +++ b/main/res/values-v21/styles.xml @@ -97,10 +97,4 @@ <item name="android:paddingLeft">@dimen/sud_edit_text_padding_horizontal</item> <item name="android:paddingRight">@dimen/sud_edit_text_padding_horizontal</item> </style> - - <!-- Button styles --> - <style name="SudGlifButton.Tertiary" parent="SudGlifButton.BaseTertiary"> - <item name="android:fontFamily">sans-serif-medium</item> - <item name="textAllCaps" tools:targetApi="ice_cream_sandwich">false</item> - </style> </resources> diff --git a/main/res/values/attrs.xml b/main/res/values/attrs.xml index c3fcaf2..f4c2b2e 100644 --- a/main/res/values/attrs.xml +++ b/main/res/values/attrs.xml @@ -55,6 +55,13 @@ <attr name="sudNavBarButtonBackground" format="color|reference" /> <attr name="sudNavBarTextColor" format="color" /> <attr name="sudNavBarTheme" format="reference" /> + <attr name="sudIconTint" format="color" /> + <attr name="sudIconGravity"> + <!-- Values in the enum has to be the same as in android.view.Gravity --> + <enum name="top" value="0x30" /> + <enum name="center_vertical" value="0x10" /> + <enum name="bottom" value="0x50" /> + </attr> <!-- Values copied from frameworks/base/core/res/res/values/attrs.xml --> <attr name="sudScrollIndicators"> @@ -148,6 +155,8 @@ <attr name="android:summary" /> <attr name="android:title" /> <attr name="android:visible" /> + <attr name="sudIconTint" /> + <attr name="sudIconGravity" /> </declare-styleable> <declare-styleable name="SudDividerItemDecoration"> @@ -163,6 +172,12 @@ <attr name="android:theme" /> </declare-styleable> + <declare-styleable name="SudIconMixin"> + <attr name="android:icon" /> + <attr name="sudUpscaleIcon" format="boolean" /> + <attr name="sudIconTint" /> + </declare-styleable> + <declare-styleable name="SudListMixin"> <attr name="android:entries" /> <attr name="sudDividerInset" /> diff --git a/main/res/values/config.xml b/main/res/values/config.xml index daa00d3..dafc0dd 100644 --- a/main/res/values/config.xml +++ b/main/res/values/config.xml @@ -27,4 +27,6 @@ <string name="sudFontSecondary" translatable="false">google-sans</string> <string name="sudFontSecondaryMedium" translatable="false">google-sans-medium</string> + <item name="sud_layout_description" type="id" /> + </resources> diff --git a/main/res/values/styles.xml b/main/res/values/styles.xml index b0a3c0c..620af4a 100644 --- a/main/res/values/styles.xml +++ b/main/res/values/styles.xml @@ -420,6 +420,7 @@ <!-- Ignore UnusedResources: used by clients --> <style name="SudGlifButton.Tertiary" parent="SudGlifButton.BaseTertiary" tools:ignore="UnusedResources"> + <item name="android:fontFamily" tools:targetApi="jelly_bean">?attr/sudButtonFontFamily</item> <item name="textAllCaps" tools:targetApi="ice_cream_sandwich">false</item> </style> diff --git a/main/src/com/google/android/setupdesign/GlifLayout.java b/main/src/com/google/android/setupdesign/GlifLayout.java index ee36285..bb71976 100644 --- a/main/src/com/google/android/setupdesign/GlifLayout.java +++ b/main/src/com/google/android/setupdesign/GlifLayout.java @@ -35,12 +35,13 @@ import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; import com.google.android.setupcompat.PartnerCustomizationLayout; -import com.google.android.setupcompat.template.HeaderMixin; -import com.google.android.setupcompat.template.IconMixin; import com.google.android.setupcompat.template.StatusBarMixin; +import com.google.android.setupdesign.template.HeaderMixin; +import com.google.android.setupdesign.template.IconMixin; import com.google.android.setupdesign.template.ProgressBarMixin; import com.google.android.setupdesign.template.RequireScrollMixin; import com.google.android.setupdesign.template.ScrollViewScrollHandlingDelegate; +import com.google.android.setupdesign.util.DescriptionStyler; /** * Layout for the GLIF theme used in Setup Wizard for N. @@ -99,8 +100,11 @@ public class GlifLayout extends PartnerCustomizationLayout { // All the constructors delegate to this init method. The 3-argument constructor is not // available in LinearLayout before v11, so call super with the exact same arguments. private void init(AttributeSet attrs, int defStyleAttr) { - registerMixin(HeaderMixin.class, new HeaderMixin(this, attrs, defStyleAttr)); - registerMixin(IconMixin.class, new IconMixin(this, attrs, defStyleAttr)); + registerMixin( + HeaderMixin.class, + new HeaderMixin(this, attrs, defStyleAttr, shouldApplyPartnerResource())); + registerMixin( + IconMixin.class, new IconMixin(this, attrs, defStyleAttr, shouldApplyPartnerResource())); registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this)); final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this); registerMixin(RequireScrollMixin.class, requireScrollMixin); @@ -131,7 +135,18 @@ public class GlifLayout extends PartnerCustomizationLayout { if (stickyHeader != 0) { inflateStickyHeader(stickyHeader); } + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + TextView description = this.findManagedViewById(R.id.sud_layout_description); + if (description != null) { + if (shouldApplyPartnerResource()) { + DescriptionStyler.applyPartnerCustomizationStyle(description); + } + } } @Override diff --git a/main/src/com/google/android/setupdesign/SetupWizardLayout.java b/main/src/com/google/android/setupdesign/SetupWizardLayout.java index 35752cd..bec06b1 100644 --- a/main/src/com/google/android/setupdesign/SetupWizardLayout.java +++ b/main/src/com/google/android/setupdesign/SetupWizardLayout.java @@ -39,7 +39,8 @@ import android.view.ViewGroup; import android.widget.ScrollView; import android.widget.TextView; import com.google.android.setupcompat.internal.TemplateLayout; -import com.google.android.setupcompat.template.HeaderMixin; +import com.google.android.setupcompat.template.SystemNavBarMixin; +import com.google.android.setupdesign.template.HeaderMixin; import com.google.android.setupdesign.template.NavigationBarMixin; import com.google.android.setupdesign.template.ProgressBarMixin; import com.google.android.setupdesign.template.RequireScrollMixin; @@ -79,7 +80,12 @@ public class SetupWizardLayout extends TemplateLayout { // All the constructors delegate to this init method. The 3-argument constructor is not // available in LinearLayout before v11, so call super with the exact same arguments. private void init(AttributeSet attrs, int defStyleAttr) { - registerMixin(HeaderMixin.class, new HeaderMixin(this, attrs, defStyleAttr)); + registerMixin( + SystemNavBarMixin.class, + new SystemNavBarMixin(this, /* window= */ null, /* applyPartnerResources= */ false)); + registerMixin( + HeaderMixin.class, + new HeaderMixin(this, attrs, defStyleAttr, /* applyPartnerResource= */ false)); registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this)); registerMixin(NavigationBarMixin.class, new NavigationBarMixin(this)); final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this); diff --git a/main/src/com/google/android/setupdesign/items/Dividable.java b/main/src/com/google/android/setupdesign/items/Dividable.java new file mode 100644 index 0000000..7ed1332 --- /dev/null +++ b/main/src/com/google/android/setupdesign/items/Dividable.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 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.google.android.setupdesign.items; + +/** + * Same as {@link com.google.android.setupdesign.DividerItemDecoration.DividedViewHolder} but not + * limited for use to {@link androidx.recyclerview.widget.RecyclerView.ViewHolder} + */ +public interface Dividable { + /** + * Returns whether divider is allowed above this item. A divider will be shown only if both items + * immediately above and below it allows this divider. + */ + boolean isDividerAllowedAbove(); + + /** + * Returns whether divider is allowed below this item. A divider will be shown only if both items + * immediately above and below it allows this divider. + */ + boolean isDividerAllowedBelow(); +} diff --git a/main/src/com/google/android/setupdesign/items/Item.java b/main/src/com/google/android/setupdesign/items/Item.java index 4217b4e..7aa6297 100644 --- a/main/src/com/google/android/setupdesign/items/Item.java +++ b/main/src/com/google/android/setupdesign/items/Item.java @@ -18,10 +18,15 @@ package com.google.android.setupdesign.items; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.drawable.Drawable; +import androidx.annotation.ColorInt; import android.util.AttributeSet; +import android.view.Gravity; import android.view.View; +import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import com.google.android.setupdesign.R; @@ -37,6 +42,8 @@ public class Item extends AbstractItem { private CharSequence summary; private CharSequence title; private boolean visible = true; + @ColorInt private int iconTint = Color.TRANSPARENT; + private int iconGravity = Gravity.CENTER; public Item() { super(); @@ -52,6 +59,8 @@ public class Item extends AbstractItem { summary = a.getText(R.styleable.SudItem_android_summary); layoutRes = a.getResourceId(R.styleable.SudItem_android_layout, getDefaultLayoutResource()); visible = a.getBoolean(R.styleable.SudItem_android_visible, true); + iconTint = a.getColor(R.styleable.SudItem_sudIconTint, Color.TRANSPARENT); + iconGravity = a.getInt(R.styleable.SudItem_sudIconGravity, Gravity.CENTER); a.recycle(); } @@ -83,6 +92,23 @@ public class Item extends AbstractItem { return icon; } + public void setIconTint(@ColorInt int iconTint) { + this.iconTint = iconTint; + } + + @ColorInt + public int getIconTint() { + return iconTint; + } + + public void setIconGravity(int iconGravity) { + this.iconGravity = iconGravity; + } + + public int getIconGravity() { + return iconGravity; + } + public void setLayoutResource(int layoutResource) { layoutRes = layoutResource; notifyItemChanged(); @@ -155,6 +181,15 @@ public class Item extends AbstractItem { iconView.setImageDrawable(null); onMergeIconStateAndLevels(iconView, icon); iconView.setImageDrawable(icon); + if (iconTint != Color.TRANSPARENT) { + iconView.setColorFilter(iconTint); + } else { + iconView.clearColorFilter(); + } + LayoutParams layoutParams = iconContainer.getLayoutParams(); + if (layoutParams instanceof LinearLayout.LayoutParams) { + ((LinearLayout.LayoutParams) layoutParams).gravity = iconGravity; + } iconContainer.setVisibility(View.VISIBLE); } else { iconContainer.setVisibility(View.GONE); diff --git a/main/src/com/google/android/setupdesign/items/ItemViewHolder.java b/main/src/com/google/android/setupdesign/items/ItemViewHolder.java index b293cfe..f79b2b6 100644 --- a/main/src/com/google/android/setupdesign/items/ItemViewHolder.java +++ b/main/src/com/google/android/setupdesign/items/ItemViewHolder.java @@ -32,12 +32,12 @@ class ItemViewHolder extends RecyclerView.ViewHolder @Override public boolean isDividerAllowedAbove() { - return isEnabled; + return item instanceof Dividable ? ((Dividable) item).isDividerAllowedAbove() : isEnabled; } @Override public boolean isDividerAllowedBelow() { - return isEnabled; + return item instanceof Dividable ? ((Dividable) item).isDividerAllowedBelow() : isEnabled; } public void setEnabled(boolean isEnabled) { diff --git a/main/src/com/google/android/setupdesign/items/ProgressBarItem.java b/main/src/com/google/android/setupdesign/items/ProgressBarItem.java new file mode 100644 index 0000000..444a0d0 --- /dev/null +++ b/main/src/com/google/android/setupdesign/items/ProgressBarItem.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 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.google.android.setupdesign.items; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import com.google.android.setupdesign.R; + +public class ProgressBarItem extends Item { + + public ProgressBarItem() { + super(); + } + + public ProgressBarItem(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean isEnabled() { + // This item is not clickable. + return false; + } + + @Override + protected int getDefaultLayoutResource() { + return R.layout.sud_items_progress_bar; + } + + @Override + public void onBindView(View view) {} +} diff --git a/main/src/com/google/android/setupdesign/template/HeaderMixin.java b/main/src/com/google/android/setupdesign/template/HeaderMixin.java new file mode 100644 index 0000000..ea2063e --- /dev/null +++ b/main/src/com/google/android/setupdesign/template/HeaderMixin.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2017 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.google.android.setupdesign.template; + +import static android.content.res.ColorStateList.valueOf; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Typeface; +import androidx.annotation.AttrRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.ViewParent; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.google.android.setupcompat.R; +import com.google.android.setupcompat.internal.TemplateLayout; +import com.google.android.setupcompat.partnerconfig.PartnerConfig; +import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper; +import com.google.android.setupcompat.template.Mixin; + +/** + * A {@link com.google.android.setupcompat.template.Mixin} for setting and getting the header text. + */ +public class HeaderMixin implements Mixin { + + private final TemplateLayout templateLayout; + + /** + * @param layout The layout this Mixin belongs to. + * @param attrs XML attributes given to the layout. + * @param defStyleAttr The default style attribute as given to the constructor of the layout. + * @param applyPartnerResource Whether to apply partner resources or not. + */ + public HeaderMixin( + @NonNull TemplateLayout layout, + @Nullable AttributeSet attrs, + @AttrRes int defStyleAttr, + boolean applyPartnerResource) { + templateLayout = layout; + final Context context = layout.getContext(); + + final TypedArray a = + layout + .getContext() + .obtainStyledAttributes(attrs, R.styleable.SucHeaderMixin, defStyleAttr, 0); + + // Set the header text + final CharSequence headerText = a.getText(R.styleable.SucHeaderMixin_sucHeaderText); + if (headerText != null) { + setText(headerText); + } + // Set the header text color + final ColorStateList headerTextColor = + a.getColorStateList(R.styleable.SucHeaderMixin_sucHeaderTextColor); + if (headerTextColor != null) { + setTextColor(headerTextColor); + } + + a.recycle(); + + TextView header = layout.findManagedViewById(R.id.suc_layout_title); + if (header != null && applyPartnerResource) { + applyPartnerCustomizationStyle(context, header); + } + } + + public void applyPartnerCustomizationStyle(Context context, TextView header) { + + int textColor = + PartnerConfigHelper.get(context).getColor(context, PartnerConfig.CONFIG_HEADER_TEXT_COLOR); + if (textColor != 0) { + setTextColor(valueOf(textColor)); + } + + float textSize = + PartnerConfigHelper.get(context) + .getDimension(context, PartnerConfig.CONFIG_HEADER_TEXT_SIZE); + if (textSize != 0) { + setTextSize(textSize); + } + + String fontFamily = + PartnerConfigHelper.get(context) + .getString(context, PartnerConfig.CONFIG_HEADER_FONT_FAMILY); + if (fontFamily != null) { + setFontFamily(Typeface.create(fontFamily, Typeface.NORMAL)); + } + + String gravity = + PartnerConfigHelper.get(context).getString(context, PartnerConfig.CONFIG_LAYOUT_GRAVITY); + if (gravity != null) { + switch (gravity.toLowerCase()) { + case "center": + setGravity(header, Gravity.CENTER); + break; + case "start": + setGravity(header, Gravity.START); + break; + default: // fall out + } + } + + int color = + PartnerConfigHelper.get(context) + .getColor(context, PartnerConfig.CONFIG_HEADER_AREA_BACKGROUND_COLOR); + setBackgroundColor(color); + } + + /** @return The TextView displaying the header. */ + public TextView getTextView() { + return (TextView) templateLayout.findManagedViewById(R.id.suc_layout_title); + } + + /** + * Sets the header text. This can also be set via the XML attribute {@code app:sucHeaderText}. + * + * @param title The resource ID of the text to be set as header. + */ + public void setText(int title) { + final TextView titleView = getTextView(); + if (titleView != null) { + titleView.setText(title); + } + } + + /** + * Sets the header text. This can also be set via the XML attribute {@code app:sucHeaderText}. + * + * @param title The text to be set as header. + */ + public void setText(CharSequence title) { + final TextView titleView = getTextView(); + if (titleView != null) { + titleView.setText(title); + } + } + + /** @return The current header text. */ + public CharSequence getText() { + final TextView titleView = getTextView(); + return titleView != null ? titleView.getText() : null; + } + + private void setTextSize(float sizePx) { + final TextView titleView = getTextView(); + if (titleView != null) { + titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, sizePx); + } + } + + /** + * Sets the color of the header text. This can also be set via XML using {@code + * app:sucHeaderTextColor}. + * + * @param color The text color of the header. + */ + public void setTextColor(ColorStateList color) { + final TextView titleView = getTextView(); + if (titleView != null) { + titleView.setTextColor(color); + } + } + + /** Sets the background color of the header's parent LinearLayout */ + public void setBackgroundColor(int color) { + final TextView titleView = getTextView(); + if (titleView != null) { + ViewParent parent = titleView.getParent(); + if (parent instanceof LinearLayout) { + ((LinearLayout) parent).setBackgroundColor(color); + } + } + } + + private void setFontFamily(Typeface fontFamily) { + final TextView titleView = getTextView(); + if (titleView != null) { + titleView.setTypeface(fontFamily); + } + } + + /** Returns the current text color of the header. */ + public ColorStateList getTextColor() { + final TextView titleView = getTextView(); + return titleView != null ? titleView.getTextColors() : null; + } + + private void setGravity(TextView header, int gravity) { + header.setGravity(gravity); + } +} diff --git a/main/src/com/google/android/setupdesign/template/IconMixin.java b/main/src/com/google/android/setupdesign/template/IconMixin.java new file mode 100644 index 0000000..d68daa4 --- /dev/null +++ b/main/src/com/google/android/setupdesign/template/IconMixin.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2017 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.google.android.setupdesign.template; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; +import android.widget.LinearLayout; +import com.google.android.setupcompat.internal.TemplateLayout; +import com.google.android.setupcompat.template.Mixin; +import com.google.android.setupdesign.R; +import com.google.android.setupdesign.util.PartnerStyleHelper; + +/** + * A {@link com.google.android.setupcompat.template.Mixin} for setting an icon on the template + * layout. + */ +public class IconMixin implements Mixin { + + private final TemplateLayout templateLayout; + + private final int originalHeight; + private final ImageView.ScaleType originalScaleType; + + /** + * @param layout The template layout that this Mixin is a part of. + * @param attrs XML attributes given to the layout. + * @param defStyleAttr The default style attribute as given to the constructor of the layout. + * @param shouldApplyPartnerResource Whether to apply partner resources or not. + */ + public IconMixin( + TemplateLayout layout, + AttributeSet attrs, + int defStyleAttr, + boolean shouldApplyPartnerResource) { + templateLayout = layout; + final Context context = layout.getContext(); + + ImageView iconView = getView(); + if (iconView != null) { + LayoutParams layoutParams = iconView.getLayoutParams(); + originalHeight = layoutParams.height; + originalScaleType = iconView.getScaleType(); + } else { + originalHeight = 0; + originalScaleType = null; + } + + final TypedArray a = + context.obtainStyledAttributes(attrs, R.styleable.SudIconMixin, defStyleAttr, 0); + + final @DrawableRes int icon = a.getResourceId(R.styleable.SudIconMixin_android_icon, 0); + if (icon != 0) { + setIcon(icon); + } + + final boolean upscaleIcon = a.getBoolean(R.styleable.SudIconMixin_sudUpscaleIcon, false); + setUpscaleIcon(upscaleIcon); + + final @ColorInt int iconTint = + a.getColor(R.styleable.SudIconMixin_sudIconTint, Color.TRANSPARENT); + if (iconTint != Color.TRANSPARENT) { + setIconTint(iconTint); + } + + a.recycle(); + + ImageView iconImage = layout.findManagedViewById(R.id.sud_layout_icon); + if (iconImage != null && shouldApplyPartnerResource) { + applyPartnerCustomizationStyle(context, iconImage); + } + } + + public void applyPartnerCustomizationStyle(Context context, ImageView iconImage) { + int gravity = PartnerStyleHelper.getLayoutGravity(context); + if (gravity != 0) { + setGravity(iconImage, gravity); + } + } + + /** + * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}. + * + * @param icon A drawable icon. + */ + public void setIcon(Drawable icon) { + final ImageView iconView = getView(); + if (iconView != null) { + iconView.setImageDrawable(icon); + iconView.setVisibility(icon != null ? View.VISIBLE : View.GONE); + } + } + + /** + * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}. + * + * @param icon A drawable icon resource. + */ + public void setIcon(@DrawableRes int icon) { + final ImageView iconView = getView(); + if (iconView != null) { + // Note: setImageResource on the ImageView is overridden in AppCompatImageView for + // support lib users, which enables vector drawable compat to work on versions pre-L. + iconView.setImageResource(icon); + iconView.setVisibility(icon != 0 ? View.VISIBLE : View.GONE); + } + } + + /** @return The icon previously set in {@link #setIcon(Drawable)} or {@code android:icon} */ + public Drawable getIcon() { + final ImageView iconView = getView(); + return iconView != null ? iconView.getDrawable() : null; + } + + /** Forces the icon view to be as big as desired in the style. */ + public void setUpscaleIcon(boolean shouldUpscaleIcon) { + final ImageView iconView = getView(); + if (iconView != null) { + LayoutParams layoutParams = iconView.getLayoutParams(); + layoutParams.height = shouldUpscaleIcon ? iconView.getMaxHeight() : originalHeight; + iconView.setLayoutParams(layoutParams); + iconView.setScaleType(shouldUpscaleIcon ? ImageView.ScaleType.FIT_CENTER : originalScaleType); + } + } + + /** Tints the icon on this layout to the given color. */ + public void setIconTint(@ColorInt int tint) { + final ImageView iconView = getView(); + if (iconView != null) { + iconView.setColorFilter(tint); + } + } + + /** Sets the content description of the icon view */ + public void setContentDescription(CharSequence description) { + final ImageView iconView = getView(); + if (iconView != null) { + iconView.setContentDescription(description); + } + } + + /** @return The content description of the icon view */ + public CharSequence getContentDescription() { + final ImageView iconView = getView(); + return iconView != null ? iconView.getContentDescription() : null; + } + + /** @return The ImageView responsible for displaying the icon. */ + protected ImageView getView() { + return (ImageView) templateLayout.findManagedViewById(R.id.sud_layout_icon); + } + + private void setGravity(ImageView icon, int gravity) { + if (icon.getLayoutParams() instanceof LinearLayout.LayoutParams) { + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) icon.getLayoutParams(); + layoutParams.gravity = gravity; + icon.setLayoutParams(layoutParams); + } + } +} diff --git a/main/src/com/google/android/setupdesign/util/DescriptionStyler.java b/main/src/com/google/android/setupdesign/util/DescriptionStyler.java new file mode 100644 index 0000000..d4e7ded --- /dev/null +++ b/main/src/com/google/android/setupdesign/util/DescriptionStyler.java @@ -0,0 +1,84 @@ +package com.google.android.setupdesign.util; + +import android.content.Context; +import android.graphics.Typeface; +import androidx.annotation.VisibleForTesting; +import android.util.TypedValue; +import android.widget.TextView; +import com.google.android.setupcompat.partnerconfig.PartnerConfig; +import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper; + +/** Applies the given style properties for the style of the given type. */ +public class DescriptionStyler { + + public static void applyPartnerCustomizationStyle(TextView description) { + + final Context context = description.getContext(); + + int descriptionTextColor = + PartnerConfigHelper.get(context) + .getColor(context, PartnerConfig.CONFIG_DESCRIPTION_TEXT_COLOR); + if (descriptionTextColor != 0) { + setTextColor(description, descriptionTextColor); + } + + int descriptionLinkTextColor = + PartnerConfigHelper.get(context) + .getColor(context, PartnerConfig.CONFIG_DESCRIPTION_LINK_TEXT_COLOR); + if (descriptionLinkTextColor != 0) { + setLinkTextColor(description, descriptionLinkTextColor); + } + + float descriptionTextSize = + PartnerConfigHelper.get(context) + .getDimension(context, PartnerConfig.CONFIG_DESCRIPTION_TEXT_SIZE, 0); + if (descriptionTextSize != 0) { + setTextSize(description, descriptionTextSize); + } + + String fontFamilyName = + PartnerConfigHelper.get(context) + .getString(context, PartnerConfig.CONFIG_DESCRIPTION_FONT_FAMILY); + Typeface font = Typeface.create(fontFamilyName, Typeface.NORMAL); + if (font != null) { + setFontFamily(description, font); + } + + setGravity(description, PartnerStyleHelper.getLayoutGravity(context)); + } + + @VisibleForTesting + static void setTextSize(TextView description, float size) { + if (description != null) { + description.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); + } + } + + @VisibleForTesting + static void setFontFamily(TextView description, Typeface fontFamily) { + if (description != null) { + description.setTypeface(fontFamily); + } + } + + @VisibleForTesting + static void setTextColor(TextView description, int color) { + if (description != null) { + description.setTextColor(color); + } + } + + @VisibleForTesting + static void setLinkTextColor(TextView description, int color) { + if (description != null) { + description.setLinkTextColor(color); + } + } + + @VisibleForTesting + static void setGravity(TextView description, int gravity) { + if (description != null) { + description.setGravity(gravity); + } + } +} diff --git a/main/src/com/google/android/setupdesign/util/PartnerStyleHelper.java b/main/src/com/google/android/setupdesign/util/PartnerStyleHelper.java new file mode 100644 index 0000000..735b705 --- /dev/null +++ b/main/src/com/google/android/setupdesign/util/PartnerStyleHelper.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.google.android.setupdesign.util; + +import android.content.Context; +import android.view.Gravity; +import com.google.android.setupcompat.partnerconfig.PartnerConfig; +import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper; + +/** The helper reads styles from the partner configurations. */ +public class PartnerStyleHelper { + + public static int getLayoutGravity(Context context) { + String gravity = + PartnerConfigHelper.get(context).getString(context, PartnerConfig.CONFIG_LAYOUT_GRAVITY); + if (gravity != null) { + switch (gravity.toLowerCase()) { + case "center": + return Gravity.CENTER; + case "start": + return Gravity.START; + default: + return 0; + } + } + return 0; + } +} diff --git a/main/src/com/google/android/setupdesign/util/SystemBarHelper.java b/main/src/com/google/android/setupdesign/util/SystemBarHelper.java index e784fb0..467c4dc 100644 --- a/main/src/com/google/android/setupdesign/util/SystemBarHelper.java +++ b/main/src/com/google/android/setupdesign/util/SystemBarHelper.java @@ -16,7 +16,6 @@ package com.google.android.setupdesign.util; -import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Dialog; import android.content.Context; @@ -25,12 +24,12 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Handler; import androidx.annotation.RequiresPermission; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; +import com.google.android.setupcompat.util.SystemBarBaseHelper; /** * A helper class to manage the system navigation bar and status bar. This will add various @@ -46,37 +45,25 @@ public class SystemBarHelper { private static final String TAG = "SystemBarHelper"; - @SuppressLint("InlinedApi") - private static final int DEFAULT_IMMERSIVE_FLAGS = - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; - - @SuppressLint("InlinedApi") - private static final int DIALOG_IMMERSIVE_FLAGS = - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - /** Needs to be equal to View.STATUS_BAR_DISABLE_BACK */ private static final int STATUS_BAR_DISABLE_BACK = 0x00400000; /** - * The maximum number of retries when peeking the decor view. When polling for the decor view, - * waiting it to be installed, set a maximum number of retries. - */ - private static final int PEEK_DECOR_VIEW_RETRIES = 3; - - /** * Hide the navigation bar for a dialog. * * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op. + * + * @deprecated If the layout is instance of TemplateLayout, please use + * SystemNavBarMixin.hideSystemBars. */ + @Deprecated public static void hideSystemBars(final Dialog dialog) { if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { final Window window = dialog.getWindow(); temporarilyDisableDialogFocus(window); - addVisibilityFlag(window, DIALOG_IMMERSIVE_FLAGS); - addImmersiveFlagsToDecorView(window, DIALOG_IMMERSIVE_FLAGS); + SystemBarBaseHelper.addVisibilityFlag(window, SystemBarBaseHelper.DIALOG_IMMERSIVE_FLAGS); + SystemBarBaseHelper.addImmersiveFlagsToDecorView( + window, SystemBarBaseHelper.DIALOG_IMMERSIVE_FLAGS); // Also set the navigation bar and status bar to transparent color. Note that this // doesn't work if android.R.boolean.config_enableTranslucentDecor is false. @@ -93,11 +80,16 @@ public class SystemBarHelper { * Wizard style. * * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op. + * + * @deprecated If the layout instance of TemplateLayout, please use + * SystemNavBarMixin.hideSystemBars. */ + @Deprecated public static void hideSystemBars(final Window window) { if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - addVisibilityFlag(window, DEFAULT_IMMERSIVE_FLAGS); - addImmersiveFlagsToDecorView(window, DEFAULT_IMMERSIVE_FLAGS); + SystemBarBaseHelper.addVisibilityFlag(window, SystemBarBaseHelper.DEFAULT_IMMERSIVE_FLAGS); + SystemBarBaseHelper.addImmersiveFlagsToDecorView( + window, SystemBarBaseHelper.DEFAULT_IMMERSIVE_FLAGS); // Also set the navigation bar and status bar to transparent color. Note that this // doesn't work if android.R.boolean.config_enableTranslucentDecor is false. @@ -110,20 +102,16 @@ public class SystemBarHelper { * Revert the actions of hideSystemBars. Note that this will remove the system UI visibility flags * regardless of whether it is originally present. You should also manually reset the navigation * bar and status bar colors, as this method doesn't know what value to revert it to. + * + * @deprecated If the layout is instance of TemplateLayout, please use + * SystemNavBarMixin.showSystemBars. */ - public static void showSystemBars(final Dialog dialog, final Context context) { - showSystemBars(dialog.getWindow(), context); - } - - /** - * Revert the actions of hideSystemBars. Note that this will remove the system UI visibility flags - * regardless of whether it is originally present. You should also manually reset the navigation - * bar and status bar colors, as this method doesn't know what value to revert it to. - */ + @Deprecated public static void showSystemBars(final Window window, final Context context) { if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - removeVisibilityFlag(window, DEFAULT_IMMERSIVE_FLAGS); - removeImmersiveFlagsFromDecorView(window, DEFAULT_IMMERSIVE_FLAGS); + SystemBarBaseHelper.removeVisibilityFlag(window, SystemBarBaseHelper.DEFAULT_IMMERSIVE_FLAGS); + SystemBarBaseHelper.removeImmersiveFlagsFromDecorView( + window, SystemBarBaseHelper.DEFAULT_IMMERSIVE_FLAGS); if (context != null) { //noinspection AndroidLintInlinedApi @@ -139,44 +127,46 @@ public class SystemBarHelper { } } - /** Convenience method to add a visibility flag in addition to the existing ones. */ + /** + * Convenience method to add a visibility flag in addition to the existing ones. + * + * @deprecated Use SystemBarBaseHelper.addVisibilityFlag(final View view, final int flag). + */ + @Deprecated public static void addVisibilityFlag(final View view, final int flag) { - if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { - final int vis = view.getSystemUiVisibility(); - view.setSystemUiVisibility(vis | flag); - } + SystemBarBaseHelper.addVisibilityFlag(view, flag); } - /** Convenience method to add a visibility flag in addition to the existing ones. */ + /** + * Convenience method to add a visibility flag in addition to the existing ones. + * + * @deprecated Use SystemBarBaseHelper.addVisibilityFlag(final Window window, final int flag). + */ + @Deprecated public static void addVisibilityFlag(final Window window, final int flag) { - if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { - WindowManager.LayoutParams attrs = window.getAttributes(); - attrs.systemUiVisibility |= flag; - window.setAttributes(attrs); - } + SystemBarBaseHelper.addVisibilityFlag(window, flag); } /** * Convenience method to remove a visibility flag from the view, leaving other flags that are not * specified intact. + * + * @deprecated Use SystemBarBaseHelper.removeVisibilityFlag(final View view, final int flag). */ + @Deprecated public static void removeVisibilityFlag(final View view, final int flag) { - if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { - final int vis = view.getSystemUiVisibility(); - view.setSystemUiVisibility(vis & ~flag); - } + SystemBarBaseHelper.removeVisibilityFlag(view, flag); } /** * Convenience method to remove a visibility flag from the window, leaving other flags that are * not specified intact. + * + * @deprecated Use SystemBarBaseHelper.removeVisibilityFlag(final Window window, final int flag). */ + @Deprecated public static void removeVisibilityFlag(final Window window, final int flag) { - if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { - WindowManager.LayoutParams attrs = window.getAttributes(); - attrs.systemUiVisibility &= ~flag; - window.setAttributes(attrs); - } + SystemBarBaseHelper.removeVisibilityFlag(window, flag); } /** @@ -193,11 +183,11 @@ public class SystemBarHelper { public static void setBackButtonVisible(final Window window, final boolean visible) { if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) { if (visible) { - removeVisibilityFlag(window, STATUS_BAR_DISABLE_BACK); - removeImmersiveFlagsFromDecorView(window, STATUS_BAR_DISABLE_BACK); + SystemBarBaseHelper.removeVisibilityFlag(window, STATUS_BAR_DISABLE_BACK); + SystemBarBaseHelper.removeImmersiveFlagsFromDecorView(window, STATUS_BAR_DISABLE_BACK); } else { - addVisibilityFlag(window, STATUS_BAR_DISABLE_BACK); - addImmersiveFlagsToDecorView(window, STATUS_BAR_DISABLE_BACK); + SystemBarBaseHelper.addVisibilityFlag(window, STATUS_BAR_DISABLE_BACK); + SystemBarBaseHelper.addImmersiveFlagsToDecorView(window, STATUS_BAR_DISABLE_BACK); } } } @@ -222,80 +212,6 @@ public class SystemBarHelper { } /** - * Add the specified immersive flags to the decor view of the window, because {@link - * View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} only takes effect when it is added to a view instead of - * the window. - */ - @TargetApi(VERSION_CODES.HONEYCOMB) - private static void addImmersiveFlagsToDecorView(final Window window, final int vis) { - getDecorView( - window, - new OnDecorViewInstalledListener() { - @Override - public void onDecorViewInstalled(View decorView) { - addVisibilityFlag(decorView, vis); - } - }); - } - - @TargetApi(VERSION_CODES.HONEYCOMB) - private static void removeImmersiveFlagsFromDecorView(final Window window, final int vis) { - getDecorView( - window, - new OnDecorViewInstalledListener() { - @Override - public void onDecorViewInstalled(View decorView) { - removeVisibilityFlag(decorView, vis); - } - }); - } - - private static void getDecorView(Window window, OnDecorViewInstalledListener callback) { - new DecorViewFinder().getDecorView(window, callback, PEEK_DECOR_VIEW_RETRIES); - } - - private static class DecorViewFinder { - - private final Handler handler = new Handler(); - private Window window; - private int retries; - private OnDecorViewInstalledListener callback; - - private final Runnable checkDecorViewRunnable = - new Runnable() { - @Override - public void run() { - // Use peekDecorView instead of getDecorView so that clients can still set window - // features after calling this method. - final View decorView = window.peekDecorView(); - if (decorView != null) { - callback.onDecorViewInstalled(decorView); - } else { - retries--; - if (retries >= 0) { - // If the decor view is not installed yet, try again in the next loop. - handler.post(checkDecorViewRunnable); - } else { - Log.w(TAG, "Cannot get decor view of window: " + window); - } - } - } - }; - - public void getDecorView(Window window, OnDecorViewInstalledListener callback, int retries) { - this.window = window; - this.retries = retries; - this.callback = callback; - checkDecorViewRunnable.run(); - } - } - - private interface OnDecorViewInstalledListener { - - void onDecorViewInstalled(View decorView); - } - - /** * Apply a hack to temporarily set the window to not focusable, so that the navigation bar will * not show up during the transition. */ |