SetupWizardLibrary/library/main/src/com/android/setupwizardlib/GlifLayout.java
Maurice Lam 0ceb8d53e3 Add ability to require scroll to GlifLayout
Generalize RequireScrollHelper and turn it into a mixin to allow
GlifLayout to use require scrolling.
This is only applicable to GLIF with sticky footer, since inline
content button requires scrolling by definition.

Also added Robolectric test support for full-support, by moving
full-support/test's contents into full-support/test/instrumentation
and put the new Robolectric tests in full-support/test/robotest.

Bug: 36387078
Test: ./gradlew connectedAndroidTest test
Change-Id: Ib07ec0ddf07affa30c46e786f4e9be7853a243c4
2017-03-24 14:57:06 -07:00

300 lines
10 KiB
Java

/*
* Copyright (C) 2015 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.android.setupwizardlib;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import com.android.setupwizardlib.template.ButtonFooterMixin;
import com.android.setupwizardlib.template.ColoredHeaderMixin;
import com.android.setupwizardlib.template.HeaderMixin;
import com.android.setupwizardlib.template.IconMixin;
import com.android.setupwizardlib.template.ProgressBarMixin;
import com.android.setupwizardlib.template.RequireScrollMixin;
import com.android.setupwizardlib.template.ScrollViewScrollHandlingDelegate;
import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
/**
* Layout for the GLIF theme used in Setup Wizard for N.
*
* <p>Example usage:
* <pre>{@code
* &lt;com.android.setupwizardlib.GlifLayout
* xmlns:android="http://schemas.android.com/apk/res/android"
* xmlns:app="http://schemas.android.com/apk/res-auto"
* android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:icon="@drawable/my_icon"
* app:suwHeaderText="@string/my_title">
*
* &lt;!-- Content here -->
*
* &lt;/com.android.setupwizardlib.GlifLayout>
* }</pre>
*/
public class GlifLayout extends TemplateLayout {
private static final String TAG = "GlifLayout";
private ColorStateList mPrimaryColor;
private boolean mBackgroundPatterned = true;
/**
* The color of the background. If null, the color will inherit from mPrimaryColor.
*/
@Nullable
private ColorStateList mBackgroundBaseColor;
public GlifLayout(Context context) {
this(context, 0, 0);
}
public GlifLayout(Context context, int template) {
this(context, template, 0);
}
public GlifLayout(Context context, int template, int containerId) {
super(context, template, containerId);
init(null, R.attr.suwLayoutTheme);
}
public GlifLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, R.attr.suwLayoutTheme);
}
@TargetApi(VERSION_CODES.HONEYCOMB)
public GlifLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
// 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 ColoredHeaderMixin(this, attrs, defStyleAttr));
registerMixin(IconMixin.class, new IconMixin(this, attrs, defStyleAttr));
registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
registerMixin(ButtonFooterMixin.class, new ButtonFooterMixin(this));
final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
registerMixin(RequireScrollMixin.class, requireScrollMixin);
final ScrollView scrollView = getScrollView();
if (scrollView != null) {
requireScrollMixin.setScrollHandlingDelegate(
new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
}
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.SuwGlifLayout, defStyleAttr, 0);
ColorStateList primaryColor =
a.getColorStateList(R.styleable.SuwGlifLayout_suwColorPrimary);
if (primaryColor != null) {
setPrimaryColor(primaryColor);
}
ColorStateList backgroundColor =
a.getColorStateList(R.styleable.SuwGlifLayout_suwBackgroundBaseColor);
setBackgroundBaseColor(backgroundColor);
boolean backgroundPatterned =
a.getBoolean(R.styleable.SuwGlifLayout_suwBackgroundPatterned, true);
setBackgroundPatterned(backgroundPatterned);
final int footer = a.getResourceId(R.styleable.SuwGlifLayout_suwFooter, 0);
if (footer != 0) {
inflateFooter(footer);
}
a.recycle();
}
@Override
protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
if (template == 0) {
template = R.layout.suw_glif_template;
}
return inflateTemplate(inflater, R.style.SuwThemeGlif_Light, template);
}
@Override
protected ViewGroup findContainer(int containerId) {
if (containerId == 0) {
containerId = R.id.suw_layout_content;
}
return super.findContainer(containerId);
}
/**
* Sets the footer of the layout, which is at the bottom of the content area outside the
* scrolling container. The footer can only be inflated once per layout.
*
* @param footer The layout to be inflated as footer.
* @return The root of the inflated footer view.
*/
public View inflateFooter(@LayoutRes int footer) {
ViewStub footerStub = (ViewStub) findManagedViewById(R.id.suw_layout_footer);
footerStub.setLayoutResource(footer);
return footerStub.inflate();
}
public ScrollView getScrollView() {
final View view = findManagedViewById(R.id.suw_scroll_view);
return view instanceof ScrollView ? (ScrollView) view : null;
}
public TextView getHeaderTextView() {
return getMixin(HeaderMixin.class).getTextView();
}
public void setHeaderText(int title) {
getMixin(HeaderMixin.class).setText(title);
}
public void setHeaderText(CharSequence title) {
getMixin(HeaderMixin.class).setText(title);
}
public CharSequence getHeaderText() {
return getMixin(HeaderMixin.class).getText();
}
public void setHeaderColor(ColorStateList color) {
final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
mixin.setColor(color);
}
public ColorStateList getHeaderColor() {
final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
return mixin.getColor();
}
public void setIcon(Drawable icon) {
getMixin(IconMixin.class).setIcon(icon);
}
public Drawable getIcon() {
return getMixin(IconMixin.class).getIcon();
}
/**
* Sets the primary color of this layout, which will be used to determine the color of the
* progress bar and the background pattern.
*/
public void setPrimaryColor(@NonNull ColorStateList color) {
mPrimaryColor = color;
updateBackground();
getMixin(ProgressBarMixin.class).setColor(color);
}
public ColorStateList getPrimaryColor() {
return mPrimaryColor;
}
/**
* Sets the base color of the background view, which is the status bar for phones and the full-
* screen background for tablets. If {@link #isBackgroundPatterned()} is true, the pattern will
* be drawn with this color.
*
* @param color The color to use as the base color of the background. If {@code null},
* {@link #getPrimaryColor()} will be used.
*/
public void setBackgroundBaseColor(@Nullable ColorStateList color) {
mBackgroundBaseColor = color;
updateBackground();
}
/**
* @return The base color of the background. {@code null} indicates the background will be drawn
* with {@link #getPrimaryColor()}.
*/
@Nullable
public ColorStateList getBackgroundBaseColor() {
return mBackgroundBaseColor;
}
/**
* Sets whether the background should be {@link GlifPatternDrawable}. If {@code false}, the
* background will be a solid color.
*/
public void setBackgroundPatterned(boolean patterned) {
mBackgroundPatterned = patterned;
updateBackground();
}
/**
* @return True if this view uses {@link GlifPatternDrawable} as background.
*/
public boolean isBackgroundPatterned() {
return mBackgroundPatterned;
}
private void updateBackground() {
final View patternBg = findManagedViewById(R.id.suw_pattern_bg);
if (patternBg != null) {
int backgroundColor = 0;
if (mBackgroundBaseColor != null) {
backgroundColor = mBackgroundBaseColor.getDefaultColor();
} else if (mPrimaryColor != null) {
backgroundColor = mPrimaryColor.getDefaultColor();
}
Drawable background = mBackgroundPatterned
? new GlifPatternDrawable(backgroundColor)
: new ColorDrawable(backgroundColor);
if (patternBg instanceof StatusBarBackgroundLayout) {
((StatusBarBackgroundLayout) patternBg).setStatusBarBackground(background);
} else {
patternBg.setBackgroundDrawable(background);
}
}
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
public boolean isProgressBarShown() {
return getMixin(ProgressBarMixin.class).isShown();
}
public void setProgressBarShown(boolean shown) {
getMixin(ProgressBarMixin.class).setShown(shown);
}
public ProgressBar peekProgressBar() {
return getMixin(ProgressBarMixin.class).peekProgressBar();
}
}