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