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
300 lines
10 KiB
Java
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
|
|
* <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">
|
|
*
|
|
* <!-- Content here -->
|
|
*
|
|
* </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();
|
|
}
|
|
}
|