Home | History | Annotate | Download | only in setupdesign
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.android.setupdesign;
     18 
     19 import android.annotation.TargetApi;
     20 import android.content.Context;
     21 import android.content.res.ColorStateList;
     22 import android.content.res.TypedArray;
     23 import android.graphics.drawable.ColorDrawable;
     24 import android.graphics.drawable.Drawable;
     25 import android.os.Build.VERSION_CODES;
     26 import androidx.annotation.ColorInt;
     27 import androidx.annotation.LayoutRes;
     28 import androidx.annotation.NonNull;
     29 import androidx.annotation.Nullable;
     30 import android.util.AttributeSet;
     31 import android.view.LayoutInflater;
     32 import android.view.View;
     33 import android.view.ViewGroup;
     34 import android.view.ViewStub;
     35 import android.widget.ProgressBar;
     36 import android.widget.ScrollView;
     37 import android.widget.TextView;
     38 import com.google.android.setupcompat.PartnerCustomizationLayout;
     39 import com.google.android.setupcompat.partnerconfig.PartnerConfig;
     40 import com.google.android.setupcompat.partnerconfig.PartnerConfigHelper;
     41 import com.google.android.setupcompat.template.StatusBarMixin;
     42 import com.google.android.setupdesign.template.HeaderMixin;
     43 import com.google.android.setupdesign.template.IconMixin;
     44 import com.google.android.setupdesign.template.ProgressBarMixin;
     45 import com.google.android.setupdesign.template.RequireScrollMixin;
     46 import com.google.android.setupdesign.template.ScrollViewScrollHandlingDelegate;
     47 import com.google.android.setupdesign.util.DescriptionStyler;
     48 
     49 /**
     50  * Layout for the GLIF theme used in Setup Wizard for N.
     51  *
     52  * <p>Example usage:
     53  *
     54  * <pre>{@code
     55  * &lt;com.google.android.setupdesign.GlifLayout
     56  *     xmlns:android="http://schemas.android.com/apk/res/android"
     57  *     xmlns:app="http://schemas.android.com/apk/res-auto"
     58  *     android:layout_width="match_parent"
     59  *     android:layout_height="match_parent"
     60  *     android:icon="@drawable/my_icon"
     61  *     app:sucHeaderText="@string/my_title">
     62  *
     63  *     &lt;!-- Content here -->
     64  *
     65  * &lt;/com.google.android.setupdesign.GlifLayout>
     66  * }</pre>
     67  */
     68 public class GlifLayout extends PartnerCustomizationLayout {
     69 
     70   private static final String TAG = "GlifLayout";
     71 
     72   private ColorStateList primaryColor;
     73 
     74   private boolean backgroundPatterned = true;
     75 
     76   private boolean applyPartnerHeavyThemeResource = false;
     77 
     78   /** The color of the background. If null, the color will inherit from primaryColor. */
     79   @Nullable private ColorStateList backgroundBaseColor;
     80 
     81   public GlifLayout(Context context) {
     82     this(context, 0, 0);
     83   }
     84 
     85   public GlifLayout(Context context, int template) {
     86     this(context, template, 0);
     87   }
     88 
     89   public GlifLayout(Context context, int template, int containerId) {
     90     super(context, template, containerId);
     91     init(null, R.attr.sudLayoutTheme);
     92   }
     93 
     94   public GlifLayout(Context context, AttributeSet attrs) {
     95     super(context, attrs);
     96     init(attrs, R.attr.sudLayoutTheme);
     97   }
     98 
     99   @TargetApi(VERSION_CODES.HONEYCOMB)
    100   public GlifLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    101     super(context, attrs, defStyleAttr);
    102     init(attrs, defStyleAttr);
    103   }
    104 
    105   // All the constructors delegate to this init method. The 3-argument constructor is not
    106   // available in LinearLayout before v11, so call super with the exact same arguments.
    107   private void init(AttributeSet attrs, int defStyleAttr) {
    108 
    109     TypedArray a =
    110         getContext().obtainStyledAttributes(attrs, R.styleable.SudGlifLayout, defStyleAttr, 0);
    111     boolean usePartnerHeavyTheme =
    112         a.getBoolean(R.styleable.SudGlifLayout_sudUsePartnerHeavyTheme, false);
    113     applyPartnerHeavyThemeResource = shouldApplyPartnerResource() && usePartnerHeavyTheme;
    114 
    115     registerMixin(
    116         HeaderMixin.class,
    117         new HeaderMixin(this, attrs, defStyleAttr));
    118     registerMixin(
    119         IconMixin.class, new IconMixin(this, attrs, defStyleAttr));
    120     registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
    121     final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
    122     registerMixin(RequireScrollMixin.class, requireScrollMixin);
    123 
    124     final ScrollView scrollView = getScrollView();
    125     if (scrollView != null) {
    126       requireScrollMixin.setScrollHandlingDelegate(
    127           new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
    128     }
    129 
    130     ColorStateList primaryColor = a.getColorStateList(R.styleable.SudGlifLayout_sudColorPrimary);
    131     if (primaryColor != null) {
    132       setPrimaryColor(primaryColor);
    133     }
    134 
    135     if (applyPartnerHeavyThemeResource) {
    136       updateContentBackgroundColorWithPartnerConfig();
    137     }
    138 
    139     ColorStateList backgroundColor =
    140         a.getColorStateList(R.styleable.SudGlifLayout_sudBackgroundBaseColor);
    141     setBackgroundBaseColor(backgroundColor);
    142 
    143     boolean backgroundPatterned =
    144         a.getBoolean(R.styleable.SudGlifLayout_sudBackgroundPatterned, true);
    145     setBackgroundPatterned(backgroundPatterned);
    146 
    147     final int stickyHeader = a.getResourceId(R.styleable.SudGlifLayout_sudStickyHeader, 0);
    148     if (stickyHeader != 0) {
    149       inflateStickyHeader(stickyHeader);
    150     }
    151     a.recycle();
    152   }
    153 
    154   @Override
    155   protected void onFinishInflate() {
    156     super.onFinishInflate();
    157 
    158     TextView description = this.findManagedViewById(R.id.sud_layout_description);
    159     if (description != null) {
    160       if (applyPartnerHeavyThemeResource) {
    161         DescriptionStyler.applyPartnerCustomizationStyle(description);
    162       }
    163     }
    164     getMixin(IconMixin.class).applyPartnerCustomizationStyle();
    165     getMixin(HeaderMixin.class).applyPartnerCustomizationStyle();
    166   }
    167 
    168   @Override
    169   protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
    170     if (template == 0) {
    171       template = R.layout.sud_glif_template;
    172     }
    173     return inflateTemplate(inflater, R.style.SudThemeGlif_Light, template);
    174   }
    175 
    176   @Override
    177   protected ViewGroup findContainer(int containerId) {
    178     if (containerId == 0) {
    179       containerId = R.id.sud_layout_content;
    180     }
    181     return super.findContainer(containerId);
    182   }
    183 
    184   /**
    185    * Sets the sticky header (i.e. header that doesn't scroll) of the layout, which is at the top of
    186    * the content area outside of the scrolling container. The header can only be inflated once per
    187    * instance of this layout.
    188    *
    189    * @param header The layout to be inflated as the header.
    190    * @return The root of the inflated header view.
    191    */
    192   public View inflateStickyHeader(@LayoutRes int header) {
    193     ViewStub stickyHeaderStub = findManagedViewById(R.id.sud_layout_sticky_header);
    194     stickyHeaderStub.setLayoutResource(header);
    195     return stickyHeaderStub.inflate();
    196   }
    197 
    198   public ScrollView getScrollView() {
    199     final View view = findManagedViewById(R.id.sud_scroll_view);
    200     return view instanceof ScrollView ? (ScrollView) view : null;
    201   }
    202 
    203   public TextView getHeaderTextView() {
    204     return getMixin(HeaderMixin.class).getTextView();
    205   }
    206 
    207   public void setHeaderText(int title) {
    208     getMixin(HeaderMixin.class).setText(title);
    209   }
    210 
    211   public void setHeaderText(CharSequence title) {
    212     getMixin(HeaderMixin.class).setText(title);
    213   }
    214 
    215   public CharSequence getHeaderText() {
    216     return getMixin(HeaderMixin.class).getText();
    217   }
    218 
    219   public void setHeaderColor(ColorStateList color) {
    220     getMixin(HeaderMixin.class).setTextColor(color);
    221   }
    222 
    223   public ColorStateList getHeaderColor() {
    224     return getMixin(HeaderMixin.class).getTextColor();
    225   }
    226 
    227   public void setIcon(Drawable icon) {
    228     getMixin(IconMixin.class).setIcon(icon);
    229   }
    230 
    231   public Drawable getIcon() {
    232     return getMixin(IconMixin.class).getIcon();
    233   }
    234 
    235   /**
    236    * Sets the primary color of this layout, which will be used to determine the color of the
    237    * progress bar and the background pattern.
    238    */
    239   public void setPrimaryColor(@NonNull ColorStateList color) {
    240     primaryColor = color;
    241     updateBackground();
    242     getMixin(ProgressBarMixin.class).setColor(color);
    243   }
    244 
    245   public ColorStateList getPrimaryColor() {
    246     return primaryColor;
    247   }
    248 
    249   /**
    250    * Sets the base color of the background view, which is the status bar for phones and the full-
    251    * screen background for tablets. If {@link #isBackgroundPatterned()} is true, the pattern will be
    252    * drawn with this color.
    253    *
    254    * @param color The color to use as the base color of the background. If {@code null}, {@link
    255    *     #getPrimaryColor()} will be used.
    256    */
    257   public void setBackgroundBaseColor(@Nullable ColorStateList color) {
    258     backgroundBaseColor = color;
    259     updateBackground();
    260   }
    261 
    262   /**
    263    * @return The base color of the background. {@code null} indicates the background will be drawn
    264    *     with {@link #getPrimaryColor()}.
    265    */
    266   @Nullable
    267   public ColorStateList getBackgroundBaseColor() {
    268     return backgroundBaseColor;
    269   }
    270 
    271   /**
    272    * Sets whether the background should be {@link GlifPatternDrawable}. If {@code false}, the
    273    * background will be a solid color.
    274    */
    275   public void setBackgroundPatterned(boolean patterned) {
    276     backgroundPatterned = patterned;
    277     updateBackground();
    278   }
    279 
    280   /** @return True if this view uses {@link GlifPatternDrawable} as background. */
    281   public boolean isBackgroundPatterned() {
    282     return backgroundPatterned;
    283   }
    284 
    285   private void updateBackground() {
    286     final View patternBg = findManagedViewById(R.id.suc_layout_status);
    287     if (patternBg != null) {
    288       int backgroundColor = 0;
    289       if (backgroundBaseColor != null) {
    290         backgroundColor = backgroundBaseColor.getDefaultColor();
    291       } else if (primaryColor != null) {
    292         backgroundColor = primaryColor.getDefaultColor();
    293       }
    294       Drawable background =
    295           backgroundPatterned
    296               ? new GlifPatternDrawable(backgroundColor)
    297               : new ColorDrawable(backgroundColor);
    298       getMixin(StatusBarMixin.class).setStatusBarBackground(background);
    299     }
    300   }
    301 
    302   public boolean isProgressBarShown() {
    303     return getMixin(ProgressBarMixin.class).isShown();
    304   }
    305 
    306   public void setProgressBarShown(boolean shown) {
    307     getMixin(ProgressBarMixin.class).setShown(shown);
    308   }
    309 
    310   public ProgressBar peekProgressBar() {
    311     return getMixin(ProgressBarMixin.class).peekProgressBar();
    312   }
    313 
    314   /**
    315    * Returns if the current layout/activity applies heavy partner customized configurations or not.
    316    */
    317   public boolean shouldApplyPartnerHeavyThemeResource() {
    318     return applyPartnerHeavyThemeResource;
    319   }
    320 
    321   /** Updates the background color of this layout with the partner-customizable background color. */
    322   private void updateContentBackgroundColorWithPartnerConfig() {
    323     @ColorInt
    324     int color =
    325         PartnerConfigHelper.get(getContext())
    326             .getColor(getContext(), PartnerConfig.CONFIG_LAYOUT_BACKGROUND_COLOR);
    327     this.getRootView().setBackgroundColor(color);
    328   }
    329 }
    330