• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.android.setupwizardlib;
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;
26 import android.os.Build.VERSION_CODES;
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.android.setupwizardlib.template.ButtonFooterMixin;
39 import com.android.setupwizardlib.template.ColoredHeaderMixin;
40 import com.android.setupwizardlib.template.HeaderMixin;
41 import com.android.setupwizardlib.template.IconMixin;
42 import com.android.setupwizardlib.template.ProgressBarMixin;
43 import com.android.setupwizardlib.template.RequireScrollMixin;
44 import com.android.setupwizardlib.template.ScrollViewScrollHandlingDelegate;
45 import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
46 
47 /**
48  * Layout for the GLIF theme used in Setup Wizard for N.
49  *
50  * <p>Example usage:
51  *
52  * <pre>{@code
53  * &lt;com.android.setupwizardlib.GlifLayout
54  *     xmlns:android="http://schemas.android.com/apk/res/android"
55  *     xmlns:app="http://schemas.android.com/apk/res-auto"
56  *     android:layout_width="match_parent"
57  *     android:layout_height="match_parent"
58  *     android:icon="@drawable/my_icon"
59  *     app:suwHeaderText="@string/my_title">
60  *
61  *     &lt;!-- Content here -->
62  *
63  * &lt;/com.android.setupwizardlib.GlifLayout>
64  * }</pre>
65  */
66 public class GlifLayout extends TemplateLayout {
67 
68   private static final String TAG = "GlifLayout";
69 
70   private ColorStateList primaryColor;
71 
72   private boolean backgroundPatterned = true;
73 
74   /** The color of the background. If null, the color will inherit from primaryColor. */
75   @Nullable private ColorStateList backgroundBaseColor;
76 
77   private boolean layoutFullscreen = true;
78 
GlifLayout(Context context)79   public GlifLayout(Context context) {
80     this(context, 0, 0);
81   }
82 
GlifLayout(Context context, int template)83   public GlifLayout(Context context, int template) {
84     this(context, template, 0);
85   }
86 
GlifLayout(Context context, int template, int containerId)87   public GlifLayout(Context context, int template, int containerId) {
88     super(context, template, containerId);
89     init(null, R.attr.suwLayoutTheme);
90   }
91 
GlifLayout(Context context, AttributeSet attrs)92   public GlifLayout(Context context, AttributeSet attrs) {
93     super(context, attrs);
94     init(attrs, R.attr.suwLayoutTheme);
95   }
96 
97   @TargetApi(VERSION_CODES.HONEYCOMB)
GlifLayout(Context context, AttributeSet attrs, int defStyleAttr)98   public GlifLayout(Context context, AttributeSet attrs, int defStyleAttr) {
99     super(context, attrs, defStyleAttr);
100     init(attrs, defStyleAttr);
101   }
102 
103   // All the constructors delegate to this init method. The 3-argument constructor is not
104   // available in LinearLayout before v11, so call super with the exact same arguments.
init(AttributeSet attrs, int defStyleAttr)105   private void init(AttributeSet attrs, int defStyleAttr) {
106     registerMixin(HeaderMixin.class, new ColoredHeaderMixin(this, attrs, defStyleAttr));
107     registerMixin(IconMixin.class, new IconMixin(this, attrs, defStyleAttr));
108     registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
109     registerMixin(ButtonFooterMixin.class, new ButtonFooterMixin(this));
110     final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
111     registerMixin(RequireScrollMixin.class, requireScrollMixin);
112 
113     final ScrollView scrollView = getScrollView();
114     if (scrollView != null) {
115       requireScrollMixin.setScrollHandlingDelegate(
116           new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
117     }
118 
119     TypedArray a =
120         getContext().obtainStyledAttributes(attrs, R.styleable.SuwGlifLayout, defStyleAttr, 0);
121 
122     ColorStateList primaryColor = a.getColorStateList(R.styleable.SuwGlifLayout_suwColorPrimary);
123     if (primaryColor != null) {
124       setPrimaryColor(primaryColor);
125     }
126 
127     ColorStateList backgroundColor =
128         a.getColorStateList(R.styleable.SuwGlifLayout_suwBackgroundBaseColor);
129     setBackgroundBaseColor(backgroundColor);
130 
131     boolean backgroundPatterned =
132         a.getBoolean(R.styleable.SuwGlifLayout_suwBackgroundPatterned, true);
133     setBackgroundPatterned(backgroundPatterned);
134 
135     final int footer = a.getResourceId(R.styleable.SuwGlifLayout_suwFooter, 0);
136     if (footer != 0) {
137       inflateFooter(footer);
138     }
139 
140     final int stickyHeader = a.getResourceId(R.styleable.SuwGlifLayout_suwStickyHeader, 0);
141     if (stickyHeader != 0) {
142       inflateStickyHeader(stickyHeader);
143     }
144 
145     layoutFullscreen = a.getBoolean(R.styleable.SuwGlifLayout_suwLayoutFullscreen, true);
146 
147     a.recycle();
148 
149     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && layoutFullscreen) {
150       setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
151     }
152   }
153 
154   @Override
onInflateTemplate(LayoutInflater inflater, @LayoutRes int template)155   protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
156     if (template == 0) {
157       template = R.layout.suw_glif_template;
158     }
159     return inflateTemplate(inflater, R.style.SuwThemeGlif_Light, template);
160   }
161 
162   @Override
findContainer(int containerId)163   protected ViewGroup findContainer(int containerId) {
164     if (containerId == 0) {
165       containerId = R.id.suw_layout_content;
166     }
167     return super.findContainer(containerId);
168   }
169 
170   /**
171    * Sets the footer of the layout, which is at the bottom of the content area outside the scrolling
172    * container. The footer can only be inflated once per instance of this layout.
173    *
174    * @param footer The layout to be inflated as footer.
175    * @return The root of the inflated footer view.
176    */
inflateFooter(@ayoutRes int footer)177   public View inflateFooter(@LayoutRes int footer) {
178     ViewStub footerStub = findManagedViewById(R.id.suw_layout_footer);
179     footerStub.setLayoutResource(footer);
180     return footerStub.inflate();
181   }
182 
183   /**
184    * Sets the sticky header (i.e. header that doesn't scroll) of the layout, which is at the top of
185    * the content area outside of the scrolling container. The header can only be inflated once per
186    * instance of this layout.
187    *
188    * @param header The layout to be inflated as the header.
189    * @return The root of the inflated header view.
190    */
inflateStickyHeader(@ayoutRes int header)191   public View inflateStickyHeader(@LayoutRes int header) {
192     ViewStub stickyHeaderStub = findManagedViewById(R.id.suw_layout_sticky_header);
193     stickyHeaderStub.setLayoutResource(header);
194     return stickyHeaderStub.inflate();
195   }
196 
getScrollView()197   public ScrollView getScrollView() {
198     final View view = findManagedViewById(R.id.suw_scroll_view);
199     return view instanceof ScrollView ? (ScrollView) view : null;
200   }
201 
getHeaderTextView()202   public TextView getHeaderTextView() {
203     return getMixin(HeaderMixin.class).getTextView();
204   }
205 
setHeaderText(int title)206   public void setHeaderText(int title) {
207     getMixin(HeaderMixin.class).setText(title);
208   }
209 
setHeaderText(CharSequence title)210   public void setHeaderText(CharSequence title) {
211     getMixin(HeaderMixin.class).setText(title);
212   }
213 
getHeaderText()214   public CharSequence getHeaderText() {
215     return getMixin(HeaderMixin.class).getText();
216   }
217 
setHeaderColor(ColorStateList color)218   public void setHeaderColor(ColorStateList color) {
219     final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
220     mixin.setColor(color);
221   }
222 
getHeaderColor()223   public ColorStateList getHeaderColor() {
224     final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
225     return mixin.getColor();
226   }
227 
setIcon(Drawable icon)228   public void setIcon(Drawable icon) {
229     getMixin(IconMixin.class).setIcon(icon);
230   }
231 
getIcon()232   public Drawable getIcon() {
233     return getMixin(IconMixin.class).getIcon();
234   }
235 
236   /**
237    * Sets the primary color of this layout, which will be used to determine the color of the
238    * progress bar and the background pattern.
239    */
setPrimaryColor(@onNull ColorStateList color)240   public void setPrimaryColor(@NonNull ColorStateList color) {
241     primaryColor = color;
242     updateBackground();
243     getMixin(ProgressBarMixin.class).setColor(color);
244   }
245 
getPrimaryColor()246   public ColorStateList getPrimaryColor() {
247     return primaryColor;
248   }
249 
250   /**
251    * Sets the base color of the background view, which is the status bar for phones and the full-
252    * screen background for tablets. If {@link #isBackgroundPatterned()} is true, the pattern will be
253    * drawn with this color.
254    *
255    * @param color The color to use as the base color of the background. If {@code null}, {@link
256    *     #getPrimaryColor()} will be used.
257    */
setBackgroundBaseColor(@ullable ColorStateList color)258   public void setBackgroundBaseColor(@Nullable ColorStateList color) {
259     backgroundBaseColor = color;
260     updateBackground();
261   }
262 
263   /**
264    * @return The base color of the background. {@code null} indicates the background will be drawn
265    *     with {@link #getPrimaryColor()}.
266    */
267   @Nullable
getBackgroundBaseColor()268   public ColorStateList getBackgroundBaseColor() {
269     return backgroundBaseColor;
270   }
271 
272   /**
273    * Sets whether the background should be {@link GlifPatternDrawable}. If {@code false}, the
274    * background will be a solid color.
275    */
setBackgroundPatterned(boolean patterned)276   public void setBackgroundPatterned(boolean patterned) {
277     backgroundPatterned = patterned;
278     updateBackground();
279   }
280 
281   /** @return True if this view uses {@link GlifPatternDrawable} as background. */
isBackgroundPatterned()282   public boolean isBackgroundPatterned() {
283     return backgroundPatterned;
284   }
285 
updateBackground()286   private void updateBackground() {
287     final View patternBg = findManagedViewById(R.id.suw_pattern_bg);
288     if (patternBg != null) {
289       int backgroundColor = 0;
290       if (backgroundBaseColor != null) {
291         backgroundColor = backgroundBaseColor.getDefaultColor();
292       } else if (primaryColor != null) {
293         backgroundColor = primaryColor.getDefaultColor();
294       }
295       Drawable background =
296           backgroundPatterned
297               ? new GlifPatternDrawable(backgroundColor)
298               : new ColorDrawable(backgroundColor);
299       if (patternBg instanceof StatusBarBackgroundLayout) {
300         ((StatusBarBackgroundLayout) patternBg).setStatusBarBackground(background);
301       } else {
302         patternBg.setBackgroundDrawable(background);
303       }
304     }
305   }
306 
isProgressBarShown()307   public boolean isProgressBarShown() {
308     return getMixin(ProgressBarMixin.class).isShown();
309   }
310 
setProgressBarShown(boolean shown)311   public void setProgressBarShown(boolean shown) {
312     getMixin(ProgressBarMixin.class).setShown(shown);
313   }
314 
peekProgressBar()315   public ProgressBar peekProgressBar() {
316     return getMixin(ProgressBarMixin.class).peekProgressBar();
317   }
318 }
319